Bridge()
For chains that support StarGate bridge
function bridge(uint256 amount) external payable override nonReentrant returns (uint256) {This function allows anyone to trigger a bridge transaction where the consolidated fees (typically in the finalTargetToken format) will be sent to the Ethereum blockchain.
Function Arguments
amount
uint256
This value represents the amount of tokens to bridge over from the contract on the selected chain to Ethereum
bridge
uint256
This value represents the bridge fee in native gas token units
This function requires 2 values to successfully work:
Amount
This value represents the amount of
finalTargetTokenyou would like to bridge over. When passing the value 0, it will try to bridge the entire available amount. How to identify the available amount?Visit the CarbonVortex contract (follow the address in the relevant chain)
ReadfinalTargetTokento find the address of the token to bridge over (if the address is null, checktargetTokenaddress instead)Check the contract balance for the token address
Bridge
This value represents the bridge fee which is required in order to pay for the 2nd transaction to claim the bridged amount on the ethereum blockchain. How to identify the required bridge fee? Different chains have different bridge implementation. Follow this step closely to find the correct value to use
Overview
The prove/finalize script lives in the bancorprotocol/carbon-vortex-bridge repo. Clone it and install dependencies:
Completing a Celo → Ethereum Vortex Bridge Withdrawal
Operator guide for the canonical OP-stack Celo Vortex bridge (VortexOpStackBridge).
Overview
Celo is an OP-stack L2, and the Vortex bridges WETH to Ethereum over the canonical Standard Bridge. A canonical L2→L1 withdrawal has three on-chain steps and an unavoidable ~7-day delay:
(L2: Celo) (L1: Ethereum) (L1: Ethereum)
1. bridge() ──► 2. prove ── wait ~7 days ──► 3. finalize
burns WETH, submits a Merkle proof of the releases WETH to
queues message withdrawal to OptimismPortal2 the vaultStep 1 is a single contract write on Celo (a Celoscan "Write").
Steps 2 & 3 happen on Ethereum L1 and are driven by a script in the repo,
scripts/withdraw.mjs (pnpm withdraw <tx>) — the proof construction is far
too complex to do by hand in a block explorer.
The bridge is permissionless to prove/finalize: any funded EOA can run steps 2 and 3, and the WETH still lands in the vault regardless of who submits them.
Setup
The prove/finalize script lives in the bancorprotocol/carbon-vortex-bridge repo. Clone it and install dependencies:
git clone https://github.com/bancorprotocol/carbon-vortex-bridge
cd carbon-vortex-bridge
pnpm installRequires Node ≥ 18 and pnpm. Nothing else — scripts/withdraw.mjs is a self-contained viem script (no Hardhat/Foundry needed for the withdrawal flow).
Prerequisites
A signing key for the L1 transactions, passed explicitly as PRIVATE_KEY on the command line
(see the commands below).
That EOA needs ETH on Ethereum mainnet for gas (prove ≈ 350k gas; finalize is similar or smaller).
For Step 1, just CELO for gas on Celo.
Step 1 – Initiate the bridge on Celo
Open the VortexOpStackBridge proxy on Celoscan → Contract → Write as Proxy:
Connect your wallet.
Find the bridge function. It takes one argument, amount:
payableAmount (CELO) – leave 0 (this bridge does not take a native fee; sending any value reverts).
amount – 0 bridges the entire WETH balance held by the Vortex; or pass a specific amount (wei).
Click Write and sign. This burns the L2 WETH and queues the canonical withdrawal message.
6. Copy the transaction hash – you need it for steps 2 and 3.
The L2 token being withdrawn is the bridged WETH 0xD221812de1BD094f35587EE8E174B07B6167D9Af; on L1 it is released as canonical WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 to the vault.
Step 2 – Prove the withdrawal on Ethereum
The withdrawal can only be proven once a dispute game covering its L2 block has been posted to L1 by Celo's proposer (OP-Succinct validity proofs). This usually takes tens of minutes to a few hours.
From the repo root, check status any time (read-only, no key):
When it reads ready-to-prove, run the same command with your key to send the prove tx:
The script is status-aware — with a key set, the same command takes the correct next action at each stage; without a key it only reports status:
waiting-to-prove
No game covers the L2 block yet. Re-run later.
ready-to-prove
Builds the proof and send the prove tx, then waits for the receipt.
waiting-to-finalize
Proven – prints the remaining time in the last 7-day window.
ready-to-finalize
Sends the finalize tx (see Step 4).
finalized
Done – WETH is in the vault.
On ready-to-prove it submits proveWithdrawalTransaction on the L1 portal and reports:
The 7-day proof-maturity timer starts at the moment the prove tx confirms.
Step 3 — Wait ~7 days
Re-running the read-only command during this period prints the countdown:
Nothing to do but wait — you don't need to keep a process running, just re-run later.
Step 4 — Finalize on Ethereum
After the window opens, run the command with your key again:
It detects ready-to-finalize, submits finalizeWithdrawalTransaction, and the WETH is released to the vault 0x60917e542aDdd13bfd1a7f81cD654758052dAdC4:
That completes the bridge.
Script Configuration
scripts/withdraw.mjs reads these from the environment (pass them on the command line; nothing is loaded from .env):
PRIVATE_KEY
Signer key for the L1 prove/finalize tx (0x-prefixed). Omit to run read-only.
—
Passing no PRIVATE_KEY runs read-only — it just prints the current status without sending anything.
Reference addresses
VortexOpStackBridge (proxy)
Celo
0x753425e27aE996f0DB75C759C6E5EBa5c74D6aAF
Vortex
Celo
0xD9D89e8A0dfE549e5B424D5b511cB3b84A764857
WETH (withdraw token, L2)
Celo
0xD221812de1BD094f35587EE8E174B07B6167D9Af
L2 Standard Bridge (predeploy)
Celo
0x4200000000000000000000000000000000000010
L2ToL1MessagePasser (predeploy)
Celo
0x4200000000000000000000000000000000000016
OptimismPortal2
L1
0xc5c5D157928BDBD2ACf6d0777626b6C75a9EAEDC
DisputeGameFactory
L1
0xFbAC162162f4009Bb007C6DeBC36B1dAC10aF683
L1 Standard Bridge
L1
0x9C4955b92F34148dbcfDCD82e9c9eCe5CF2badfe
WETH (released to vault, L1)
L1
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Vault (final recipient)
L1
0x60917e542aDdd13bfd1a7f81cD654758052dAdC4
Troubleshooting
eth_getProof → "Missing or invalid parameters" – forno does not serve eth_getProof. Use an
archive endpoint (the default celo.drpc.org, or rpc.ankr.com/celo). This is why the prove step uses
CELO_ARCHIVE_RPC separately from CELO_RPC.
"Dispute game not found" / stuck on waiting-to-prove – the proposer hasn't posted a game covering
your L2 block yet. Wait and re-run; this is normal for the first tens of minutes to a couple of hours.
Prove/finalize tx fails or never sends – confirm the signing EOA has mainnet ETH for gas, and
that you passed PRIVATE_KEY (without it the script is read-only by design).
Want to check status without spending gas – run the command with no PRIVATE_KEY; it stays
read-only and just prints the current status.
Doing it manually (raw contract calls)
To drive the flow yourself without the script — every L1/L2 function call, on which contract, and how to source each parameter — see the contract-level reference: celo-bridge-withdrawal-technical.md.
On Coti
View the wETH token page on readProxy on cotiscan
Find the read function called
quoteGasPayment
Input
1to indicate Ethereum as the destination chainClick
Readto discover the required gas cost
Once you have this information available, paste it on the Send native COTI field for the bridge function
On BNB Bridge is utilizing the "across" bridge infrastructure which knows how to calculate all required fees during execution.
bridge fee value should be set to zero (0)
Click "write" and initiate the briding process.
Thats it.
On Sei, Base, Tac, Fantom, Mantle, Linea, Blast, Telos and Iota: Bridge supports automatic "claim" and as such you are required to include the gas fee needed for the following transaction on the ethereum blockchain. In order for the transaction to go through successfully, you must identify the required gas fee by following this process:
Visit StarGate interface
Connect wallet
Attempt to bridge any amount of tokens (you want to see the transaction details on your wallet signed page DO NOT SIGN THE TRANSACTION)

In the wallet confirmation popup, find the value under "Param #2" as outlined in the image (you can "Cancel" the wallet popup after coping the required value)

Copy the indicated value and paste it into the
bridgefield of the transaction. Make sure you normalize the decimal correctly to the gas token of the chain. For example, on Base, the input value should be in "ETH" units i.e. 0.000666588492010473 and not as indicated in WEI.
Example
Last updated