# Wrap ETH to WETH9 and Bridge to Ethereum Mainnet This guide explains the complete process of wrapping ETH to WETH9 and bridging it to Ethereum Mainnet from ChainID 138. ## Overview The process involves three main steps: 1. **Wrap ETH to WETH9** - Convert native ETH to WETH9 tokens 2. **Approve Bridge** - Grant the bridge contract permission to spend your WETH9 3. **Bridge to Ethereum Mainnet** - Send WETH9 cross-chain via CCIP ## Prerequisites - Private key with sufficient ETH balance (amount + gas fees) - `cast` tool from Foundry (for command-line execution) - Access to ChainID 138 RPC endpoint - Basic understanding of blockchain transactions ## Contract Addresses ### ChainID 138 (Source Chain) - **WETH9 Contract**: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` - **WETH9 Bridge**: `0x89dd12025bfCD38A168455A44B400e913ED33BE2` - **RPC URL**: `http://192.168.11.250:8545` or `https://rpc-core.d-bis.org` ### Ethereum Mainnet (Destination) - **Chain Selector**: `5009297550715157269` - **Chain ID**: `1` ## Quick Start ### Using the Automated Script ```bash # Basic usage (with PRIVATE_KEY in .env) ./scripts/wrap-and-bridge-to-ethereum.sh 1.0 # With private key as argument ./scripts/wrap-and-bridge-to-ethereum.sh 1.0 0xYourPrivateKeyHere ``` The script will: 1. Check your ETH balance 2. Wrap ETH to WETH9 if needed 3. Approve the bridge contract 4. Calculate CCIP fees 5. Send the cross-chain transfer ## Manual Process (Step-by-Step) ### Step 1: Check Your Balance ```bash # Get your address from private key DEPLOYER=$(cast wallet address --private-key "0xYourPrivateKey") # Check ETH balance cast balance "$DEPLOYER" --rpc-url "http://192.168.11.250:8545" # Check WETH9 balance cast call "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" \ "balanceOf(address)" "$DEPLOYER" \ --rpc-url "http://192.168.11.250:8545" ``` ### Step 2: Wrap ETH to WETH9 WETH9 uses the standard `deposit()` function to wrap ETH: ```bash # Convert amount to wei (e.g., 1.0 ETH) AMOUNT_WEI=$(cast --to-wei 1.0 ether) # Wrap ETH by calling deposit() with value cast send "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" "deposit()" \ --value "$AMOUNT_WEI" \ --rpc-url "http://192.168.11.250:8545" \ --private-key "0xYourPrivateKey" \ --gas-price 5000000000 ``` **What happens:** - ETH is sent to the WETH9 contract - Equivalent WETH9 tokens are minted to your address - A `Deposit` event is emitted - A `Transfer` event is emitted (from address(0) to you) ### Step 3: Approve Bridge Contract Before bridging, you must approve the bridge to spend your WETH9: ```bash # Approve bridge (using max uint256 for unlimited approval) MAX_UINT256="115792089237316195423570985008687907853269984665640564039457584007913129639935" cast send "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" \ "approve(address,uint256)" \ "0x89dd12025bfCD38A168455A44B400e913ED33BE2" \ "$MAX_UINT256" \ --rpc-url "http://192.168.11.250:8545" \ --private-key "0xYourPrivateKey" \ --gas-price 5000000000 ``` **Check allowance:** ```bash cast call "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" \ "allowance(address,address)" \ "$DEPLOYER" \ "0x89dd12025bfCD38A168455A44B400e913ED33BE2" \ --rpc-url "http://192.168.11.250:8545" ``` ### Step 4: Calculate CCIP Fee Before bridging, check the required fee: ```bash ETHEREUM_SELECTOR="5009297550715157269" AMOUNT_WEI=$(cast --to-wei 1.0 ether) cast call "0x89dd12025bfCD38A168455A44B400e913ED33BE2" \ "calculateFee(uint64,uint256)" \ "$ETHEREUM_SELECTOR" \ "$AMOUNT_WEI" \ --rpc-url "http://192.168.11.250:8545" ``` ### Step 5: Bridge to Ethereum Mainnet Send the cross-chain transfer: ```bash ETHEREUM_SELECTOR="5009297550715157269" AMOUNT_WEI=$(cast --to-wei 1.0 ether) DEPLOYER=$(cast wallet address --private-key "0xYourPrivateKey") cast send "0x89dd12025bfCD38A168455A44B400e913ED33BE2" \ "sendCrossChain(uint64,address,uint256)" \ "$ETHEREUM_SELECTOR" \ "$DEPLOYER" \ "$AMOUNT_WEI" \ --rpc-url "http://192.168.11.250:8545" \ --private-key "0xYourPrivateKey" \ --gas-price 5000000000 ``` **What happens:** - Bridge contract transfers WETH9 from your address - CCIP message is sent to Ethereum Mainnet - On Ethereum Mainnet, WETH9 tokens are minted to your address - The process typically takes a few minutes ## Using Web3 Libraries ### JavaScript/TypeScript (ethers.js) ```javascript const { ethers } = require('ethers'); // Setup const provider = new ethers.providers.JsonRpcProvider('http://192.168.11.250:8545'); const wallet = new ethers.Wallet('0xYourPrivateKey', provider); const WETH9_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; const BRIDGE_ADDRESS = '0x89dd12025bfCD38A168455A44B400e913ED33BE2'; const ETHEREUM_SELECTOR = '5009297550715157269'; // Step 1: Wrap ETH const weth9 = new ethers.Contract(WETH9_ADDRESS, [ 'function deposit() payable', 'function balanceOf(address) view returns (uint256)', 'function approve(address,uint256) returns (bool)', 'function allowance(address,address) view returns (uint256)' ], wallet); const amount = ethers.utils.parseEther('1.0'); const wrapTx = await weth9.deposit({ value: amount }); await wrapTx.wait(); console.log('Wrapped ETH to WETH9:', wrapTx.hash); // Step 2: Approve Bridge const approveTx = await weth9.approve(BRIDGE_ADDRESS, ethers.constants.MaxUint256); await approveTx.wait(); console.log('Approved bridge:', approveTx.hash); // Step 3: Bridge const bridge = new ethers.Contract(BRIDGE_ADDRESS, [ 'function sendCrossChain(uint64,address,uint256)', 'function calculateFee(uint64,uint256) view returns (uint256)' ], wallet); const fee = await bridge.calculateFee(ETHEREUM_SELECTOR, amount); console.log('CCIP Fee:', ethers.utils.formatEther(fee)); const bridgeTx = await bridge.sendCrossChain(ETHEREUM_SELECTOR, wallet.address, amount); await bridgeTx.wait(); console.log('Bridged to Ethereum Mainnet:', bridgeTx.hash); ``` ### Python (web3.py) ```python from web3 import Web3 # Setup w3 = Web3(Web3.HTTPProvider('http://192.168.11.250:8545')) account = w3.eth.account.from_key('0xYourPrivateKey') WETH9_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' BRIDGE_ADDRESS = '0x89dd12025bfCD38A168455A44B400e913ED33BE2' ETHEREUM_SELECTOR = 5009297550715157269 # WETH9 ABI (simplified) weth9_abi = [ { "constant": False, "inputs": [], "name": "deposit", "outputs": [], "payable": True, "stateMutability": "payable", "type": "function" }, { "constant": False, "inputs": [{"name": "spender", "type": "address"}, {"name": "amount", "type": "uint256"}], "name": "approve", "outputs": [{"name": "", "type": "bool"}], "type": "function" } ] # Bridge ABI (simplified) bridge_abi = [ { "constant": False, "inputs": [ {"name": "destinationChainSelector", "type": "uint64"}, {"name": "recipient", "type": "address"}, {"name": "amount", "type": "uint256"} ], "name": "sendCrossChain", "outputs": [], "type": "function" } ] weth9 = w3.eth.contract(address=WETH9_ADDRESS, abi=weth9_abi) bridge = w3.eth.contract(address=BRIDGE_ADDRESS, abi=bridge_abi) amount = w3.toWei(1.0, 'ether') # Step 1: Wrap ETH tx_hash = weth9.functions.deposit().transact({ 'from': account.address, 'value': amount, 'gas': 100000, 'gasPrice': w3.toWei(5, 'gwei') }) receipt = w3.eth.wait_for_transaction_receipt(tx_hash) print(f'Wrapped ETH: {tx_hash.hex()}') # Step 2: Approve Bridge max_uint256 = 2**256 - 1 tx_hash = weth9.functions.approve(BRIDGE_ADDRESS, max_uint256).transact({ 'from': account.address, 'gas': 100000, 'gasPrice': w3.toWei(5, 'gwei') }) receipt = w3.eth.wait_for_transaction_receipt(tx_hash) print(f'Approved bridge: {tx_hash.hex()}') # Step 3: Bridge tx_hash = bridge.functions.sendCrossChain( ETHEREUM_SELECTOR, account.address, amount ).transact({ 'from': account.address, 'gas': 500000, 'gasPrice': w3.toWei(5, 'gwei') }) receipt = w3.eth.wait_for_transaction_receipt(tx_hash) print(f'Bridged to Ethereum Mainnet: {tx_hash.hex()}') ``` ## Important Notes ### Gas Fees - Wrapping ETH: ~50,000 gas - Approving bridge: ~50,000 gas - Bridging: ~200,000-500,000 gas (depends on CCIP complexity) - Keep extra ETH for gas fees (recommend 0.01+ ETH) ### Transaction Confirmation - ChainID 138 transactions typically confirm in seconds - CCIP bridge transfers may take 5-15 minutes to complete on Ethereum Mainnet - Monitor both chains for completion ### Security - **Never share your private key** - Store private keys securely (use environment variables or secure key management) - Verify contract addresses before interacting - Double-check amounts before sending ### Troubleshooting **Insufficient Balance:** ```bash # Check ETH balance cast balance "$DEPLOYER" --rpc-url "$RPC_URL" # Check WETH9 balance cast call "$WETH9_ADDRESS" "balanceOf(address)" "$DEPLOYER" --rpc-url "$RPC_URL" ``` **Transaction Failed:** - Check gas price (may need to increase) - Verify nonce (may need to wait for previous transactions) - Ensure sufficient balance for amount + gas **Bridge Not Approved:** ```bash # Check allowance cast call "$WETH9_ADDRESS" "allowance(address,address)" "$DEPLOYER" "$WETH9_BRIDGE" --rpc-url "$RPC_URL" ``` ## Monitoring Transactions - **ChainID 138 Explorer**: https://explorer.d-bis.org - **Ethereum Mainnet Explorer**: https://etherscan.io ## Additional Resources - [WETH9 Contract Documentation](https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#WETH) - [CCIP Documentation](https://docs.chain.link/ccip) - [Foundry Cast Documentation](https://book.getfoundry.sh/reference/cast/)