Withdrawals are matched by amount+address instead of nonce, and the Ethereum write pins no chain ID

Aperta
#612 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
38/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
typescript

Direzione di ricerca

Start with src/components/modals/WithdrawalModal.tsx, src/hooks/wallet/useWithdraw.ts, and the SDK signingClient.ts initiation path. Compare the sibling hooks that use ETH_CHAIN_ID, then trace how initiation results and withdrawal events are represented. Done means the exact request identity is preserved, the Ethereum write is chain-pinned, stale requests cannot win, and the documented migration state is consistent.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

From the external repository review (10 Sep 2026). Verified, and there is a second defect in the same path the review flags only in passing.

a) Withdrawals are matched by amount + address, not identity

src/components/modals/WithdrawalModal.tsx:117-127:

const matching = withdrawals
    .filter((w: any) => w.base_address?.toLowerCase() === targetBaseAddress.toLowerCase() && w.amount === targetAmount)
    .sort((a: any, b: any) => {
        if (a.status === "signed" && b.status !== "signed") return -1;
        ...
    });
const found = matching[0];

signed sorts ahead of everything regardless of age, and there is no created_at > initiatedAt floor. A stale signed request for the same (address, amount) wins over the one just initiated, and its nonce is what gets handed to the Ethereum write (line 136 → 228).

The root cause is upstream: no nonce is available from initiation. initiateWithdrawal (SDK signingClient.ts:1076-1121) discards everything except result.transactionHash, throwing away the tx events that carry the nonce. The amount+address heuristic is a workaround for that, not a lapse in the modal alone — so fixing this properly requires an SDK change too (see poker-vm#2609, which is about the same discarded result object).

Minor: initiatedAmountRef (declared :64, written :180, reset :89) is never read — dead state.

b) The Ethereum write pins no chain

src/hooks/wallet/useWithdraw.ts:41-51 calls mutate({ address, abi, functionName, args }) with no chainId — wagmi uses whatever chain the wallet happens to be on.

This is inconsistent within the same codebase: useAllowance.ts:17, useWalletBalance.ts:17 and useDecimals.ts:15 all pass chainId: ETH_CHAIN_ID, and Dashboard.tsx:340-342 explicitly switchChain. useWithdraw and WithdrawalModal do neither, and there is no chain assertion anywhere in the withdrawal path.

Compounding it, the app configures networks = [mainnet, base] and the SDK memo for this flow still reads "Initiate USDC withdrawal to Base chain" — leftover from the migration. A user on Base would send a withdrawal at an address that means something different there.

This matters more given poker-vm#2611: the bridge digest has no domain separation, so a signature is not bound to a chain either. Neither layer pins it.

Suggested plan

  1. Return the nonce from initiation. Have the SDK surface the MsgInitiateWithdrawal response / tx events rather than only the hash, then persist that nonce and resume that exact request. This is the fix; everything else is mitigation.
  2. Until then, make the heuristic safe: require created_at >= initiatedAt, and prefer the newest match rather than any signed one. A stale signed request should never outrank a fresh initiation.
  3. Pin the chain explicitly in useWithdraw (chainId: ETH_CHAIN_ID) and assert the connected chain before enabling the button, matching the sibling hooks.
  4. Reconcile against Ethereum: check withdrawNonces[nonce] on the contract before presenting a request as claimable, so a consumed nonce cannot be retried.
  5. Persist modal flow state so closing and reopening resumes rather than restarting.
  6. Fix the stale "Base chain" memo, and delete initiatedAmountRef.

Original review finding 10.

Lingua principale
TypeScript
Stelle
2
Fork
5
Merge medio
23h 23m
PR unite (30g)
97

Preparare l'ambiente

Non abbiamo ancora controllato i file di configurazione di questo progetto. Parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di block52/ui

Tutte le issue di block52/ui

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.