> ## Documentation Index
> Fetch the complete documentation index at: https://docs.base.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Base-Solana Bridge

> Bridge tokens and messages between Base and Solana Mainnet

export const GithubRepoCard = ({title, githubUrl}) => {
  return <a href={githubUrl} target="_blank" rel="noopener noreferrer" className="mb-4 flex items-center rounded-lg bg-zinc-900 p-4 text-white transition-all hover:bg-zinc-800">
      <div className="flex w-full items-center gap-3">
        <svg height="24" width="24" className="flex-shrink-0 dark:fill-white" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
          <path fill="currentColor" fillRule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
        </svg>

        <div className="flex min-w-0 flex-grow flex-col">
          <span className="truncate text-base font-medium">{title}</span>
          <span className="truncate text-xs text-zinc-400">{githubUrl}</span>
        </div>

        <svg className="h-5 w-5 flex-shrink-0 text-zinc-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
        </svg>
      </div>
    </a>;
};

The Base-Solana bridge enables bidirectional token transfers and message passing between Base and
Solana networks. This bridge allows you to:

* **Transfer tokens** between Base and Solana
* **Send arbitrary cross-chain messages**
* **Combine both flows (transfer with arbitrary calls)**
* **Deploy wrapped tokens** on either chain

This guide covers the bridge architecture, the production addresses, and practical implementation
patterns.

## How it works

### On Base

The Base bridge contract locks or burns tokens when sending tokens to Solana, and mints or unlocks
tokens when receiving tokens from Solana. The Bridge contract itself builds Merkle trees from
outgoing messages. Validators verify the Merkle root every \~300 finalized blocks and relay it to
Solana. You then prove your message exists in the tree to complete the transfer on Solana.

<Info>
  Tokens that are native to Base are locked and tokens that are native to Solana are burned when bridging to Solana.
  Tokens that are native to Solana are minted and tokens that are native to Base are unlocked when bridging to Base.
</Info>

**Key Smart contracts:**

* [**Bridge Contract**](https://github.com/base/bridge/blob/main/base/src/Bridge.sol): Handles outgoing transfers
* [**CrossChainERC20**](https://github.com/base/bridge/blob/main/base/src/CrossChainERC20.sol): Mintable/burnable tokens for cross-chain transfers
* [**BridgeValidator**](https://github.com/base/bridge/blob/main/base/src/BridgeValidator.sol): Validates messages with oracle signatures
* [**Twin Contract**](https://github.com/base/bridge/blob/main/base/src/Twin.sol): Your personal smart contract on Base for executing calls from Solana

<Tip>
  **What is the Twin Contract?**\
  Each Solana wallet deterministically maps to a Twin contract on Base. When you attach a contract call
  to a bridge message, the call is executed from this Twin contract, ie. the Twin becomes `msg.sender` on Base.
</Tip>

### On Solana

The Solana bridge program handles token transfers by locking or burning tokens and emitting events.
For messaging, validators relay these events to Base where they are executed through your Twin
contract.

**Key Programs (Solana Mainnet-Beta):**

* [**Bridge Program**](https://github.com/base/bridge/blob/main/solana/programs/bridge): Handles outgoing transfers and message commitments.
* [**Base Relayer Program**](https://github.com/base/bridge/blob/main/solana/programs/base_relayer): Optional relayer that can prepay gas on Base.

<Info>
  The relayer program is not part of the core bridge. It is an optional convenience layer that can pay
  Base gas fees on behalf of the Solana user in the Solana → Base direction.

  The user would still need to pay the gas fee by adding `PayForRelay` to the Solana transaction.
  If the user does not add `PayForRelay`, the relayer program will not pay the gas fee.
</Info>

You can access the full repository here:

<GithubRepoCard title="Base Bridge - Official Repository" githubUrl="https://github.com/base/bridge" />

## Bridging Flows

<CardGroup cols={3}>
  <Card title="Solana → Base" icon="arrow-right" href="#solana-to-base">
    Push-based with optional relayer for instant execution on Base
  </Card>

  <Card title="Base → Solana" icon="arrow-left" href="#base-to-solana">
    Proof-based burn and unlock with full custody
  </Card>

  <Card title="Terminally Onchain" icon="command-line" href="#terminally-onchain-example">
    Production terminal UI for bridging + contract calls
  </Card>
</CardGroup>

## Solana to Base

**Flow:** Lock SOL/SPL → (Optional) Pay for relay → Validators approve → Mint + execute on Base

The Solana to Base bridge uses a pull-based model that requires 3 steps:

1. **Initiate the bridge on Solana** - Lock your SOL or native SPL token in a Solana vault
2. **Wait for validators to pre-approve the message** - Validators verify and approve your bridge message
3. **Execute the message on Base** - The approved message is executed on Base to mint SOL and execute any additional arbitrary calls

<Info>
  When bridging from Solana to Base, native SOL/SPL are locked and ERC20 SOL is minted on Base.
</Info>

<Warning>
  If your Solana → Base message includes a call to execute, you must ensure
  the ABI-encoded call is **executable on Base**. A call that cannot be executed
  on Base **cannot be undone**. If you bridge tokens in the same transaction,
  those tokens will be **locked**.
</Warning>

Reference scripts (auto-relay, token wrapping, CLI utilities) live in the `scripts/` directory of the official repository:

<GithubRepoCard title="Solana → Base CLI Scripts" githubUrl="https://github.com/base/bridge/tree/main/scripts/src/commands/sol/bridge" />

### Auto-Relay Example

This is a sample script that shows how to bridge SOL with auto-relay

```typescript solToBaseWithAutoRelay/index.ts expandable theme={null}
// Configure
const TO = "0x8c1a617bdb47342f9c17ac8750e0b070c372c721"; // Base address
const AMOUNT = 0.001; // SOL amount

// Bridge SOL with auto-relay
const ixs = [
  getBridgeSolInstruction({
    payer,
    from: payer,
    solVault: solVaultAddress,
    bridge: bridgeAccountAddress,
    outgoingMessage,
    to: toBytes(TO),
    remoteToken: toBytes("0xC5b9112382f3c87AFE8e1A28fa52452aF81085AD"), // SOL on Base
    amount: BigInt(AMOUNT * 10**9),
  }),
  await buildPayForRelayIx(RELAYER_PROGRAM_ID, outgoingMessage, payer)
];

await buildAndSendTransaction(SOLANA_RPC_URL, ixs, payer);
```

For more details, see the [Solana to Base Relay Script](https://github.com/base/bridge/blob/main/scripts/src/commands/sol/bridge/solana-to-base/bridge-sol.handler.ts).

### Wrap Custom SPL Tokens

The example above shows how to bridge native SOL to Base.
To bridge custom SPL tokens,
you need to create wrapped ERC20 representations on Base using the CrossChainERC20Factory.

<GithubRepoCard title="Token Wrapping Example" githubUrl="https://github.com/base/bridge/blob/main/scripts/src/commands/sol/bridge/solana-to-base/wrap-token.handler.ts" />

```typescript wrapSolTokenOnBase/index.ts expandable theme={null}
// Deploy wrapped token on Base
const mintBytes32 = getBase58Codec().encode(SOLANA_SPL_MINT_ADDRESS).toHex();

await client.writeContract({
  address: "0x58207331CBF8Af87BB6453b610E6579D9878e4EA", // Factory
  abi: TokenFactory,
  functionName: "deploy",
  args: [`0x${mintBytes32}`, "Token Name", "SYMBOL", 9],
});
```

## Base to Solana

**Flow:** Burn ERC20 SOL on Base → Wait for finalization → Generate Merkle proof → Execute on Solana

Burn wrapped tokens on Base, wait for the message to become provable, then execute the proof on
Solana to unlock the native asset. This path offers full custody and requires a prover.

<GithubRepoCard title="Base → Solana Example" githubUrl="https://github.com/base/bridge/blob/main/scripts/src/internal/sol/base.ts" />

```typescript bridgeSolFromBaseToSolana/index.ts expandable theme={null}
// Step 1: Burn SOL on Base
const transfer = {
  localToken: "0xC5b9112382f3c87AFE8e1A28fa52452aF81085AD", // SOL (on Base)
  remoteToken: pubkeyToBytes32(SOL_ADDRESS),
  to: pubkeyToBytes32(solanaAddress),
  remoteAmount: BigInt(AMOUNT * 10**9),
};

const txHash = await client.writeContract({
  address: "0xB2068ECCDb908902C76E3f965c1712a9cF64171E", // Bridge
  abi: Bridge,
  functionName: "bridgeToken",
  args: [transfer, []],
});

// Step 2: Wait for finalization
const isProvable = await isBridgeMessageProvable(txHash);

// Step 3: Generate proof
const { event, rawProof } = await generateProof(txHash, baseBlockNumber);

// Step 4: Execute on Solana
const proveIx = getProveMessageInstruction({
  nonce: event.message.nonce,
  sender: toBytes(event.message.sender),
  data: toBytes(event.message.data),
  proof: rawProof.map(e => toBytes(e)),
  messageHash: toBytes(event.messageHash),
});

const relayIx = getRelayMessageInstruction({ message: messagePda });
await buildAndSendTransaction(SOLANA_RPC_URL, [proveIx, relayIx], payer);
```

<Warning>
  If you operate a relayer that signs and submits Solana transactions for users in the **Base → Solana**
  direction, do **not** sign transactions that require your relayer pubkey as a signer.

  A malicious user can encode a transaction that includes your relayer pubkey as a required signer; if
  you sign and submit it, you may unintentionally authorize arbitrary instructions (including ones
  that can steal relayer funds). As a baseline mitigation, ignore any transaction that specifies your
  pubkey as a signer.
</Warning>

## Utilities

The repository includes utilities for converting between Solana and Base address formats,
getting your Solana CLI keypair for signing transactions,
and building and sending Solana transactions.

<GithubRepoCard title="Base Bridge Examples - Utilities" githubUrl="https://github.com/base/bridge/tree/main/scripts/src/commands" />

### Address Conversion

Convert Solana pubkey to bytes32 for Base contracts:

```typescript example.ts theme={null}
// Convert Solana pubkey to bytes32 for Base contracts
import { pubkeyToBytes32 } from "./utils/pubkeyToBytes32";

const bytes32Address = pubkeyToBytes32(solanaAddress);
```

### Keypair Management

Get your Solana CLI keypair for signing transactions:

```typescript example.ts theme={null}
import { getSolanaCliConfigKeypairSigner } from "./utils/keypair";

const payer = await getSolanaCliConfigKeypairSigner();
```

### Transaction Building

Build and send Solana transactions:

```typescript example.ts theme={null}
import { buildAndSendTransaction } from "./utils/buildAndSendTransaction";

const signature = await buildAndSendTransaction(SOLANA_RPC_URL, ixs, payer);
```

## Terminally Onchain Example

<GithubRepoCard title="Terminally Onchain" githubUrl="https://github.com/base/sol2base" />

[Terminally Onchain](https://terminallyonchain.com/) is a production Next.js app that exposes the bridge via a
command terminal UI. Users connect a Solana wallet, type commands such as to bridge and call a contract on Base:

```bash theme={null}
bridge 0.0001 sol 0xYourTwin --call-contract 0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82 \
  --call-selector "transfer(address,uint256)" \
  --call-args 0x0000000000000000000000000000000000000000 100000000000000
```

The workflow:

1. **Parse command:** The terminal parser resolves the asset, destination, and optional Base call (selector + args + value).
2. **Stage bridge:** `queueBridge` validates SPL overrides, ABI-encodes the Base call via `encodeFunctionData`, and stages relay overrides.
3. **Execute:** `solanaBridge.bridge()` resolves the destination (ENS/Basename), ensures balances, and calls `realBridgeImplementation` to sign and send the Solana transaction.
4. **Relay + Call:** If relay gas is prepaid, the Base Relayer executes the attached call from the user’s Twin contract immediately after ERC20 SOL is minted.

Key implementation references:

* `src/lib/bridge.ts`: Asset resolution (supports mint addresses), environment-aware RPC connections, and call attachment support.
* `src/lib/realBridgeImplementation.ts`: Builds Solana transactions with `PayForRelay` + `bridge_sol`/`bridge_spl` instructions, using per-environment PDAs and gas-fee receivers.
* `src/components/MainContent.tsx`: Terminal UI with command staging, log viewer, and ABI encoding for arbitrary Base calls.
* `src/components/WalletConnection.tsx`: Fetches the deterministic Twin address on Base Mainnet/Sepolia for the connected Solana wallet.

### Running the Terminal

```bash Terminal theme={null}
git clone https://github.com/base/sol2base.git
cd sol2base
npm install --legacy-peer-deps

# Configure env (RPC URLs, relayer addresses, CDP API keys, etc.)
cp env.template .env.local

npm run dev   # defaults to http://localhost:3000
```

<Tip>
  The terminal exposes both Base Sepolia ↔ Solana Devnet and Base Mainnet ↔ Solana Mainnet. Use the
  network dropdown in the UI to switch.

  Set `CDP_API_KEY` in your `.env` file to get access to the faucet.
</Tip>

## Contract Addresses

### Base Mainnet

```json theme={null}
{
  "Bridge": "0x3eff766C76a1be2Ce1aCF2B69c78bCae257D5188",
  "BridgeValidator": "0xAF24c1c24Ff3BF1e6D882518120fC25442d6794B",
  "CrossChainERC20Factory": "0xDD56781d0509650f8C2981231B6C917f2d5d7dF2",
  "SOL": "0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82"
}
```

### Solana Mainnet

```json theme={null}
{
  "BridgeProgram": "HNCne2FkVaNghhjKXapxJzPaBvAKDG1Ge3gqhZyfVWLM",
  "BaseRelayerProgram": "g1et5VenhfJHJwsdJsDbxWZuotD5H4iELNG61kS4fb9"
}
```

### Base Sepolia

```json theme={null}
{
  "Bridge": "0x01824a90d32A69022DdAEcC6C5C14Ed08dB4EB9B",
  "BridgeValidator": "0xa80C07DF38fB1A5b3E6a4f4FAAB71E7a056a4EC7",
  "CrossChainERC20Factory": "0x488EB7F7cb2568e31595D48cb26F63963Cc7565D",
  "SOL": "0xCace0c896714DaF7098FFD8CC54aFCFe0338b4BC",
  "FLYWHEEL_ADDRESS": "0x00000F14AD09382841DB481403D1775ADeE1179F",
  "BRIDGE_CAMPAIGN_ADDRESS": "0xE2AD1C34382410C30d826B019A0B3700F5c4e6c9"
}
```

### Solana Devnet

```json theme={null}
{
  "BridgeProgram": "7c6mteAcTXaQ1MFBCrnuzoZVTTAEfZwa6wgy4bqX3KXC",
  "BaseRelayerProgram": "56MBBEYAtQAdjT4e1NzHD8XaoyRSTvfgbSVVcEcHj51H",
  "GasFeeReceiver": "AFs1LCbodhvwpgX3u3URLsud6R1XMSaMiQ5LtXw4GKYT"
}
```

## Resources

<CardGroup cols={2}>
  <Card title="Base Bridge Repository" icon="github" href="https://github.com/base/bridge">
    Source code, contracts, programs, and scripts
  </Card>

  <Card title="Solana Explorer" icon="magnifying-glass" href="https://explorer.solana.com/">
    Monitor Solana mainnet-beta transactions
  </Card>

  <Card title="Base Explorer" icon="magnifying-glass" href="https://basescan.org/">
    Monitor Base Mainnet transactions
  </Card>

  <Card title="Discord Support" icon="discord" href="https://base.org/discord">
    Get help from the Base community
  </Card>
</CardGroup>
