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.

Activity

  1. added
    bugSomething isn't working
    help wantedExtra attention is needed
    Official CampaignAudit finding under the Official Campaign
    and removed
    Official CampaignAudit finding under the Official Campaign
    on Jun 18, 2026
  2. added
    GrantFox OSSIssue tracked in GrantFox OSS
    Maybe RewardedIssue may be eligible for a GrantFox reward
    Official CampaignAudit finding under the Official Campaign
    on Jun 18, 2026
  3. Just-Bamford commented on Jun 20, 2026

    @Just-Bamford
    Contributor

    Hi maintainer, I'd like to work on this issue. My approach is to improve the idempotent flow by re-validating on-chain state whenever an existing donation is still PENDING or FAILED, updating the stored record before returning the response. I'll also add a bounded re-validation window to prevent excessive Horizon/RPC calls during retry storms, include a recovered flag so clients can distinguish refreshed results from cached responses, and add tests covering stale status recovery, retry behavior, and idempotent responses.

  4. grantfox-oss commented on Jun 20, 2026

    @grantfox-oss

    🦊 GrantFox — @Just-Bamford has been assigned to this issue as part of the Official Campaign campaign!

    Next steps:

    1. Open a Pull Request referencing this issue (e.g., Closes #2)
    2. Your PR will be reviewed by the OrbitChainLabs maintainers

    Good luck! Track your progress on GrantFox.

  5. grantfox-oss commented on Jun 22, 2026

    @grantfox-oss

    🎉 This issue has been marked as completed on GrantFox as part of the Official Campaign campaign!

    @Just-Bamford's PR #34 was approved and merged by @Alqku.

    🏆 @Just-Bamford: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (433 total points). Track your full progress on GrantFox.

    👏 Great work, @Just-Bamford! Keep contributing to OrbitChainLabs.

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 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