Skip to content

Fix double-payouts for maintenance pools and overdue expiry race conditions - #473

Open
Ultra-Tech-code wants to merge 2 commits into
MergeFi:mainfrom
Ultra-Tech-code:fix-issues-458-460
Open

Ultra-Tech-code wants to merge 2 commits into
MergeFi:mainfrom
Ultra-Tech-code:fix-issues-458-460

Conversation

@Ultra-Tech-code

Copy link
Copy Markdown
Contributor

Description:

This PR resolves a couple of critical race conditions and validation bugs when expiring bounties and paying out maintenance pool rewards.

Fixes

1. Atomic Overdue Expiry (#460)

  • Problem: BountiesService.expireOverdue() was reading an overdue list into memory and looping through per-row save()s. If a bounty transitioned (e.g., IN_REVIEW or PAID) during this loop, it would get incorrectly overwritten to EXPIRED using the stale in-memory copy.
  • Solution: Replaced the loop with an atomic UPDATE query via the query builder. This guarantees that status changes only apply to records that are still eligible at the exact moment of execution, completely avoiding the read-write gap.

2. Guard against double-payouts by pool and issue (#458)

  • Problem: assignReward incorrectly keyed its guard on (pool, recipient) rather than (pool, issue). This allowed paying out the same issue multiple times to different recipients, while unfairly blocking legitimate payouts when a maintainer completed two distinct issues.
  • Solution:
    • Added a maintenanceIssue relation and maintenanceIssueId column to the Payment entity.
    • Added a unique index on (escrowId, maintenanceIssueId).
    • Updated MaintenancePoolService.assignReward() to check the payout guard against issueId instead of recipientId.
    • Updated EscrowService.poolWithdraw() to correctly stamp the resulting payment with the corresponding maintenanceIssueId.
    • Added specs to guarantee that a single issue cannot be paid twice (even to different recipients) and that a single recipient can be paid sequentially for different issues.

Closes #460
Closes #458

Replace read-then-save loop with an atomic bulk update so concurrently-advanced bounties are not overwritten to EXPIRED.
- Adds maintenanceIssueId to Payment with a unique index alongside escrowId
- Updates MaintenancePoolService.assignReward to check payouts by issueId instead of recipientId
- Passes issueId through EscrowService.poolWithdraw
@vercel

vercel Bot commented Sep 29, 2026

Copy link
Copy Markdown

@Ultra-Tech-code is attempting to deploy a commit to the chonilius' projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Sep 29, 2026

Copy link
Copy Markdown

@Ultra-Tech-code Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

This branch has not been deployed

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

Labels

None yet

Projects

None yet

1 participant