Skip to content

[CRITICAL] Payout rounding leaves dust permanently trapped in the contract — sum of payouts never equals the pool #169

Description

@grantfox-oss

Summary

prediction_market/src/lib.rs claim computes each winner's payout as:

let payout = (entry.net * total_pool) / winning_side;

Each payout uses independent integer division. The sum of all payouts is Σ floor(net_i * P / W) ≤ P, with the deficit P - Σ payout_i (rounding dust) never distributed and never accounted for. It accumulates in the contract's XLM balance permanently.

Impact

  • Stranded funds: the dust is not added to AccumulatedFees, not refunded, and not tracked anywhere. It is permanently unreachable.
  • Invariant violation: contract_balance == AccumulatedFees + Σ unclaimed_payouts + Σ refundable_gross is broken by the dust.
  • Compounding: every resolved market that has multiple winners leaves dust behind.
  • Audit confusion: the discrepancy grows over time and is invisible to on-chain accounting.

Why it's hard

  • Distributing the remainder requires knowing the full set of winners at claim time, but claims are per-user and asynchronous.
  • Adding remainder to fees requires a post-claim reconciliation pass with no trigger.
  • Pre-computing exact payouts at resolve time requires iterating all winners (unbounded gas risk).

Fix

  • Implement a settlement model: either (a) compute and store exact per-winner payouts at resolve_market time with a bounded winner iteration, or (b) sweep the remainder to AccumulatedFees via a finalization function callable only after all claims, or (c) round up the last claimer's payout (requires on-chain tracking of claim order).

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSThird CampaignCampaign: Third CampaignaccountingAccounting / fee logiccriticalCritical severity - funds at riskprediction-marketPrediction market contract

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions