Repository navigation
Let senders retry a dashboard pay-out whose update or start failed after the wallet broadcast - #1401
Merged
Merged
Conversation
…rt fails Once the wallet has broadcast a SELL's squidRouter transactions the funds sit on the ephemeral account, so a failed /ramp/update or /ramp/start (for example a maintenance-window 503) must not drop the ramp or the hashes. Signing now hands its output to a separate submit step, failures land in AwaitingRetry, and the recovery snapshot carries the unsubmitted output across reloads.
… deadline The API refuses to start a ramp 15 minutes after registration, so the retry panel counts down to expiresAt and, once it passes, gives the ramp ID for a support-led recovery instead of a retry that can only fail.
✅ Deploy Preview for vortexfi canceled.
|
✅ Deploy Preview for vortex-sandbox ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for vrtx-dashboard ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
…ry toast Nothing listens to TRANSFER_FAILED, and the retry panel already shows the error inline.
…amp-post-broadcast-retry # Conflicts: # apps/dashboard/src/components/transfer/OnrampForm.tsx # apps/dashboard/src/components/transfer/TransferForm.tsx # apps/dashboard/src/machines/transfer.actors.ts
Since #1394 the recovery worker starts a non-domestic SELL whose source hash was reported once its start deadline passes, but the expired panel still said the transfer could no longer start and offered a new one, inviting a second payment. A start that succeeded before a reload looked the same.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
On a dashboard pay-out (SELL), the connected wallet broadcasts the squidRouter transactions before the final
/ramp/updatereports their hashes and/ramp/startruns. If either call failed (the maintenance guard's 503, a network error), the machine went straight toFailed. The hashes were never recorded, the tokens sat on the ephemeral account, and recovery meant digging through the localStorage ephemeral backup by hand. #1398 narrows the window with a maintenance check before signing, but the gap between the broadcast and the final update/start remains.What changes
signUserTransactionsnow only drives the wallet and returns the signatures and hashes. A newSubmittingUserTxsstate sends them to/ramp/update. A failed update therefore no longer throws away what the wallet produced.AwaitingRetrystate (SELL only). A failed post-broadcast update or start keeps the ramp, plus any signatures and hashes the API has not accepted yet.RETRYresends only the call that failed: the update if it is still owed, otherwise just the start. It never signs or broadcasts again. BUY behaviour is unchanged: a failed start still goes back toAwaitingPayment, and a failed Monerium permit update still goes toFailed, because nothing has moved yet at that point.SubmittingUserTxs,StartingandAwaitingRetry, and includes the unsubmitted wallet output. On restore, a SELL snapshot resumes inAwaitingRetry. Snapshots that are malformed, or a BUY snapshot that carries wallet output, are discarded as before.expiresAt(the API's 15-minuteRAMP_START_EXPIRATION_TIME_SECONDS). After the deadline, retry is hidden. If/ramp/updatehad already accepted the source hash of a non-AlfredPay pay-out (BRL in practice), the panel says the transfer starts automatically within about 10 minutes (the Start funded sell ramps that the client never started #1394 recovery worker does that) and not to pay again. Otherwise it shows the ramp ID for support. Both views ask the user to check Transactions before sending the payment again, warn against clearing browser data (the ephemeral keys live there), and offer to start a new transfer. The transactions page offers Resume transfer for this state.SubmittingUserTxs, the same as duringSigningUserTxs.Tests
transfer.machine.test.tsuses the realsignUserTransactionswith a countinguserSigningmock. A failed update keeps the hash and resends the identical submission with one broadcast in total. A failed start retries only the start. A restored snapshot resumes at the update it still owes without touching the wallet. Other-ownerRETRYis ignored. The owner-activation blocking test now also coversSubmittingUserTxs.transferActor.test.ts: a SELL snapshot restores intoAwaitingRetryand stays persisted. A corrupt submission is discarded, and so is a BUY snapshot that carries wallet output.transfer-mxn-journey.spec.ts: the hash update gets a 503 from the maintenance guard, then the page reloads and Try again sends an update identical to the failed one, followed by start and navigation. The wallet stub countseth_sendTransactionin sessionStorage, and the test asserts exactly one broadcast across the reload. The same test fails onstagingsource.domain/transfer.test.ts:offrampStartsAfterDeadlinematches the recovery worker's rule (non-domestic output currency and an accepted source hash).bun run test(174 pass),bun typecheck, Biome, and the full dashboard Playwright suite (79 pass).Notes for review
signUserTransactions, anduseActiveMaintenance()runs before the new early return inTransferForm.Failed.AwaitingRetry; the existing BUY retry path has the same gap. After the deadline the panel tells the user to check Transactions before paying again.docs/product-dashboard.md,docs/operations-testing.md, and the dashboard-snapshot note indocs/security-spec/02-signing-keys/ephemeral-accounts.mdare updated. The snapshot now holds user-signed permits and hashes, never ephemeral secrets.