Files
explorer-monorepo/docs/WRAP_AND_BRIDGE_TO_ETHEREUM.md

340 lines
9.5 KiB
Markdown
Raw Normal View History

# 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/)