feat(deposit-address-service): execute v3 refund withdrawals - #3709
Conversation
6427a95 to
7048066
Compare
7048066 to
427658f
Compare
427658f to
fb4601d
Compare
fb4601d to
3348163
Compare
3348163 to
114b904
Compare
114b904 to
c54ec33
Compare
|
@droplet-rl Review changes since last approval. No change? |
|
Confirmed — no change. The commit patch is byte-identical (64,692 bytes) and the message unchanged across all three force-pushes since your approval at Only tree delta vs the approved commit is Worth flagging though: it's now CONFLICTING. The base branch gained |
The refund path for a mis_route or intent_refund, and for a correct_transfer the execute endpoint rejected as below the minimum — replacing the placeholder throws at the lines they sat on, so the deposit lock is held across both actions via processUnderLock's existing try/finally. The parent's exclusion routing is kept: anything that is not a correct_transfer diverts to the withdraw, so intent_refund takes the same second hop out to the committed refund address as a mis_route. Withdrawals are EVM-only, stricter than the deposit path, and need the message's withdraw leaf materials; canonicality-then-balance and the broadcast/reconciliation plumbing are reused unchanged, with operation: "withdraw" on the pending record. A sign-withdraw 422 is terminal on the HTTP status alone, recorded as withdraw_failed (code now optional — the client discards the API's discriminator) and ACKed; everything else NACKs. The refund deducts gas (deductGasFromRefund: true), deliberately unlike v1. withdraw_executed is recorded but not yet published; lifecycle publishing follows before execution is enabled. Gated by ENABLE_V3_WITHDRAWALS, the same variable the polling bot reads, defaulting off. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c54ec33 to
d9481bf
Compare
|
Approved |
Part of #3663 — PR 5 of the standalone deposit-address service. Stacked on #3701.
Executes the v3 refund withdrawal: the path for a
mis_route, and for acorrect_transferthe execute endpoint rejected asAMOUNT_BELOW_MINIMUM. Replaces PR 4's two placeholder throws at the lines they sat on, so the deposit lock is held across both actions viaprocessUnderLock's existingtry/finally.WithdrawRouteNotImplementedErrordisappears with them, taking the last identifier carrying the removedroutevocabulary.Review focus: one lock held across both actions; terminal 422 handling.
What is genuinely new
executeWithdrawindepositHandler.ts, ported guard-for-guard frominitiateWithdrawV3per the issue's parity matrix: theENABLE_V3_WITHDRAWALSgate (same env var the polling bot reads, NACK while off), EVM-only namespaces (stricter than the deposit path —assertSupportedNamespaceallowstronon TVM chains, so it could not be reused), the withdraw leaf materials check, and a smaller response assertion (assertValidWithdrawResponse: signedchainIdagainst the refund chainerc20Transfer.chainId, and the now+60s signature deadline —assertValidExecuteResponsedeliberately does not carry over)._getSignedWithdrawV3does (isHttpError(err) && err.status === 422): persistwithdraw_failed, ACK. Everything else NACKs. No client change;_postOrThrowdiscards the API's error code, sowithdraw_failed.codebecomesoptional(...)and is unset — every existing PR 3 state test passes unchanged.deductGasFromRefund: true, deliberately unlike v1's full-amount refund — not to be unified in the v1 PR.Reused unchanged
The lock, both state reads,
assertSupportedOriginChain(already runs onerc20Transfer.chainIdbefore routing), canonicality-then-balance in that order and for the same reason,onBroadcast+maxTries, the pending-write retry, andresolvePendingTransaction(whoseoperation: "withdraw"mapping already existed).broadcast()is parameterised over{operation, to, data, value, message, mrkdwn}rather than duplicated. One adjustment there: a confirmed withdraw is not expected to carry theMetadataEmittedprovenance event, so the missing-metadata warning is now gated to deposits.Not in this PR
withdraw_executedis recorded but not published — lifecycle publishing and its recovery are PR 6, which lands before PR 7 enables execution anywhere.Verification
yarn tsc --build --forceclean;yarn lintclean.TransactionClient(163 on the base branch; +27 here).deductGasFromRefund, the signed-chainId check, theoperationlabel, 422-only terminal classification, the code-gated below-minimum fallthrough, the lock held across both actions (the fake API records the lock token it observed inside each call), the withdraw gate, the leafkindfilter, EVM-only strictness, and canonicality-before-balance ordering — each failed exactly the expected tests, then passed on revert.🤖 Generated with Claude Code