Bridge from Pod

This guide walks through bridging ERC20 tokens from Pod to Ethereum. For background on how the bridge works, see Native Bridgearrow-up-right.

Decimal Scaling

All tokens on Pod are represented with 18 decimals, regardless of their decimals on Ethereum. When calling withdraw on the Pod bridge precompile, the amount must be specified in the Ethereum token's units. For example, to bridge 1 USDC (6 decimals on Ethereum), pass 1000000 (1e6), not 1000000000000000000 (1e18).

circle-exclamation

Steps

  1. Call withdraw(token, amount, ethRecipient, chainId) on the Pod bridge precompile. The chainId is the chain ID of the target chain (e.g. 1 for Ethereum mainnet) — it prevents the withdrawal proof from being replayed on other chains.

  2. Call pod_getBridgeClaimProof(txHash) on the full node to get the claim proof.

  3. Call claim(token, amount, ethRecipient, proof, auxTxSuffix) on the Ethereum bridge contract.

Examples for bridging 100 tokens (e.g. USDC) from Pod to Ethereum (assuming 6 decimals on Ethereum):

import { ethers } from "ethers";

const podProvider = new ethers.JsonRpcProvider("https://rpc.v1.dev.pod.network");
const ethProvider = new ethers.JsonRpcProvider("https://eth.llamarpc.com");
const podWallet = new ethers.Wallet(PRIVATE_KEY, podProvider);
const ethWallet = new ethers.Wallet(PRIVATE_KEY, ethProvider);

const POD_BRIDGE = "0x0000000000000000000000000000000000B41D9E";
const ETH_BRIDGE = "ETHEREUM_BRIDGE_ADDRESS";
const POD_TOKEN = "POD_TOKEN_ADDRESS"; // use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token
const ETH_TOKEN = "ETH_TOKEN_ADDRESS";
const amount = ethers.parseUnits("100", 6); // amount in Ethereum token units (e.g. 6 decimals for USDC)
const ethRecipient = ethWallet.address;
const ETH_CHAIN_ID = 1; // Ethereum mainnet chain ID

// 1. Withdraw on Pod bridge precompile
// IMPORTANT: tx.value must be 0, even for native token withdrawals
const podBridge = new ethers.Contract(
  POD_BRIDGE,
  ["function withdraw(address token, uint256 amount, address to, uint256 chainId) returns (bytes32)"],
  podWallet
);
const withdrawTx = await podBridge.withdraw(POD_TOKEN, amount, ethRecipient, ETH_CHAIN_ID, { value: 0 });
const receipt = await withdrawTx.wait();

// 2. Get claim proof
const claimProof = await podProvider.send("pod_getBridgeClaimProof", [receipt.hash]);

// 3. Claim on Ethereum
const ethBridge = new ethers.Contract(
  ETH_BRIDGE,
  ["function claim(address token, uint256 amount, address to, bytes proof, bytes auxTxSuffix)"],
  ethWallet
);
const claimTx = await ethBridge.claim(
  ETH_TOKEN, amount, ethRecipient, claimProof.proof, claimProof.auxTxSuffix
);
await claimTx.wait();
circle-info

Anyone can submit the claim transaction on Ethereum - it does not need to come from the original depositor.

Last updated