Bridging L1 and L2 (Standard Bridge)
Titan supports Standard Bridge for moving assets between Ethereum L1 and Titan L2. Users can send ETH and ERC20 tokens to L2 via a Standard Bridge contract (deposit). Conversely, users can transfer ETH, ERC20 tokens from L2 to L1 via Standard Bridge (withdraw).
To deposit ETH from L1 to L2, you must first use the depositETH
or depositETHTo
functions of the L1StandardBridge
contract to deposit ETH. For ERC20 tokens, use the depositERC20
or depositERC20To
functions of the same contract. After the deposit transaction is mined, it takes a few minutes for the assets to be processed and appear in L2.
Withdrawal refers to the movement of assets from L2 to L1. To withdraw ETH and ERC20 tokens from L2, use the withdraw
and withdrawTo
functions of the L2StandardBridge
contract. Unlike L1, withdrawals in L2 are not split between ETH and ERC20, as ETH is treated as a ERC20 token in L2. Withdrawals from Titan can take up to one week due to the characteristics of Optimistic Rollup and the time required for L2 to validate transactions.
This section will guide you on importing the Titan Contacts package and demonstrate a JavaScript code example for depositing or withdrawing ETH.
The example code can be found here. To learn how to transfer ETH between L1-L2 using the Titan SDK, we recommend running the code yourself.
Setup
To interact with the Ethereum blockchain, import the
ethers
library. Additionally, obtain the@tokamak-network/titan-contracts
package to pre-deploy and obtain the ABI and bytecode of theL1StandardBridge
andL2StandardBridge
.
To create a factory instance of each contract, use the artifacts of
L1StandardBridge
andL2StandardBridge
as parameters, which can be imported via the@tokamak-network/titan-contracts
package.
Using the
ethers
library, create aprovider
object and awallet
object for L1 and L2. Then create instances ofL1StandardBridge
andL2StandardBridge
as follows.
Create
L2StandardBridge
instance:Use
factory__L2StandardBridge
to leverage methods from a contract factory instanceConnect
l2Wallet
toL2StandardBridge
Create an
L2StandardBridge
instance by calling theattach
function withpredeploys.L2StandardBridge
as the contract address
Create
L1StandardBridge
instance:Use
factory__L1StandardBridge
to leverage methods from a contract factory instanceCall the
L2StandardBridge
'sl1TokenBridge()
function to get the L1 Standard Bridge contract address,L1StandardBridgeAddress
.Connect
l1Wallet
toL1StandardBridge
Call the
attach
function usingL1StandardBridgeAddress
as the contract address to create an instance of theL1StandardBridge
.
Deposit
To move ETH from L1 to L2, call the
depositETH
function of theL1StandardBridge
contract created in the previous step. Ensure that your L1 account has at least the amount of ETH you are depositing, as well as the appropriate gas fee to send the transaction.The
depositETH
function has three parameters. The first parameter is the amount of gas to be used for the L2 transaction, while the second parameter is additional data passed in the form of calldata. In the example below, an empty array is used. The third parameter sets the amount of ETH to deposit via thevalue
property. This is done by converting thebalance
value to ether usingethers.utils.parseEther(balance)
.After deposit transaction is processed on L1,
receipt
object representing the information for the transaction can be retrieved. You can check thestatus
property of the transactionreceipt
object to see if the transaction was processed successfully. If the value ofstatus
is not 1, it will throw anError
object indicating that the transaction has failed.The deposit transaction requested from L1 generates a message with
L2StandardBridge
as the destination and forwards it to L2. After passing throughL1CrossDomainMessenger
andL2CrossDomainMessenger
, the message calls thefinalizeDeposit
function ofL2StandardBridge
to send the amount of ETH deposited to L2.
Withdraw
You can withdraw ETH from L2 to L1 by calling the
withdraw
function ofL2StandardBridge
. (Make sure you have appropriate ETH to pay for the gas fee.)The first parameter of the function specifies a L2 token address that specifies the asset to be withdrawn to L1. In our example, we use
predeploys.OVM_ETH
, which usesOVM_ETH
so that it can be treated as a token. The second parameter sets the amount of ETH to be withdrawn. It is set by converting thebalance
value to ether units usingethers.utils.parseEther(balance)
. The third parameter is a value representing the withdrawal ownership of the token. In our example, we use 0. The fourth parameter is additional data about the withdrawal, passed as a string. The example uses'0xFFFF'
.We wait for the withdraw transaction to be processed on the L2 and get a
receipt
object representing the receive information for the transaction. You can confirm thestatus
property of the transaction'sreceipt
object to see if the transaction was processed successfully.The withdraw transaction sent by L2 generates a message with
L1StandardBridge
as the destination and forwards it to L1. In an optimal rollup, the transaction and State Root generated on L2 are rolled-up to L1. Once it is confirmed that the State Root has been successfully rolled-up on L1, the message relayer service callsL1CrossDomainMessenger
to forward the message to L1. Titan supports batch-relay, where multiple messages are delivered in one transaction to lower transaction fees and speed up to relay. The withdrawal is then finalized by calling thefinalizeETHWithdrawal
function ofL1StandardBridge
to send ETH to L1.
Last updated