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:txTypeis the transaction type. ForDEPOSITtransactions, it isKeystoreTxType.DEPOSIT.datais the transaction data, serialized differently depending on the transaction type. ForDEPOSITtransactions, 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 theuint256L1-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 theuint256fee 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:
batchIndexsuchbatchIndex >= c, such that there is a batchhwhereh.batchIndex = batchIndex.preimagemust be aOutputRootPreImagewhere:preimage.stateRoot = h.lastBlock.stateRootpreimage.withdrawalsRoot = h.lastBlock.withdrawalsRootpreimage.lastValidBlockhash = h.lastBlock.blockhash
keystoreAddress = t.userAcct.keystoreAddresswithdrawAmount = t.amtnonce = t.nonceto = t.toproofto 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)
isLeftis auint256that packs all theisLeftbooleans 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.