Skip to content

[CRITICAL] — Idempotent createDonation path returns a stale FAILED / PENDING row without re-verifying on-chain status, permanently masking recovered donations #2

Description

@ibrahimmosouf-png

Severity: Critical
Type: Bug
Scope: Donations, Stellar
Labels: bug, help wanted, Official Campaign

Description

DonationsService.createDonation (src/donations/donations.service.ts, lines ~46–72) short-circuits when prisma.donation.findUnique({ where: { txHash } }) returns a row, returning the previously stored DonationResponseDto verbatim. There is no live re-check against Horizon or the Soroban RPC, even when the stored status is PENDING or FAILED.

Concrete impact:

  • If verifyDonationOnChain polled during a Stellar RPC outage and stored FAILED, but the transaction actually succeeded on-chain, every subsequent POST with the same txHash returns the stale FAILED row. The user's UI shows the donation was rejected even though it is in the ledger.
  • If a future flow promotes the row to REFUNDED and the user retries, the idempotent path returns the pre-refund CONFIRMED payload.
  • Clients cannot distinguish "idempotent replay" from "actual recovery", so the only remediation today is a manual database fix.

Recommendation

  • On the idempotent branch, if donation.status is PENDING or FAILED, re-run stellarTxs.verifyDonationTransaction and update the row before returning.
  • Add an idempotency window (e.g. stop re-polling after 30 seconds) to absorb legitimate retry storms from the wallet client instead of triggering one Horizon call per retry.
  • Include a recovered: boolean flag in the response so consumers can tell a fresh confirmation apart from a cached one.

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignAudit finding under the Official CampaignbugSomething isn't workinghelp wantedExtra attention is needed

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions