Skip to content

fix(#806): guard withdrawnAmount/depositedAmount mutations behind ide…#982

Open
BernardOnuh wants to merge 1 commit into
LabsCrypt:mainfrom
BernardOnuh:fix/806-idempotency-withdrawn-toppedup
Open

fix(#806): guard withdrawnAmount/depositedAmount mutations behind ide…#982
BernardOnuh wants to merge 1 commit into
LabsCrypt:mainfrom
BernardOnuh:fix/806-idempotency-withdrawn-toppedup

Conversation

@BernardOnuh

Copy link
Copy Markdown
Contributor

Description

Fixes a real idempotency bug in the Soroban event worker: handleTokensWithdrawn and handleStreamToppedUp checked for a duplicate StreamEvent after already mutating the Stream row. That meant the duplicate check only protected the audit log, not the actual financial fields — a replayed tokens_withdrawn event would double-count withdrawnAmount.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • 🧪 Test addition or update

Related Issues

Closes #806

Changes Made

  • handleTokensWithdrawn: moved the streamEvent.findUnique duplicate check to the top of the transaction and return early before accumulating withdrawnAmount, so a replayed event can no longer double-increment it.
  • handleStreamToppedUp: same fix applied for consistency — duplicate check now guards the depositedAmount/endTime mutation, not just the StreamEvent upsert.
  • Added two idempotency tests to soroban-event-worker.test.ts:
    • handleTokensWithdrawn processed twice with the same txHash — asserts withdrawnAmount changes exactly once
    • handleStreamToppedUp replayed with the same txHash — asserts depositedAmount/endTime are applied once and not re-applied on replay

Testing

Test Coverage

  • Unit tests added/updated
  • Integration tests added/updated (out of scope per issue — no live RPC integration tests)
  • Manual testing performed

Test Steps

  1. cd backend && npx vitest run tests/soroban-event-worker.test.ts
  2. All 9 tests in the Event processing idempotency suite pass
  3. Verified regression coverage by temporarily reverting the source fix and confirming both new tests fail against the old (buggy) code, then re-confirming they pass with the fix applied

Breaking Changes

None.

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published (N/A)

Additional Notes

Scope limited to backend/tests/soroban-event-worker.test.ts and backend/src/workers/soroban-event-worker.ts per the issue's "Files to touch." Broadcast (sseService.broadcastToStream) behavior on replay was left unchanged, since it wasn't part of the acceptance criteria — worth a follow-up issue if duplicate SSE events to clients become a concern.

…ehind idempotency check

Adds replay tests for handleTokensWithdrawn and handleStreamToppedUp,
and fixes a bug where the duplicate-event check ran after the Stream
mutation instead of before it — a replayed tokens_withdrawn event
would double-count withdrawnAmount.

Closes LabsCrypt#806
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.

[Testing] No idempotency test for the withdrawnAmount/topped-up financial fields when an event is re-processed

1 participant