Move Model Lifecycle
This document illustrates the lifecycle of key Move models in the deposit and withdrawal flows, showing how data structures transform between onchain (Sui) and offchain (Bitcoin) states.
What is the entry-function gating principle?
Every entry function that takes the Hashi object asserts the package
version is enabled. Beyond that, pause and reconfiguration gate only the
deposit and withdrawal flows. The table shows which entry functions stop
when governance pauses the system and which stop while a committee handoff is
pending.
| Entry functions | Stops during a pause | Stops while a committee handoff is pending |
|---|---|---|
Deposit approval (approve_deposit()) and confirmation (confirm_deposit()) | Yes | Yes |
Withdrawal approval (approve_request()), commitment, signing, and finalization (finalize_withdrawal()) | Yes | Yes |
User requests (deposit(), request_withdrawal()) | Yes | No |
Withdrawal confirmation (confirm_withdrawal()) | Yes | No |
| Withdrawal cancellation | No | No |
| Reconfiguration, MPC certificate submission, governance | No | No |
Cleanup entries: cleanup_spent_utxos, archive_confirmed_withdrawals, archive_withdrawal_requests, finish_archive_withdrawal_txns, destroy_key_gen_certs, destroy_nonce_certs, delete_expired_deposit, proposal::delete_expired | No | No |
| Validator registration or key rotation | No | No |
The last 4 rows never check pause, because an emergency pause must not block operators from maintaining nodes or the chain from shedding dead state. Nodes themselves stop all leader work while paused, garbage collection included, so during a pause only a manual call sheds that state. One asymmetry is intentional: users can request deposits and withdrawals during reconfiguration (a withdrawal request only escrows their hBTC); only committee approval, commitment, signing, and deposit confirmation wait for the new committee.
How do Move models change during a deposit?
During a reconfiguration, users can still call deposit(), but approval and
confirmation wait for the new committee; see
What is the entry-function gating principle?.
Deposit flow summary
| Step | Actor | Action | Model Transformation |
|---|---|---|---|
| 1 | User | User sends BTC to bridge address | Bitcoin UTXO created |
| 2 | User | User calls deposit() | DepositRequest → DepositRequestQueue |
| 3 | Committee members | Committee members wait for Bitcoin confirmations | bitcoin_confirmation_threshold blocks on the deposit transaction |
| 4 | Committee members | Committee members screen and sign request | Members with a TRM API key screen it (Mainnet only); BLS signatures aggregated → CommitteeSignature |
| 5 | Leader | Leader calls approve_deposit() with cert | verify_certificate() → request stores approval_cert and approved_timestamp_ms |
| 6 | None | Time-delay window elapses | bitcoin_deposit_time_delay_ms (a window to catch a faulty approval and pause before the contract mints anything) |
| 7 | Anyone | Anyone calls confirm_deposit() | Re-verify_certificate() → CertifiedMessage<DepositConfirmationMessage> |
| 8 | Treasury | Treasury mints tokens | If the UTXO has a derivation path, Utxo.amount → Balance<BTC> sent to that address |
| 9 | None | Certified request processed | Utxo → UtxoPool; DepositRequest → DepositRequestQueue.processed with confirmed_timestamp_ms set |
How do Move models change during a withdrawal?
During a reconfiguration, users can still call request_withdrawal() and
withdrawal confirmation still proceeds, but approval, commitment, signing, and
finalization wait for the new committee; see
What is the entry-function gating principle?.
The config key bitcoin_confirmation_threshold (default 6) stores the
Bitcoin confirmation threshold onchain. Hashi stores witness signatures
onchain so that any leader can reconstruct and re-broadcast the signed
Bitcoin transaction without MPC re-signing (for example, after leader
rotation, mempool eviction, or a Bitcoin reorganization).
Limiter coordination. The LocalLimiter on each committee node is a
deterministic projection of the onchain stream. Outside a reconcile (below),
its next_seq advances only when the node's object mirror sees a
WithdrawalTransaction become fully signed (the finalize_withdrawal write).
The finalize path uses validate_consume (read-only) to gate participation,
never to mutate state: the leader checks before it calls the guardian, and
each member checks again before it signs the finalize certificate. The
leader's flow only reaches finalize_withdrawal() after
finalize_withdrawal_through_guardian returns Ok, so seeing the transaction
become fully signed onchain is a sufficient proxy for the guardian having
acknowledged the request. The guardian advances its own next_seq when it
signs, so the local cache trails it while a withdrawal is in flight. On
startup, each node seeds its LocalLimiter through GetGuardianInfo, then
periodically reconciles against it, snapping back a cache that stalled or
drifted and adopting a new limiter policy after a guardian rotation.
Withdrawal flow summary
| Step | Actor | Action | Model Transformation |
|---|---|---|---|
| 1 | User | User requests withdrawal | Balance<BTC> → WithdrawalRequest → WithdrawalRequestQueue.requests |
| 2 | Committee | Committee screens and approves request | Members with a TRM API key screen it (Mainnet only); approve_request() records approval_cert on the request |
| 3 | Leader | Leader commits withdrawal tx | Balance<BTC> burned, WithdrawalTransaction created in .withdrawal_txns |
| 4 | Committee (MPC) | MPC protocol signs Bitcoin transaction | Committee signs each input through MPC; commit_input_signatures() stores the signatures onchain in chunks |
| 5 | Leader | Leader checks its LocalLimiter | LocalLimiter::validate_consume(seq, ts, amt) (read-only) before calling the guardian |
| 6 | Leader | Leader BLS-certs StandardWithdrawalRequest | Aggregated cert over (wid, seq, ts, utxos), the input to the guardian RPC |
| 7 | Guardian | Guardian rate-limit check + enclave sig | StandardWithdrawal RPC: verify cert → consume(seq, ts, amt) → enclave signatures |
| 8 | Leader | Leader finalizes with guardian signatures | Members re-run validate_consume and certify both signature sets; finalize_withdrawal() attaches the guardian signatures |
| 9 | Each node | Each node advances its LocalLimiter | Object mirror sees the tx become fully signed → apply_consume(seq, ts, amt) |
| 10 | Leader | BTC transaction broadcast (and re-broadcast) | Signed tx reconstructed from onchain data, broadcast to Bitcoin |
| 11 | Committee | Committee signs confirmation certificate | CommitteeSignature created after BTC tx confirmed |
| 12 | Leader | Leader confirms withdrawal | confirmed_timestamp_ms set, input UTXOs marked spent; the leader's GC later moves the tx to .confirmed_txns, its requests to .processed, and the spent inputs to spent_utxos |
What are the key Move models?
| Model | Location | Description |
|---|---|---|
Balance<BTC> | User wallet | Wrapped BTC token on Sui |
DepositRequest | DepositRequestQueue.requests, then .processed once confirmed | Deposit request with its approval cert and timestamps; deleted if it expires unconfirmed |
Utxo | UtxoPool | Onchain representation of a Bitcoin UTXO |
WithdrawalRequest | WithdrawalRequestQueue.requests, then .processed once archived | User's withdrawal request with destination; approval_cert and withdrawal_txn_id mark approval and commitment |
WithdrawalTransaction | WithdrawalRequestQueue.withdrawal_txns | In-flight withdrawal tx (kept after confirmation until archived), stores inputs, outputs, and witness signatures |
WithdrawalTransaction | WithdrawalRequestQueue.confirmed_txns | Confirmed withdrawal tx, moved here by the leader's archival GC (historical record) |
Bitcoin UTXO | Bitcoin Network | Actual unspent transaction output on Bitcoin |
Committee | CommitteeSet | BLS signing committee of Sui validators for an epoch |
CommitteeMember | Committee.members | Validator with public_key and voting weight |
CommitteeSignature | Built in the programmable transaction block (PTB) by committee::new_committee_signature; stored as approval_cert on requests | Aggregated BLS signature with signers bitmap |
CertifiedMessage<T> | Verified onchain | Message proven to have committee quorum support |