Repository navigation
Wait for 0x Gasless swaps to mine before saving - #513
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
peachbits
left a comment
There was a problem hiding this comment.
0x's getStatus reference says a submitted trade can list several transactions, of which one mines, and that succeeded (in a block) and confirmed (three confirmations) return only the mined one, so waiting for those two saves the hash that mines. Locally tsc and eslint are clean and the full suite passes (276). With the old exit test (any non-pending status that lists one transaction) put back, 4 of the 5 new tests fail, the approve test among them.
Blocking: one failed status request still ends a swap that 0x already has, and two of the loop's exits have no test (inline).
Non-blocking: the body says gasless rows are saved without lastSeenTime, so the one-day drop never fires for them. accb's addTransaction stamps lastSeenTime on every unconfirmed row that saveTx adds. The drop wouldn't unblock sends anyway: getUnconfirmedTxs returns every row at blockHeight 0, dropped or not, and makeSpend throws PendingFundsError for any of them. Wallets with a stuck row still need a cleanup, and marking the row dropped won't be enough.
|
Both blocking items are fixed in 4c7f0bf (inline replies). The PR body no longer claims gasless rows lack |
peachbits
left a comment
There was a problem hiding this comment.
All four points from the last review are fixed in 4c7f0bf. Checked locally:
- A failed status request no longer ends the swap. The retry test fails with the
tryremoved, andapprove()now saves under the mined hash after one 503 or one dropped request. A status request that always fails stops at the deadline (23 requests, the wait doubling to 16 s), andapprove()then rejects with the timeout error and saves nothing. Afailedanswer after failed requests still throws its reason at once. - The
confirmedand several-hashes tests fail without their branches, the hash test fails with the check removed or loosened, and both log lines uselog.warn. - The stuck-row paragraph in the PR body now matches accb.
tscand eslint are clean, and the full suite passes (280).
Non-blocking: autosquash drops the fixup's message, so the final commit keeps its 10-17 body, which names the failed throw, the five-minute bound and the status log but not the retry or the hash check. Your fixup body already explains both; an amend! that adds them (or a reword at land) keeps that in history.
4c7f0bf to
b8191d6
Compare
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
The status poll exited on 'submitted' with one transaction and saved that hash. The relayer can replace a submitted transaction, so the saved row never confirmed and the wallet blocked later sends as pending. Poll until 'succeeded' or 'confirmed' and save the hash 0x reports as mined. A mined status must carry exactly one well-formed 32-byte hash; several hashes or a malformed one throw instead of saving a guess. The loop also spun forever on a 'failed' status with no transactions. It now throws the failure reason, bounds the wait at five minutes, and logs each status change at warn. A failed status request no longer ends the wait: 0x may still mine the signed trade, so the poll retries with a doubling delay (capped at 16 seconds) until the deadline.
b8191d6 to
30f8873
Compare
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
none
Description
Asana task
0x Gasless saved the swap under whatever hash the status endpoint listed first. The old poll loop (
status === 'pending' || transactions.length !== 1) exited onsubmittedwith one hash. Per the 0x getStatus docs,submittedcan list several transactions and only one of them mines. If the relayer replaced the hash, the wallet kept a row under a hash that never mines. That row stays atblockHeight === 0, andEthereumEngine.makeSpendthrowsPendingFundsErroron every later send. The same loop also spun forever onfailed, which can report zero transactions.Changes in
waitForMinedTxid:pendingandsubmitted. It returns only onsucceededorconfirmed, the statuses where 0x reports the mined transaction.failedwith the 0x reason.warnand lower levels never reach a log export.The swap's
orderId,txidand saved transaction now all use the mined hash.Added wait: one poll cycle (500 ms) plus block inclusion. On Arc the first poll already returned
succeeded, about 1.1 s after the swap started. On Ethereum mainnet expect about one block (~12 s). The existing swap-processing state covers this wait. The gui needs no change.Tests: unit tests for the same-hash, replaced-hash,
confirmed, failed, timeout, failed-status-request, malformed-hash and several-transactions cases, plus an approve() test that the saved transaction uses the mined hash. The approve test fails against the old loop, which saves the submitted hash.Real swap on the iOS sim at the current head: 0.4525 EURC to 0.484 USDC on Arc via 0x Gasless, through to the success scene. The plugin logged
0x gasless status: submitted [0x6e6ed4ee...7e40], then0x gasless status: succeededwith the same hash. Core saved that hash as both the txid and the orderId. On chain that transaction mined in block 30944708 with status 1, sent by the 0x relayer. The earlier swap on the first commit (0.445 EURC, block 26367212) behaved the same way. Neither swap listed a replaced hash; the unit test covers that case.Timeout error on the sim (hack-forced, reverted, never committed): I stubbed the 0x submit so no funds moved, pinned the status to
submitted, and cut the timeout to 5 s. The swap scene shows the error as an alert ("Swap timed out after 5 seconds waiting for 0x to mine it (last status: submitted [...]). It may still complete."), and the slider re-arms.Existing stuck rows are not cleared by this change. accb's
addTransactionstampslastSeenTimeon these rows, and the one-day drop rule can mark them dropped. That does not unblock sends:getUnconfirmedTxsreturns every row atblockHeight0, dropped or not, andmakeSpendthrowsPendingFundsErrorfor any of them. Wallets that already have a stuck row need a separate cleanup that removes it.Note
Medium Risk
Changes when and which hash is written to the wallet after gasless swaps; incorrect behavior previously caused stuck pending txs, but approve now blocks longer until mining or timeout.
Overview
Fixes 0x Gasless swaps that were persisted under a submitted transaction hash the relayer could replace, leaving a never-mining pending row that blocked later sends.
After submit, the plugin now uses
waitForMinedTxidto poll status (500 ms interval, 5 minute cap) until 0x reportssucceededorconfirmed, then setsorderId,txid, and the saved wallet transaction to that mined hash.failedsurfaces the API reason; timeouts error with a message that the swap may still complete. Status transitions and hashes are logged on change.Adds unit tests for replaced-hash, failure, timeout, and
approve()saving the mined hash.Reviewed by Cursor Bugbot for commit c51378c. Bugbot is set up for automated code reviews on this repo. Configure here.
Test evidence
c51378cWait for 0x Gasless swaps to mine before saving
2026-10-17
🪓 stubbed the 0x submit (no funds moved), pinned the status to submitted, and cut the timeout to 5 s
1. arc eurc usdc 0x gasless quote
2. swap success
3. 🪓 timeout error
4c7f0bffixup! Wait for 0x Gasless swaps to mine before saving
2026-11-13
11. gasless quote eurc to usdc
0x Gasless quote, 0.4525 EURC to 0.484 USDC on Arc, at fixup 4c7f0bf
12. gasless swap success
Success scene after the poll saw succeeded; saved txid 0x6e6ed4ee...7e40 mined in block 30944708