Skip to content

[ANCHOR-1329]: Fix refund cap check for repeated refund ids in notify_refund_sent and notify_refund_pending - #2097

Open
ceciliaromao wants to merge 7 commits into
developfrom
fix/anchor-1329
Open

ceciliaromao wants to merge 7 commits into
developfrom
fix/anchor-1329

Conversation

@ceciliaromao

Copy link
Copy Markdown
Collaborator

Description

  • notify_refund_sent (SEP-6 and SEP-24, pending_anchor) now computes its cap and next status over the refund list as it will be stored: the other stored refunds plus the request, with the request's id replacing any stored refund of the same id. Amount and fee are summed at the asset's significant_decimals.
  • notify_refund_pending (SEP-6 and SEP-24 deposits) now replaces a repeated refund.id instead of appending it, and applies the same cap arithmetic.
  • notify_refund_sent for SEP-31 now rejects a second refund in every supported status with the existing "Multiple refunds aren't supported" error, not only in pending_receiver.
  • Two existing tests in NotifyRefundPendingHandlerTest (test_handle_sep24_ok_second_refund, test_handle_sep6_ok_second_refund) asserted the old append behavior (the same id stored twice). They now store a different id for the first refund; the expectations are otherwise unchanged.

Context

  • HackerOne 4028479
  • HackerOne 4141638 (duplicate)
  • The cap check added the request to the stored amount_refunded, while persistence replaced the refund with the same id. A replayed id was therefore checked as x + x but stored as x. The effects were a false flip to refunded, false rejection of a legitimate correction (for example 60 to 70 on an amount_in of 100), and, in notify_refund_pending, a duplicated payment with a doubled amount_refunded.

Testing

  • ./gradlew test
  • Unit: ./gradlew :platform:test --tests "org.stellar.anchor.platform.rpc.RefundIdReplayTest" (new, 142 tests; SEP-6 cases run over deposit, withdrawal, deposit-exchange and withdrawal-exchange)
  • Unit: ./gradlew :platform:test --tests "org.stellar.anchor.platform.rpc.*" (590 tests, 0 failed)
  • Covers: replay of a stored id (including 25 repeated calls), replay with a fee, correction up and over amount_in, new id at and one above the bound, mixed stored fees, 7-decimal amounts and fees, a stored list holding the same id twice, notify_refund_pending replacing a repeated id, the pending / sent / pending sequence, rejected calls leaving the transaction unchanged, and SEP-31 in pending_stellar and pending_receiver.
  • Manual: replay the reporters' calls against a funded transaction. Send notify_refund_sent with the same refund.id and amount repeatedly, and notify_refund_pending twice with the same id (amount 0.4, fee 0.01 on amount_in 1). amount_refunded and the payments list should match one refund.

Documentation

  • N/A, no documentation change. The behavior of repeated ids is clarified and no new feature is added.

Known limitations

  • Concurrent calls with the same id are not covered by this change (tracked separately in HackerOne 3582304).
  • In SEP-31, a second refund is now rejected in pending_stellar too. No RPC route reaches that state with a stored refund, so this only matters for transactions changed through PATCH /transactions.

@ceciliaromao ceciliaromao self-assigned this Nov 6, 2026
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