Skip to content

[Backend] handleTokensWithdrawn increments withdrawnAmount before the dedup guard - replay/reset double-counts and corrupts claimable #802

Description

@grantfox-oss

Telegram (ask questions / claim the issue here first): https://t.me/+DOylgFv1jyJlNzM0

Labels: bug, backend, Stellar Wave, database, critical

The withdrawn-amount update runs before the dedup check, so replaying events under-pays recipients.

soroban-event-worker.ts:631-641 computes newWithdrawnAmount = BigInt(stream.withdrawnAmount) + BigInt(amount) and calls tx.stream.update unconditionally. The dedup check at line 643 only guards inserting the StreamEvent row, not the financial field. So when the admin POST /v1/admin/indexer/replay resets the cursor and re-polls the same ledgers, every replay adds amount again even though the StreamEvent row is skipped. withdrawnAmount inflates, claimable shrinks, and the recipient is short-changed. The replay endpoint's Swagger doc even claims it's idempotent.

What the fix has to hold to

  • The stream's withdrawnAmount only changes when the StreamEvent row is newly created, in the same transaction
  • Replay/reset is genuinely idempotent

Done when

  • withdrawnAmount update is idempotent (mutate only on a new StreamEvent insert, same tx)
  • Test processes the same tokens_withdrawn event twice and asserts withdrawnAmount changes once
  • handleStreamCancelled/handleStreamCompleted audited to confirm they stay idempotent
  • Tests + lint pass, CI green

Where to start
backend/src/workers/soroban-event-worker.ts for the ordering fix; indexerService.ts and admin.routes.ts are listed for the replay path and audit. On-chain event schema is out of scope. Medium.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26Stellar WaveIssues in the Stellar wave programbackendBackend related tasksbugSomething isn't workingcriticaldatabasePostgreSQL / Prisma

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions