Deposit Bridge
The deposit bridge proves that an ordered range of Ethereum deposits produces the expected Zeko deposit actions.
Deposits on Ethereum
Users call deposit for ERC20 tokens or depositETH for native ETH on EthereumZekoBridge.sol.
For each deposit, the contract:
- Checks that the token is allowed and the amount is non-zero.
- Locks the funds and rejects fee-on-transfer ERC20 tokens.
- Normalizes the Ethereum amount to the configured Zeko decimals.
- Increments
depositNonce. - Computes a deposit leaf.
- Appends the leaf to
currentDepositState. - Stores the checkpoint in
depositStateByNonce.
Packed Zeko addresses contain a Pasta Fp x-coordinate in the lower 255 bits and the public-key parity flag in the highest bit.
Proof input
BridgeTransitionInput contains:
| Field | Meaning |
|---|---|
ethereum.chain_id | Chain ID included in every deposit leaf. |
ethereum.bridge_address | Bridge address included in leaves and used as holderAccountL1. |
ethereum.deposit_nonce | Nonce immediately before the batch. |
ethereum.deposit_state | Deposit accumulator immediately before the batch. |
zeko.action_state | Zeko action state immediately before the batch. |
deposits[] | Ordered deposits to replay. |
Each deposit contains token, amount, zeko_amount, zeko_recipient, and timeout. The guest uses zeko_amount; the original Ethereum amount is informational and is not included in the proof calculation.
Deposit accumulator
For each deposit, the guest increments the nonce and computes values equivalent to Solidity keccak256(abi.encode(...)):
deposit_leaf = keccak256(
keccak256("ZEKO_BRIDGE_DEPOSIT_LEAF_V1"),
chain_id,
bridge_address,
token,
zeko_recipient,
zeko_amount,
timeout,
nonce
)
deposit_state_after = keccak256(
keccak256("ZEKO_BRIDGE_DEPOSIT_STATE_V1"),
deposit_state_before,
deposit_leaf
)Zeko deposit action
The guest unpacks zeko_recipient into (x, isOdd) and computes:
action = Poseidon.hashWithPrefix("Deposit_params - qFB3jXP*)", [
Field(0),
holderAccountL1,
zekoAmount,
recipient.x,
recipient.isOdd,
timeout
])Each deposit is wrapped in its own Mina action list and appended with the same domain-separated Poseidon operations used by o1js.
Public values
| Field | Meaning |
|---|---|
ethereum_state_before | Deposit accumulator before the batch. |
ethereum_state_after | Deposit accumulator after the batch. |
ethereum_nonce_before | Deposit nonce before the batch. |
ethereum_nonce_after | Deposit nonce after the batch. |
zeko_action_state_before | Supplied Zeko action state before the batch. |
zeko_action_state_after | Computed Zeko action state after the batch. |
deposit_count | Number of replayed deposits. |
Contract checks
submitBridgeTransition verifies:
depositStateByNonce[ethereum_nonce_before] == ethereum_state_before
ethereum_nonce_after == depositNonce
ethereum_state_after == currentDepositState
ethereum_nonce_after == ethereum_nonce_before + deposit_count
zeko_action_state_after has not already been processedThis binds the proven batch to the current Ethereum deposit history.
Settlement binding
The deposit transition currently does not require its before or after Zeko action state to be a checkpoint recorded by ZekoSettlement. The accepted event alone does not prove that Zeko consumed the deposit actions.