Skip to content

fix(polymarket): a withdrawal that may have moved money is never signed twice - #174

Merged
VickyXAI merged 4 commits into
mainfrom
fix/withdraw-idempotency
Oct 8, 2026
Merged

VickyXAI merged 4 commits into
mainfrom
fix/withdraw-idempotency

Conversation

@VickyXAI

@VickyXAI VickyXAI commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • A retry that resolves the earlier withdrawal ends the call. Settled, failed or expired: the outcome is reported and nothing new is signed. Before this, the guard cleared itself and the same confirm:true call signed a second transfer.
  • EOA (sigType 0) withdrawals have no deadline. The transfer is signed locally, and its hash, nonce and signed bytes are persisted before the broadcast. Only a receipt resolves it. Until then, a retry re-broadcasts the same bytes, so it can execute at most once.
    • The old 300s expiry is gone. So is any reading of an advanced nonce plus an unknown hash as "dropped".
    • The guard is released before a receipt only on an outright node rejection that the RPC doesn't know. "nonce too low" and "already known" keep it.
  • The relayer withdrawal is recorded before submit, not only in the catch, so a process killed mid-POST still leaves the guard. A definite 4xx still releases it.
  • HTTP 408 is now an unknown outcome in isDefiniteRejection, which is shared by the CLOB submit, the relayer batch and fund.
  • Bumps to 0.54.2 with a CHANGELOG entry.

Test plan

  • npm test: 1394/1394
  • npm run build
  • New tests: test/polymarket-withdraw-eoa.test.ts and test/polymarket-definite-rejection.test.ts. The withdraw and relayer tests were updated for the new lifecycle.
  • Mutation-checked: I reverted each of six fixes and confirmed its tests fail.
    1. Resolution continues into a new withdrawal.
    2. EOA time expiry.
    3. "nonce too low" releases the guard.
    4. Fresh signature on retry.
    5. Relayer guard armed only after the submit.
    6. 408 treated as definite.

…ed twice

A retry that resolved the earlier withdrawal now ends the call instead of
signing another. The EOA rail signs locally and persists hash, nonce and
bytes before the broadcast; only a receipt resolves it, and a retry
re-broadcasts the same bytes. No time expiry and no nonce inference for a
plain transaction. The relayer withdrawal is recorded before the submit.
HTTP 408 is an unknown outcome, not a definite rejection.
The public reader and the write RPC can disagree on the pending pool; a
reader nonce could collide with a transaction only the write node has seen
and then wedge the guard behind a 'nonce too low'. prepareTransactionRequest
now fills the nonce through the wallet's own transport, and that nonce is
what gets persisted.
@VickyXAI
VickyXAI merged commit e9b2bd5 into main Oct 8, 2026
3 checks passed
@VickyXAI
VickyXAI deleted the fix/withdraw-idempotency branch October 8, 2026 02:54
VickyXAI added a commit that referenced this pull request Oct 11, 2026
skills/decide teaches POST api.blockrun.ai/v1/decisions (OpenAI Decisions
contract, gpt-6-luna): input + questions, predicate / choice / score, image
input, and a live example response. It is the only rail, free with a key:
gateway #804 took Decisions off x402 (the x402 floor is above what a call
costs) and the paid route was never deployed, so the skill no longer names
one. The legacy /v1/decide shape is still accepted there.

skills/blockrun routing and the marketplace entry point at the new path.
Version 0.54.3: 0.54.2 shipped the withdrawal fix (#174).
VickyXAI added a commit that referenced this pull request Oct 11, 2026
…sions

Release notes for #176 (Solana media polls carry a wallet ownership proof
instead of a payment signature; one payment at video completion) join the
decide skill rewrite: POST api.blockrun.ai/v1/decisions (OpenAI Decisions
contract, gpt-6-luna), the only rail, free with a key. Gateway #804 took
Decisions off x402, so the skill names no paid route. The legacy
/v1/decide shape is still accepted there.

Version 0.54.3: 0.54.2 shipped the withdrawal fix (#174).
VickyXAI added a commit that referenced this pull request Oct 11, 2026
…sions

Release notes for #176 (Solana media polls carry a wallet ownership proof
instead of a payment signature; one payment at video completion) join the
decide skill rewrite: POST api.blockrun.ai/v1/decisions (OpenAI Decisions
contract, gpt-6-luna), the only rail, free with a key. Gateway #804 took
Decisions off x402, so the skill names no paid route. The legacy
/v1/decide shape is still accepted there.

Version 0.54.3: 0.54.2 shipped the withdrawal fix (#174).
VickyXAI added a commit that referenced this pull request Oct 11, 2026
…sions (#172)

Release notes for #176 (Solana media polls carry a wallet ownership proof
instead of a payment signature; one payment at video completion) join the
decide skill rewrite: POST api.blockrun.ai/v1/decisions (OpenAI Decisions
contract, gpt-6-luna), the only rail, free with a key. Gateway #804 took
Decisions off x402, so the skill names no paid route. The legacy
/v1/decide shape is still accepted there.

Version 0.54.3: 0.54.2 shipped the withdrawal fix (#174).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant