mirror of
https://github.com/luxfi/dex.git
synced 2026-09-24 00:26:31 +00:00
A TxDeposit MINTS ledger balance, but its authorization was the DEPOSITOR'S OWN signature (verifyTxSignature required signer == the body's beneficiary), and handleDeposit exposed it on the same public ZAP route as dex_place/dex_submit. So any authenticated principal could self-sign a deposit and mint unlimited unbacked balance, then withdraw it (redteam_unbacked_deposit_test proved 500B minted). OPTION B (gate to the trusted bridge authority) — chosen over Option A (route all deposits through the atomic import) because: (1) the trustless atomic import (TxImport, atomic.go) is only wired in production (runtime + shared memory) and credits a DIFFERENT account axis (crossChainAccount(C-address)) than the DEX tx-auth account (Account16) — routing all deposits through it would require wiring shared memory + reconciling account models across 17 test files; (2) tx.go:47 already documents TxDeposit as the bridge/proxy-credit path — this implements that intent correctly (the bug was the missing authority check); (3) the trustless atomic import remains UNCHANGED and available for cross-chain swaps. Both backing mechanisms now coexist: trustless import for swaps, authority-gated deposit for bridge-custodied funds. The fix: - VM gains depositAuthority (a CONSENSUS config param, vmConfig.DepositAuthority hex, decoded at Initialize). ZERO => no authority => EVERY TxDeposit rejected fail-closed (value then enters only via the backed atomic import). - authorizeTx (the authoritative consensus gate): a TxDeposit is accepted ONLY when the recovered signer == depositAuthority; else rejected (no mint, no nonce burn). - verifyTxSignature: a deposit no longer requires signer==beneficiary (the signer is the authority; the beneficiary is bound via the signed digest). Withdraw is UNCHANGED — still signer==beneficiary (a user withdraws their own funds). - submitTx: boundary pre-screen rejects a non-authority deposit before the mempool. Backing invariant enforced: Σ(ledger credits via TxDeposit) ≤ Σ(bridge-authorized deposits); combined with the import's Σ(credits) ≤ Σ(consumed C->D objects), NO path credits the ledger without backing. The authority gate also HARDENS RED #4: a stranded/self-signed deposit that lands in a later block is rejected, so it cannot mint; withdraw is untouched (debits own available, clamped — no burn). TDD: TestRedteam_UnbackedSelfSignedDepositMints now PASSES (self-signed deposit rejected at boundary + consensus; minted 0, withdrew 0). New TestBackedAuthoritySignedDepositCredits proves the legitimate authority-signed deposit credits + withdraws correctly. Test funding migrated to an authority-signed helper (fundAcct/fundTx); auth_test nonce expectations updated (a funded account's first own tx is nonce 0 — funding no longer consumes the user's nonce). ALL suites green (go test ./... -count=1), go vet clean; the F1-F5 cross-arch execRoots + ledgers still match byte-for-byte across arm64/amd64. KNOWN FOLLOW-UPS (tracked): (a) chains/dexvm + precompile/dex are separate modules that also encode the ZAP frame — they need the same exact-integer wire bump to interoperate; (b) F7 — retract the inflated 12.76B/9.13B/5.60B "ord/s" GPU benchmark numbers in ~/work/lux/papers (they measure all-cross synthetic fills/s ~71-85x inflated; the paper's own text already caps a single GPU below 10^9 fills/s). Co-authored-by: Hanzo Dev <[email protected]>