Skip to main content

L2→L1 Bridge

This guide explains how to withdraw assets from GIWA Chain (L2) to Ethereum mainnet (L1).

L1→L2 Deposit

For deposits from Ethereum to GIWA Chain, use the official GIWA Superbridge.

See: GIWA Bridge Documentation

useBridge Hook

import { useBridge } from 'giwa-react-native-wallet';

function BridgeScreen() {
const {
withdrawETH, // L2 → L1 ETH withdrawal
withdrawToken, // L2 → L1 token withdrawal
getPendingTransactions,
getTransaction, // Track transaction by hash
getEstimatedWithdrawalTime,
isLoading,
isInitializing,
error,
} = useBridge();

// ...
}

ETH Withdrawal

Transfer ETH from GIWA Chain to Ethereum mainnet:

const handleWithdrawETH = async () => {
try {
const hash = await withdrawETH('0.1'); // 0.1 ETH

console.log('L2 TX Hash:', hash);

// Track transaction status
const tx = getTransaction(hash);
console.log('Status:', tx?.status);

// Note: Full withdrawal takes ~7 days due to Challenge Period
} catch (error) {
console.error('Withdrawal failed:', error.message);
}
};

Withdraw to Different Address

// Withdraw to a specific L1 address
const hash = await withdrawETH('0.1', '0x1234...abcd');

Token Withdrawal

Transfer ERC-20 tokens from GIWA Chain to Ethereum mainnet:

const handleWithdrawToken = async () => {
const l2TokenAddress = '0x...'; // L2 token address
const amount = 100000000000000000000n; // 100 tokens (in wei)

try {
const hash = await withdrawToken(l2TokenAddress, amount);

console.log('L2 TX Hash:', hash);

// Track transaction status
const tx = getTransaction(hash);
console.log('Status:', tx?.status);
} catch (error) {
console.error('Withdrawal failed:', error.message);
}
};

Challenge Period

7-Day Waiting Period

L2 → L1 withdrawals require approximately 7 days of Challenge Period for security reasons. During this period, validators verify the validity of the withdrawal request.

This is a security feature of the OP Stack architecture, not a limitation of this SDK.

// Get estimated withdrawal time in seconds
const time = getEstimatedWithdrawalTime();
console.log('Estimated time:', time / 86400, 'days'); // ~7 days

Pending Transactions

Track pending bridge transactions:

const pendingTxs = getPendingTransactions();

pendingTxs.forEach((tx) => {
console.log('Hash:', tx.l2TxHash);
console.log('Amount:', tx.amount);
console.log('Status:', tx.status);
});

Complete Example

import { useState } from 'react';
import { View, Text, TextInput, Button, Alert, Linking } from 'react-native';
import { useBridge, useBalance } from 'giwa-react-native-wallet';

export function BridgeScreen() {
const [amount, setAmount] = useState('');
const {
withdrawETH,
getEstimatedWithdrawalTime,
isLoading,
isInitializing,
error,
} = useBridge();
const { formattedBalance } = useBalance();

const handleWithdraw = async () => {
if (!amount) return;

const days = Math.round(getEstimatedWithdrawalTime() / 86400);

Alert.alert(
'Confirm Withdrawal',
`Withdraw ${amount} ETH to L1?\n\nThis will take approximately ${days} days.`,
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Confirm',
onPress: async () => {
try {
const hash = await withdrawETH(amount);
Alert.alert('Withdrawal Started', `TX: ${hash}`);
} catch (error) {
Alert.alert('Error', error.message);
}
},
},
]
);
};

const openSuperbridge = () => {
Linking.openURL('https://superbridge.app');
};

if (isInitializing) {
return <Text>Loading...</Text>;
}

return (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, marginBottom: 10 }}>Bridge</Text>

{error && (
<Text style={{ color: 'red', marginBottom: 10 }}>{error.message}</Text>
)}

{/* Deposit Link */}
<Button
title="Deposit (L1→L2) via Superbridge"
onPress={openSuperbridge}
/>

<Text style={{ marginTop: 20, marginBottom: 10 }}>
Withdraw (L2→L1)
</Text>
<Text style={{ color: '#666', marginBottom: 10 }}>
Balance: {formattedBalance} ETH
</Text>

<TextInput
placeholder="Amount (ETH)"
value={amount}
onChangeText={setAmount}
keyboardType="decimal-pad"
style={{
borderWidth: 1,
borderColor: '#ccc',
padding: 12,
marginBottom: 10,
borderRadius: 8,
}}
/>

<Text style={{ color: 'orange', marginBottom: 10, fontSize: 12 }}>
Withdrawals take approximately 7 days
</Text>

<Button
title={isLoading ? 'Processing...' : 'Withdraw'}
onPress={handleWithdraw}
disabled={isLoading || !amount}
/>
</View>
);
}

Next Steps