Skip to content

Commit 2b882af

Browse files
authored
Update Solana Base Bridge Page (#702)
* update wsol * update list of features * add code examples
1 parent ba61447 commit 2b882af

1 file changed

Lines changed: 130 additions & 38 deletions

File tree

docs/base-chain/quickstart/base-solana-bridge.mdx

Lines changed: 130 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ The Base-Solana bridge enables bidirectional token transfers and message passing
99
Solana networks. This bridge allows you to:
1010

1111
* **Transfer tokens** between Base and Solana
12-
* **Send arbitrary cross-chain messages** (optionally combined with a transfer of tokens)
12+
* **Send arbitrary cross-chain messages**
13+
* **Combine both flows (transfer with arbitrary calls)**
1314
* **Deploy wrapped tokens** on either chain
1415

1516
This guide covers the bridge architecture, the production addresses, and practical implementation
@@ -88,21 +89,144 @@ The Solana to Base bridge uses a pull-based model that requires 3 steps:
8889
2. **Wait for validators to pre-approve the message** - Validators verify and approve your bridge message
8990
3. **Execute the message on Base** - The approved message is executed on Base to mint SOL and execute any additional arbitrary calls
9091
<Info>
91-
When bridging from Solana to Base, native SOL/SPL are locked and wrapped WSOL/ERC20 is minted on Base.
92+
When bridging from Solana to Base, native SOL/SPL are locked and ERC20 SOL is minted on Base.
9293
</Info>
9394

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

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

99+
### Auto-Relay Example
100+
This is a sample script that shows how to bridge SOL with auto-relay
101+
102+
```typescript solToBaseWithAutoRelay/index.ts expandable
103+
// Configure
104+
const TO = "0x8c1a617bdb47342f9c17ac8750e0b070c372c721"; // Base address
105+
const AMOUNT = 0.001; // SOL amount
106+
107+
// Bridge SOL with auto-relay
108+
const ixs = [
109+
getBridgeSolInstruction({
110+
payer,
111+
from: payer,
112+
solVault: solVaultAddress,
113+
bridge: bridgeAccountAddress,
114+
outgoingMessage,
115+
to: toBytes(TO),
116+
remoteToken: toBytes("0xC5b9112382f3c87AFE8e1A28fa52452aF81085AD"), // SOL on Base
117+
amount: BigInt(AMOUNT * 10**9),
118+
}),
119+
await buildPayForRelayIx(RELAYER_PROGRAM_ID, outgoingMessage, payer)
120+
];
121+
122+
await buildAndSendTransaction(SOLANA_RPC_URL, ixs, payer);
123+
```
124+
125+
For more details, see the [Solana to Base Relay Script](https://github.com/base/bridge/blob/main/scripts/src/commands/sol/onchain/bridge/solana-to-base/bridge-sol.handler.ts).
126+
127+
### Wrap Custom SPL Tokens
128+
129+
The example above shows how to bridge native SOL to Base.
130+
To bridge custom SPL tokens,
131+
you need to create wrapped ERC20 representations on Base using the CrossChainERC20Factory.
132+
133+
<GithubRepoCard title="Token Wrapping Example" githubUrl="https://github.com/base/bridge/blob/main/scripts/src/commands/sol/onchain/bridge/solana-to-base/wrap-token.handler.ts" />
134+
135+
```typescript wrapSolTokenOnBase/index.ts expandable
136+
// Deploy wrapped token on Base
137+
const mintBytes32 = getBase58Codec().encode(SOLANA_SPL_MINT_ADDRESS).toHex();
138+
139+
await client.writeContract({
140+
address: "0x58207331CBF8Af87BB6453b610E6579D9878e4EA", // Factory
141+
abi: TokenFactory,
142+
functionName: "deploy",
143+
args: [`0x${mintBytes32}`, "Token Name", "SYMBOL", 9],
144+
});
145+
```
146+
98147
## Base to Solana
99148

100-
**Flow:** Burn WSOL/ERC20 on Base → Wait for finalization → Generate Merkle proof → Execute on Solana
149+
**Flow:** Burn ERC20 SOL on Base → Wait for finalization → Generate Merkle proof → Execute on Solana
101150

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

105154
<GithubRepoCard title="Base → Solana Example" githubUrl="https://github.com/base/bridge/blob/main/scripts/src/internal/sol/base.ts" />
155+
156+
```typescript bridgeSolFromBaseToSolana/index.ts expandable
157+
// Step 1: Burn SOL on Base
158+
const transfer = {
159+
localToken: "0xC5b9112382f3c87AFE8e1A28fa52452aF81085AD", // SOL (on Base)
160+
remoteToken: pubkeyToBytes32(SOL_ADDRESS),
161+
to: pubkeyToBytes32(solanaAddress),
162+
remoteAmount: BigInt(AMOUNT * 10**9),
163+
};
164+
165+
const txHash = await client.writeContract({
166+
address: "0xB2068ECCDb908902C76E3f965c1712a9cF64171E", // Bridge
167+
abi: Bridge,
168+
functionName: "bridgeToken",
169+
args: [transfer, []],
170+
});
171+
172+
// Step 2: Wait for finalization
173+
const isProvable = await isBridgeMessageProvable(txHash);
174+
175+
// Step 3: Generate proof
176+
const { event, rawProof } = await generateProof(txHash, baseBlockNumber);
177+
178+
// Step 4: Execute on Solana
179+
const proveIx = getProveMessageInstruction({
180+
nonce: event.message.nonce,
181+
sender: toBytes(event.message.sender),
182+
data: toBytes(event.message.data),
183+
proof: rawProof.map(e => toBytes(e)),
184+
messageHash: toBytes(event.messageHash),
185+
});
186+
187+
const relayIx = getRelayMessageInstruction({ message: messagePda });
188+
await buildAndSendTransaction(SOLANA_RPC_URL, [proveIx, relayIx], payer);
189+
```
190+
191+
## Utilities
192+
193+
The repository includes utilities for converting between Solana and Base address formats,
194+
getting your Solana CLI keypair for signing transactions,
195+
and building and sending Solana transactions.
196+
197+
<GithubRepoCard title="Base Bridge Examples - Utilities" githubUrl="https://github.com/base/bridge/tree/main/scripts/src/commands" />
198+
199+
### Address Conversion
200+
201+
Convert Solana pubkey to bytes32 for Base contracts:
202+
```typescript example.ts
203+
// Convert Solana pubkey to bytes32 for Base contracts
204+
import { pubkeyToBytes32 } from "./utils/pubkeyToBytes32";
205+
206+
const bytes32Address = pubkeyToBytes32(solanaAddress);
207+
```
208+
209+
### Keypair Management
210+
211+
Get your Solana CLI keypair for signing transactions:
212+
213+
```typescript example.ts
214+
import { getSolanaCliConfigKeypairSigner } from "./utils/keypair";
215+
216+
const payer = await getSolanaCliConfigKeypairSigner();
217+
```
218+
219+
### Transaction Building
220+
221+
Build and send Solana transactions:
222+
223+
```typescript example.ts
224+
import { buildAndSendTransaction } from "./utils/buildAndSendTransaction";
225+
226+
const signature = await buildAndSendTransaction(SOLANA_RPC_URL, ixs, payer);
227+
```
228+
229+
106230
## Terminally Onchain Example
107231

108232
<GithubRepoCard title="Terminally Onchain" githubUrl="https://github.com/base/sol2base" />
@@ -121,7 +245,7 @@ The workflow:
121245
1. **Parse command:** The terminal parser resolves the asset, destination, and optional Base call (selector + args + value).
122246
2. **Stage bridge:** `queueBridge` validates SPL overrides, ABI-encodes the Base call via `encodeFunctionData`, and stages relay overrides.
123247
3. **Execute:** `solanaBridge.bridge()` resolves the destination (ENS/Basename), ensures balances, and calls `realBridgeImplementation` to sign and send the Solana transaction.
124-
4. **Relay + Call:** If relay gas is prepaid, the Base Relayer executes the attached call from the user’s Twin contract immediately after WSOL is minted.
248+
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.
125249

126250
Key implementation references:
127251

@@ -159,7 +283,7 @@ Set `CDP_API_KEY` in your `.env` file to get access to the faucet.
159283
"Bridge": "0x3eff766C76a1be2Ce1aCF2B69c78bCae257D5188",
160284
"BridgeValidator": "0xAF24c1c24Ff3BF1e6D882518120fC25442d6794B",
161285
"CrossChainERC20Factory": "0xDD56781d0509650f8C2981231B6C917f2d5d7dF2",
162-
"WrappedSOL": "0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82"
286+
"SOL": "0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82"
163287
}
164288
```
165289

@@ -179,7 +303,7 @@ Set `CDP_API_KEY` in your `.env` file to get access to the faucet.
179303
"Bridge": "0x01824a90d32A69022DdAEcC6C5C14Ed08dB4EB9B",
180304
"BridgeValidator": "0xa80C07DF38fB1A5b3E6a4f4FAAB71E7a056a4EC7",
181305
"CrossChainERC20Factory": "0x488EB7F7cb2568e31595D48cb26F63963Cc7565D",
182-
"WrappedSOL": "0xCace0c896714DaF7098FFD8CC54aFCFe0338b4BC"
306+
"SOL": "0xCace0c896714DaF7098FFD8CC54aFCFe0338b4BC"
183307
}
184308
```
185309

@@ -192,38 +316,6 @@ Set `CDP_API_KEY` in your `.env` file to get access to the faucet.
192316
}
193317
```
194318

195-
## Troubleshooting
196-
197-
<AccordionGroup>
198-
<Accordion title="Incorrect gas fee receiver">
199-
A mismatch triggers `Error Code: 12300`. Instead of hardcoding the receiver address, query it directly from the [bridge config](https://github.com/base/bridge/blob/main/solana/programs/bridge/src/common/state/bridge.rs#L170). See the [bridge script](https://github.com/base/bridge/blob/main/scripts/src/commands/sol/bridge/solana-to-base/bridge-sol.handler.ts#L92) for an example.
200-
</Accordion>
201-
<Accordion title="RPC 403 on mainnet">
202-
Public Solana RPC endpoints throttle cross-origin requests. Set
203-
`NEXT_PUBLIC_SOLANA_MAINNET_RPC` (or the equivalent in your client) to a dedicated provider such
204-
as Helius, Triton, or QuickNode.
205-
</Accordion>
206-
<Accordion title="Message not appearing on Solana">
207-
* Wait ~15 minutes for Base finality and relay.
208-
* Confirm the Base tx emitted `MessageRegistered`.
209-
* Verify you are using consistent network pairs (Mainnet/Mainnet or Sepolia/Devnet).
210-
</Accordion>
211-
<Accordion title="Proof verification failed">
212-
* Use the latest provable block number.
213-
* Confirm the message hash and Merkle proof correspond to the same transaction.
214-
* Ensure all PDAs / account seeds are derived with the correct program IDs per environment.
215-
</Accordion>
216-
</AccordionGroup>
217-
218-
## Security
219-
220-
<Warning>
221-
* Never mix testnet and mainnet addresses or RPC endpoints.
222-
* Validate all destination addresses before bridging.
223-
* Monitor both Base and Solana explorers for your transactions.
224-
* Keep private keys and API keys secure; never expose them in client bundles.
225-
</Warning>
226-
227319
## Resources
228320

229321
<CardGroup cols={2}>

0 commit comments

Comments
 (0)