You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[CRITICAL] — Idempotent createDonation path returns a stale FAILED / PENDING row without re-verifying on-chain status, permanently masking recovered donations #2
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.
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.
Activity
Just-Bamford commentedon Jun 20, 2026
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
PENDINGorFAILED, 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 arecoveredflag so clients can distinguish refreshed results from cached responses, and add tests covering stale status recovery, retry behavior, and idempotent responses.grantfox-oss commentedon Jun 20, 2026
🦊 GrantFox — @Just-Bamford has been assigned to this issue as part of the Official Campaign campaign!
Next steps:
Closes #2)Good luck! Track your progress on GrantFox.
grantfox-oss commentedon Jun 22, 2026
🎉 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.