security(operator): scope EVM deposit nonce lookup by source chain #184

Open
opened 2026-09-12 12:46:48 +00:00 by PlasticDigits · 0 comments

Summary

find_evm_deposit_id_by_nonce_for_evm in packages/operator/src/db/mod.rs selects a pending evm_deposits row with WHERE nonce = $1 AND status = 'pending' LIMIT 1. Source chain and transfer hash are not in the predicate. Nonces are per source bridge, not globally unique: BSC, opBNB, MegaETH, and other EVM sources all start at the same nonce sequence. LIMIT 1 with no ORDER BY can mark the wrong pending row processed after dest WithdrawApprove. The deposit that was actually approved stays pending.

The cosmos sibling already binds source chain. find_evm_deposit_id_by_src_v2_chain_nonce_for_cosmos uses src_v2_chain_id = $1 AND nonce = $2 AND dest_chain_type = 'cosmos' AND status = 'pending'. The EVM helper’s comment says it omits dest_chain_type on purpose (V2 poll-and-approve can dest-approve EVM→EVM without the DB-driven path). That is not a reason to omit src_v2_chain_id.

Caller already has the missing key. EvmWriter::sync_deposit_status_after_approval(&self, src_chain_id: &[u8; 4], nonce: u64) is invoked from enumeration and from poll_and_approve after dest approve succeeds. It passes only nonce into the EVM lookup, then update_evm_deposit_status(..., "processed") and returns. Schema already indexes (chain_id, nonce) (idx_evm_deposits_chain_nonce) and uniqueness is (chain_id, tx_hash, log_index), not global nonce.

This is not #183 (RS-H2: reorg / stored block_hash never re-checked). This is not #182 (RS-H1: Terra confirmation depth). This is not closed #115 (RPC quorum / FINALITY_BLOCKS). This is not the cosmos helper (already scoped).

Internal review id: RS-H5 (high). Still in source as of 2026-09-12 (packages/operator/src/db/mod.rs + writers/evm.rs on main).

Bundle (same ticket, do not split):

  1. Scope the EVM pending-by-nonce lookup by src_v2_chain_id (required). Optionally also bind transfer_hash / xchain_hash_id when the approve path has it.
  2. Pass src_chain_id from sync_deposit_status_after_approval into that helper. Do not LIMIT 1 across chains. Fail closed if zero rows match; do not fall through to a different chain’s row.
  3. Tests with two pending evm_deposits sharing a nonce on different EVM src_v2_chain_id values: dest-approve for chain A must mark A processed and leave B pending.

Founder-required operator dest-approve / deposit status. No community autoland. Do not add ready.

Impact (today vs hypothetical)

Funds and operator correctness at risk today on any live operator that dest-approves EVM-origin withdrawals via V2 poll-and-approve / enumeration and then syncs DB status through this helper. Multi-EVM is the production topology (BSC, opBNB, additional EVM peers). Independent bridges assign overlapping nonces. The first matching pending row wins.

Wrong row marked processed:

  • Honest deposit on chain B with the same nonce is skipped by later DB-driven dest-approve (process_evm_deposit / pending queries that skip non-pending). User lock on B never gets dest mint/unlock through the DB path.
  • The deposit that was just dest-approved on chain A stays pending. Legacy DB-driven code can try to dest-approve it again, or /status pending_deposits stays wrong for the real transfer and lies for the stolen row.

Cross-family variant of the same bug: sync_deposit_status_after_approval tries the nonce-only EVM lookup first and returns on any hit. A Terra-source dest-approve with nonce N can mark a pending BSC row with nonce N processed and never reach find_terra_deposit_id_by_nonce. Binding EVM lookup to src_v2_chain_id stops that fall-through.

This is not permissionless theft of unrelated vault inventory by a stranger with no deposit. It is operator state corruption at dest-approve time: the wrong lock is treated as done, the right lock is left pending or skipped. Severity is high because dest mint/unlock is the payout and processed is the gate that stops a second dest-approve. Rate limits and dest cancel windows do not restore the skipped row.

Hypothetical-only if every pending-by-nonce lookup already required src_v2_chain_id (they do not: only the cosmos helper does) or if the operator ingested a single EVM source so nonces cannot collide (not true once two EVM watchers insert pending rows). Sticky until the predicate and caller pass the source id and tests prove colliding nonces cannot cross-mark.

Do not publish a mainnet two-chain same-nonce dest-approve sequence.

Cosmos helper already scoped; EVM helper is not

find_evm_deposit_id_by_src_v2_chain_nonce_for_cosmos
  WHERE src_v2_chain_id = $1 AND nonce = $2 AND dest_chain_type = 'cosmos' AND status = 'pending'

find_evm_deposit_id_by_nonce_for_evm
  WHERE nonce = $1 AND status = 'pending'
  LIMIT 1

The EVM helper’s docstring contrasts dest type, not source chain. src_v2_chain_id is a column on insert (insert_evm_deposit) and on pending SELECTs. It is unused here.

Caller drops the source id it already has

sync_deposit_status_after_approval(src_chain_id, nonce) is called from:

  • Enumeration dest-approve success (submit_withdraw_approve then sync).
  • poll_and_approve dest-approve success (WithdrawSubmit events).

Both have src_chain_id and xchain_hash_id in scope. Only nonce reaches SQL. On Ok(Some(deposit_id)) the writer sets processed and returns, so a Terra fallback never runs.

Schema does not treat nonce as global

UNIQUE (chain_id, tx_hash, log_index). Index idx_evm_deposits_chain_nonce is (chain_id, nonce). Two pending rows with the same nonce on different chain_id / src_v2_chain_id are valid. LIMIT 1 is undefined which id wins.

Invariants

  • INV-OP-N1 (new): A pending evm_deposits row may be marked processed from V2 dest-approve sync only if src_v2_chain_id matches the approved source chain (4-byte V2 id). Nonce alone is not an identity.
  • INV-OP-N2 (new): Two pending EVM deposits with the same nonce and different src_v2_chain_id must not affect each other’s status. Dest-approve for A leaves B pending.
  • INV-OP-N3 (new): Zero matching rows → no status write (log and continue). Do not pick another chain’s row. Do not fail dest-approve that already landed on-chain solely because DB sync missed; dest-approve is already submitted — sync is bookkeeping, not a second approve.
  • INV-OP-N4 (new): If transfer_hash / xchain_hash_id is used as a second key, a hash mismatch must not update a different pending row with the same nonce.
  • Do not weaken dest WithdrawApprove verification, hash words, finality_blocks, or user withdrawSubmit. Do not drop the cosmos helper’s src_v2_chain_id bind. Do not make nonce globally unique in a way that rejects honest multi-EVM inserts.

Constraints / guardrails

  • Prefer adding src_v2_chain_id: &[u8; 4] to find_evm_deposit_id_by_nonce_for_evm (or replace it with a clearly named helper) and passing src_chain_id from sync_deposit_status_after_approval. Keep “any dest_chain_type” unless a dest-type filter is proven safe for every V2 path that calls this sync.
  • Optional tighter bind: AND transfer_hash = $n when the approve path has xchain_hash_id and the row stores transfer_hash. Do not require hash if older rows have NULL; then source+nonce must still be unique enough (fail closed if two pending rows share source+nonce).
  • Prefer src_v2_chain_id (V2 4-byte) over native chain_id BIGINT so BSC / opBNB / other EVM peers match the cosmos helper and the bytes the writer already holds. If some rows have NULL src_v2_chain_id, fail closed for those rows on this sync path rather than matching on nonce only.
  • Do not ORDER BY id + LIMIT 1 as a “fix”. That still picks the wrong chain.
  • Do not change Solidity / CosmWasm / Solana programs. Do not retune reorg inclusion (#183) or Terra confirmation depth (#182) here.
  • Founder-required operator / dest approve / deposit identity. No community autoland. Do not add ready. No public mainnet collision recipe.

Relevant files

Path Why
packages/operator/src/db/mod.rs find_evm_deposit_id_by_nonce_for_evm (nonce-only); cosmos sibling already scoped; update_evm_deposit_status
packages/operator/src/writers/evm.rs sync_deposit_status_after_approval has src_chain_id and ignores it; two call sites after dest approve
packages/operator/src/writers/terra.rs Cosmos helper call site — pattern to mirror, do not regress
packages/operator/migrations/001_initial.sql (chain_id, nonce) index; nonce not globally unique
Operator DB tests Missing colliding-nonce fixture
  1. Change the EVM helper to WHERE src_v2_chain_id = $1 AND nonce = $2 AND status = 'pending' (plus optional transfer_hash). Return None unless exactly one row matches. If two+ match, do not LIMIT 1; log and skip the status write (or match hash).
  2. Thread src_chain_id from sync_deposit_status_after_approval into the helper. Keep Terra fallback only when the EVM lookup returns None and src_chain_id is the Terra V2 id (existing Terra gate).
  3. Unit test: insert two pending EVM deposits, same nonce, distinct src_v2_chain_id (and distinct transfer_hash). Sync for chain A → only A is processed. Repeat for B.
  4. Unit test: Terra src_chain_id + colliding EVM pending nonce → EVM row stays pending; Terra path may still run.
  5. Honest path: single pending row matching source+nonce still becomes processed after dest-approve sync.

Acceptance criteria

  • AC1. find_evm_deposit_id_by_nonce_for_evm (or replacement) requires src_v2_chain_id. Query must not be nonce + pending only.
  • AC2. Two pending deposits, same nonce, different src_v2_chain_id: dest-approve sync for A marks A processed and leaves B pending.
  • AC3. Dest-approve whose src_chain_id matches no pending EVM row does not mark some other chain’s pending nonce processed.
  • AC4. Terra-source dest-approve with nonce equal to a pending EVM deposit does not mark that EVM row processed.
  • AC5. Cosmos helper find_evm_deposit_id_by_src_v2_chain_nonce_for_cosmos stays source-scoped. No contract change.
  • AC6. Existing operator tests stay green. New tests cover AC2–AC4 without a live BSC/opBNB node.

Test plan (functional paths)

# Path Expect
T1 One pending EVM row; dest-approve sync with matching src_v2_chain_id + nonce That id processed
T2 Two pending rows, same nonce, chain A and chain B; sync A A processed, B pending
T3 Same fixture; sync B B processed, A still pending (or already processed from T2 in a separate test)
T4 Sync with source C (no row) and nonce that exists on A A stays pending; no status write
T5 Matching source+nonce, status already approved / processed Helper returns None; no overwrite of a third pending row
T6 Optional hash bind: same source+nonce, wrong transfer_hash No status write
T7 Cosmos helper EVM→Terra still matches src_v2_chain_id + cosmos dest Unchanged

Test plan (attack, hack, and abuse)

Non-exploitative. Operator unit tests / local DB fixtures only. Do not use these as a mainnet recipe.

# Vector Expect
A1 Two EVM sources, identical nonce, both pending; dest-approve A Only A processed
A2 Repeat A1 with reversed insert order (so old LIMIT 1 would flip) Still only the matching source
A3 Terra-source dest-approve, EVM pending same nonce EVM row not processed
A4 NULL src_v2_chain_id on a pending row Fail closed for this sync; do not match on nonce only
A5 Ambiguous two pending rows same source+nonce (data bug) No LIMIT 1 pick; no silent wrong processed

Verification criteria

  • Operator package tests: T1–T7 and A1–A5. Grep that find_evm_deposit_id_by_nonce_for_evm (or replacement) binds src_v2_chain_id in SQL, not only in the Rust signature.
  • Grep that sync_deposit_status_after_approval passes src_chain_id into the helper.
  • Grep absence of WHERE nonce = $1 AND status = 'pending' without a chain or hash bind on the EVM deposit sync path.
  • Do not verify by dest-approving colliding mainnet deposits or by inspecting a live operator DB.

Out of scope

  • #183 reorg / block_hash inclusion before dest approve.
  • #182 Terra LCD confirmation depth.
  • #115 RPC quorum / FINALITY_BLOCKS defaults.
  • Making Terra find_terra_deposit_id_by_nonce multi-chain (single Terra source; only in scope insofar as the EVM-first fall-through in AC4).
  • Solidity getDeposit layout / hash words.
  • Live operator redeploy (ops).

First-pass model recommendation

Recommendation: grok-high

Rationale: Security class and founder-required operator dest-approve / deposit identity (wallet / bridge funds). Composer is disallowed (High/security; not a low-risk first pass). Even though the production edit is likely db/mod.rs plus writers/evm.rs plus tests, file count does not establish safety: a wrong processed write skips dest mint for the real lock or leaves it pending for a second dest-approve. Verify with two-chain colliding-nonce fixtures, not a live multi-EVM dest-approve.

## Summary `find_evm_deposit_id_by_nonce_for_evm` in `packages/operator/src/db/mod.rs` selects a pending `evm_deposits` row with `WHERE nonce = $1 AND status = 'pending' LIMIT 1`. Source chain and transfer hash are not in the predicate. Nonces are per source bridge, not globally unique: BSC, opBNB, MegaETH, and other EVM sources all start at the same nonce sequence. `LIMIT 1` with no `ORDER BY` can mark the wrong pending row `processed` after dest `WithdrawApprove`. The deposit that was actually approved stays `pending`. The cosmos sibling already binds source chain. `find_evm_deposit_id_by_src_v2_chain_nonce_for_cosmos` uses `src_v2_chain_id = $1 AND nonce = $2 AND dest_chain_type = 'cosmos' AND status = 'pending'`. The EVM helper’s comment says it omits `dest_chain_type` on purpose (V2 poll-and-approve can dest-approve EVM→EVM without the DB-driven path). That is not a reason to omit `src_v2_chain_id`. Caller already has the missing key. `EvmWriter::sync_deposit_status_after_approval(&self, src_chain_id: &[u8; 4], nonce: u64)` is invoked from enumeration and from `poll_and_approve` **after** dest approve succeeds. It passes only `nonce` into the EVM lookup, then `update_evm_deposit_status(..., "processed")` and `return`s. Schema already indexes `(chain_id, nonce)` (`idx_evm_deposits_chain_nonce`) and uniqueness is `(chain_id, tx_hash, log_index)`, not global nonce. This is not [#183](https://git.cl8y.com/code/cl8y-bridge-monorepo/issues/183) (RS-H2: reorg / stored `block_hash` never re-checked). This is not [#182](https://git.cl8y.com/code/cl8y-bridge-monorepo/issues/182) (RS-H1: Terra confirmation depth). This is not closed [#115](https://git.cl8y.com/code/cl8y-bridge-monorepo/issues/115) (RPC quorum / `FINALITY_BLOCKS`). This is not the cosmos helper (already scoped). Internal review id: RS-H5 (high). Still in source as of 2026-09-12 (`packages/operator/src/db/mod.rs` + `writers/evm.rs` on `main`). Bundle (same ticket, do not split): 1. Scope the EVM pending-by-nonce lookup by `src_v2_chain_id` (required). Optionally also bind `transfer_hash` / `xchain_hash_id` when the approve path has it. 2. Pass `src_chain_id` from `sync_deposit_status_after_approval` into that helper. Do not `LIMIT 1` across chains. Fail closed if zero rows match; do not fall through to a different chain’s row. 3. Tests with two pending `evm_deposits` sharing a nonce on different EVM `src_v2_chain_id` values: dest-approve for chain A must mark A processed and leave B pending. Founder-required operator dest-approve / deposit status. No community autoland. Do not add `ready`. ## Impact (today vs hypothetical) Funds and operator correctness at risk **today** on any live operator that dest-approves EVM-origin withdrawals via V2 poll-and-approve / enumeration and then syncs DB status through this helper. Multi-EVM is the production topology (BSC, opBNB, additional EVM peers). Independent bridges assign overlapping nonces. The first matching `pending` row wins. Wrong row marked `processed`: - Honest deposit on chain B with the same nonce is skipped by later DB-driven dest-approve (`process_evm_deposit` / pending queries that skip non-`pending`). User lock on B never gets dest mint/unlock through the DB path. - The deposit that was just dest-approved on chain A stays `pending`. Legacy DB-driven code can try to dest-approve it again, or `/status` `pending_deposits` stays wrong for the real transfer and lies for the stolen row. Cross-family variant of the same bug: `sync_deposit_status_after_approval` tries the nonce-only EVM lookup **first** and returns on any hit. A Terra-source dest-approve with nonce N can mark a pending BSC row with nonce N `processed` and never reach `find_terra_deposit_id_by_nonce`. Binding EVM lookup to `src_v2_chain_id` stops that fall-through. This is not permissionless theft of unrelated vault inventory by a stranger with no deposit. It is operator state corruption at dest-approve time: the wrong lock is treated as done, the right lock is left pending or skipped. Severity is high because dest mint/unlock is the payout and `processed` is the gate that stops a second dest-approve. Rate limits and dest cancel windows do not restore the skipped row. Hypothetical-only if every pending-by-nonce lookup already required `src_v2_chain_id` (they do not: only the cosmos helper does) or if the operator ingested a single EVM source so nonces cannot collide (not true once two EVM watchers insert pending rows). Sticky until the predicate and caller pass the source id and tests prove colliding nonces cannot cross-mark. Do not publish a mainnet two-chain same-nonce dest-approve sequence. ### Cosmos helper already scoped; EVM helper is not ```text find_evm_deposit_id_by_src_v2_chain_nonce_for_cosmos WHERE src_v2_chain_id = $1 AND nonce = $2 AND dest_chain_type = 'cosmos' AND status = 'pending' find_evm_deposit_id_by_nonce_for_evm WHERE nonce = $1 AND status = 'pending' LIMIT 1 ``` The EVM helper’s docstring contrasts dest type, not source chain. `src_v2_chain_id` is a column on insert (`insert_evm_deposit`) and on pending SELECTs. It is unused here. ### Caller drops the source id it already has `sync_deposit_status_after_approval(src_chain_id, nonce)` is called from: - Enumeration dest-approve success (`submit_withdraw_approve` then sync). - `poll_and_approve` dest-approve success (WithdrawSubmit events). Both have `src_chain_id` and `xchain_hash_id` in scope. Only `nonce` reaches SQL. On `Ok(Some(deposit_id))` the writer sets `processed` and returns, so a Terra fallback never runs. ### Schema does not treat nonce as global `UNIQUE (chain_id, tx_hash, log_index)`. Index `idx_evm_deposits_chain_nonce` is `(chain_id, nonce)`. Two pending rows with the same nonce on different `chain_id` / `src_v2_chain_id` are valid. `LIMIT 1` is undefined which id wins. ## Invariants - INV-OP-N1 (new): A pending `evm_deposits` row may be marked `processed` from V2 dest-approve sync only if `src_v2_chain_id` matches the approved source chain (4-byte V2 id). Nonce alone is not an identity. - INV-OP-N2 (new): Two pending EVM deposits with the same nonce and different `src_v2_chain_id` must not affect each other’s status. Dest-approve for A leaves B `pending`. - INV-OP-N3 (new): Zero matching rows → no status write (log and continue). Do not pick another chain’s row. Do not fail dest-approve that already landed on-chain solely because DB sync missed; dest-approve is already submitted — sync is bookkeeping, not a second approve. - INV-OP-N4 (new): If `transfer_hash` / `xchain_hash_id` is used as a second key, a hash mismatch must not update a different pending row with the same nonce. - Do not weaken dest `WithdrawApprove` verification, hash words, `finality_blocks`, or user `withdrawSubmit`. Do not drop the cosmos helper’s `src_v2_chain_id` bind. Do not make nonce globally unique in a way that rejects honest multi-EVM inserts. ## Constraints / guardrails - Prefer adding `src_v2_chain_id: &[u8; 4]` to `find_evm_deposit_id_by_nonce_for_evm` (or replace it with a clearly named helper) and passing `src_chain_id` from `sync_deposit_status_after_approval`. Keep “any dest_chain_type” unless a dest-type filter is proven safe for every V2 path that calls this sync. - Optional tighter bind: `AND transfer_hash = $n` when the approve path has `xchain_hash_id` and the row stores `transfer_hash`. Do not require hash if older rows have NULL; then source+nonce must still be unique enough (fail closed if two pending rows share source+nonce). - Prefer `src_v2_chain_id` (V2 4-byte) over native `chain_id` BIGINT so BSC / opBNB / other EVM peers match the cosmos helper and the bytes the writer already holds. If some rows have NULL `src_v2_chain_id`, fail closed for those rows on this sync path rather than matching on nonce only. - Do not `ORDER BY id` + `LIMIT 1` as a “fix”. That still picks the wrong chain. - Do not change Solidity / CosmWasm / Solana programs. Do not retune reorg inclusion (#183) or Terra confirmation depth (#182) here. - Founder-required operator / dest approve / deposit identity. No community autoland. Do not add `ready`. No public mainnet collision recipe. ## Relevant files | Path | Why | | --- | --- | | `packages/operator/src/db/mod.rs` | `find_evm_deposit_id_by_nonce_for_evm` (nonce-only); cosmos sibling already scoped; `update_evm_deposit_status` | | `packages/operator/src/writers/evm.rs` | `sync_deposit_status_after_approval` has `src_chain_id` and ignores it; two call sites after dest approve | | `packages/operator/src/writers/terra.rs` | Cosmos helper call site — pattern to mirror, do not regress | | `packages/operator/migrations/001_initial.sql` | `(chain_id, nonce)` index; nonce not globally unique | | Operator DB tests | Missing colliding-nonce fixture | ## Recommended direction 1. Change the EVM helper to `WHERE src_v2_chain_id = $1 AND nonce = $2 AND status = 'pending'` (plus optional `transfer_hash`). Return `None` unless exactly one row matches. If two+ match, do not `LIMIT 1`; log and skip the status write (or match hash). 2. Thread `src_chain_id` from `sync_deposit_status_after_approval` into the helper. Keep Terra fallback only when the EVM lookup returns `None` **and** `src_chain_id` is the Terra V2 id (existing Terra gate). 3. Unit test: insert two pending EVM deposits, same nonce, distinct `src_v2_chain_id` (and distinct `transfer_hash`). Sync for chain A → only A is `processed`. Repeat for B. 4. Unit test: Terra `src_chain_id` + colliding EVM pending nonce → EVM row stays `pending`; Terra path may still run. 5. Honest path: single pending row matching source+nonce still becomes `processed` after dest-approve sync. ## Acceptance criteria - AC1. `find_evm_deposit_id_by_nonce_for_evm` (or replacement) requires `src_v2_chain_id`. Query must not be nonce + `pending` only. - AC2. Two pending deposits, same nonce, different `src_v2_chain_id`: dest-approve sync for A marks A `processed` and leaves B `pending`. - AC3. Dest-approve whose `src_chain_id` matches no pending EVM row does not mark some other chain’s pending nonce `processed`. - AC4. Terra-source dest-approve with nonce equal to a pending EVM deposit does not mark that EVM row `processed`. - AC5. Cosmos helper `find_evm_deposit_id_by_src_v2_chain_nonce_for_cosmos` stays source-scoped. No contract change. - AC6. Existing operator tests stay green. New tests cover AC2–AC4 without a live BSC/opBNB node. ## Test plan (functional paths) | # | Path | Expect | | --- | --- | --- | | T1 | One pending EVM row; dest-approve sync with matching `src_v2_chain_id` + nonce | That id `processed` | | T2 | Two pending rows, same nonce, chain A and chain B; sync A | A `processed`, B `pending` | | T3 | Same fixture; sync B | B `processed`, A still `pending` (or already processed from T2 in a separate test) | | T4 | Sync with source C (no row) and nonce that exists on A | A stays `pending`; no status write | | T5 | Matching source+nonce, `status` already `approved` / `processed` | Helper returns `None`; no overwrite of a third pending row | | T6 | Optional hash bind: same source+nonce, wrong `transfer_hash` | No status write | | T7 | Cosmos helper EVM→Terra still matches `src_v2_chain_id` + cosmos dest | Unchanged | ## Test plan (attack, hack, and abuse) Non-exploitative. Operator unit tests / local DB fixtures only. Do not use these as a mainnet recipe. | # | Vector | Expect | | --- | --- | --- | | A1 | Two EVM sources, identical nonce, both `pending`; dest-approve A | Only A processed | | A2 | Repeat A1 with reversed insert order (so old `LIMIT 1` would flip) | Still only the matching source | | A3 | Terra-source dest-approve, EVM pending same nonce | EVM row not processed | | A4 | NULL `src_v2_chain_id` on a pending row | Fail closed for this sync; do not match on nonce only | | A5 | Ambiguous two pending rows same source+nonce (data bug) | No `LIMIT 1` pick; no silent wrong `processed` | ## Verification criteria - Operator package tests: T1–T7 and A1–A5. Grep that `find_evm_deposit_id_by_nonce_for_evm` (or replacement) binds `src_v2_chain_id` in SQL, not only in the Rust signature. - Grep that `sync_deposit_status_after_approval` passes `src_chain_id` into the helper. - Grep absence of `WHERE nonce = $1 AND status = 'pending'` without a chain or hash bind on the EVM deposit sync path. - Do not verify by dest-approving colliding mainnet deposits or by inspecting a live operator DB. ## Out of scope - [#183](https://git.cl8y.com/code/cl8y-bridge-monorepo/issues/183) reorg / `block_hash` inclusion before dest approve. - [#182](https://git.cl8y.com/code/cl8y-bridge-monorepo/issues/182) Terra LCD confirmation depth. - [#115](https://git.cl8y.com/code/cl8y-bridge-monorepo/issues/115) RPC quorum / `FINALITY_BLOCKS` defaults. - Making Terra `find_terra_deposit_id_by_nonce` multi-chain (single Terra source; only in scope insofar as the EVM-first fall-through in AC4). - Solidity `getDeposit` layout / hash words. - Live operator redeploy (ops). ## First-pass model recommendation Recommendation: grok-high Rationale: Security class and founder-required operator dest-approve / deposit identity (wallet / bridge funds). Composer is disallowed (High/security; not a low-risk first pass). Even though the production edit is likely `db/mod.rs` plus `writers/evm.rs` plus tests, file count does not establish safety: a wrong `processed` write skips dest mint for the real lock or leaves it pending for a second dest-approve. Verify with two-chain colliding-nonce fixtures, not a live multi-EVM dest-approve.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-bridge-monorepo#184
No description provided.