Deposits
Deposit is the process of moving funds from L1 to a keystore account on the rollup, which is done by executing aDEPOSIT
transaction on the keystore. DEPOSIT
transaction are L1-initiated transactions. A transaction must be submitted to the rollup bridge on L1 using the initiateL1Transaction
function. The bridge performs validation to ensure sufficient funds are deposited.
L1-Initiated Transactions Format
L1-initiated transactions follow this structure defined in the keystore bridge contract:txType
is the transaction type. ForDEPOSIT
transactions, it isKeystoreTxType.DEPOSIT
.data
is the transaction data, serialized differently depending on the transaction type. ForDEPOSIT
transactions, it represents the keystore address.
Withdrawals
Withdrawal is the process of moving funds from keystore to L1, which is done by executing aWITHDRAW
transaction on the keystore. A WITHDRAW
transaction is serialized in the following format:
bool isL1Initiated
: Whether the transaction is L1-initiated.bytes l1InitiatedNonce
: Represents theuint256
L1-initiated nonce for the transaction if the transaction is L1-initiated and the empty bytestringbytes(0x)
otherwise.uint256 nonce
: The nonce for the transaction.bytes feePerGas
: Represents theuint256
fee per gas for the transaction if the transaction is not L1-initiated and the empty bytestringbytes(0x)
otherwise.address to
: The L1 Ethereum address to withdraw to.uint256 amt
: The amount of ETH in wei to withdraw.KeystoreAccount userAcct
: The user account paying for the transaction.bytes userProof
: The user’s ZK authentication proof for the transaction.
keystore_sendRawTransaction
RPC endpoint.
Once a withdrawal transaction is finalized on L1, it is possible to withdraw funds from the keystore bridge contract to the requested L1 Ethereum address, which is determined by the to
field of the withdrawal transaction. This process is called finalizing a withdrawal.
To finalize a withdrawal, call the finalizeWithdrawal
method on the keystore bridge contract, which is defined as:
tx
. Assume tx
was included in block k
, and k
was committed in batch c
. Also assume c
is finalized on L1.
To finalize tx
(to withdraw funds from bridge contract) user needs to call finalizeWithdrawal
method on the contract with following arguments:
batchIndex
suchbatchIndex >= c
, such that there is a batchh
whereh.batchIndex = batchIndex
.preimage
must be aOutputRootPreImage
where:preimage.stateRoot = h.lastBlock.stateRoot
preimage.withdrawalsRoot = h.lastBlock.withdrawalsRoot
preimage.lastValidBlockhash = h.lastBlock.blockhash
keystoreAddress = t.userAcct.keystoreAddress
withdrawAmount = t.amt
nonce = t.nonce
to = t.to
proof
to be a Merkle Proof showing(withdrawalHash, withdrawal)
pair exists in the withdrawals state at blockh.lastBlock
, where:withdrawalHash = keccak256(abi.encodePacked(t.userAcct.keystoreAddress, t.nonce))
withdrawal = Withdrawal(t.to, t.amt)
isLeft
is auint256
that packs all theisLeft
booleans in the Merkle proof returned by the node JSONRPC server.
buildFinalizeWithdrawalArgs
that prepares the required arguments for finalizeWithdrawal
.
Latency
The latency of deposits is mainly determined by the L1-initiated transaction inclusion time. This refers to the total time from the submission of an L1-initiated transaction to L1 until it is included in an L2 block. This timing depends on how closely the sequencer follows L1. In keystore, the sequencer lags behind L1 blocks by 10–30 blocks. The latency of a withdrawal can be broken down into two parts:- Proof generation time: the total time it takes for the signature prover to generate the ZK proof(s) for a transaction.
- Transaction finalization: the total time from the submission of a transaction to the sequencer until it is finalized on the L1 bridge.