Skip to content

[Bug] reclaim_stalled_dispute doesn't account for fee-on-transfer shortfall #207

Closed

Description

@collinsezedike

Summary

reclaim_stalled_dispute (contracts/tholos/src/lib.rs:831-886) pays assertion.bond to each of the asserter and disputer directly, with no check against how much the contract actually received when those bonds were originally deposited. This is the same class of gap #164 identified for finalize/resolve: a fee-on-transfer token can mean the contract actually holds less than 2 * assertion.bond for a given dispute.

#180 (fixing #164) adds an AssertionEscrow mechanism that finalize and resolve now use to cap payouts against what was actually escrowed for that specific assertion, rather than trusting the nominal bond value. reclaim_stalled_dispute isn't touched by that fix and still pays the raw nominal amount.

Impact: a stalled dispute funded with a fee-on-transfer token either traps on insufficient balance when someone calls reclaim_stalled_dispute (bricking the liveness fallback #166 exists to provide, for exactly the disputes most in need of it), or, if the contract's pooled balance from other open assertions happens to cover the shortfall, pays out more than this specific assertion actually escrowed, at other assertions' expense.

Scope

  • Once fix(tholos): verify balance deltas for incoming token transfers (#164) #180 merges and AssertionEscrow exists, update reclaim_stalled_dispute to cap its two payouts against that same tracking, the same way finalize/resolve now do, instead of paying the raw assertion.bond value to each side.
  • Add a test using a fee-on-transfer token that opens a dispute, lets it stall, and confirms reclaim_stalled_dispute either succeeds with the correct escrowed amounts or fails cleanly, rather than trapping or overpaying.

Proposed approach

Mirror whatever pattern #180 lands for finalize/resolve's escrow-capped payout in reclaim_stalled_dispute's two token_client.transfer calls.

Activity

  1. xtep103 commented on Sep 7, 2026

    @xtep103
    Contributor

    Hi! I'd like to work on this issue.

    I understand the bug as a payout-accounting gap in "reclaim_stalled_dispute": unlike the "finalize" and "resolve" paths fixed by #180, it still transfers the nominal "assertion.bond" to both the asserter and disputer without accounting for the amount the contract actually received when the bonds were deposited.

    My approach would be to:

    • Review the "AssertionEscrow" implementation introduced by fix(tholos): verify balance deltas for incoming token transfers (#164) #180 and the payout logic used by "finalize" and "resolve".
    • Apply the same escrow-capped accounting to both payouts in "reclaim_stalled_dispute".
    • Ensure the function cannot consume pooled funds belonging to other assertions when a fee-on-transfer token results in a lower actual escrow.
    • Add a regression test using a fee-on-transfer token that creates and stalls a dispute, then exercises "reclaim_stalled_dispute".
    • Verify that the reclaim either pays only the amounts actually escrowed for that assertion or fails cleanly without trapping or overpaying.
    • Run the relevant contract tests and existing test suite to ensure the change doesn't introduce regressions.

    I'll keep the implementation consistent with #180 rather than introducing a separate escrow mechanism or duplicating the accounting logic.

  2. Iker2522 commented on Sep 7, 2026

    @Iker2522
    Contributor

    I can refactor reclaim_stalled_dispute in contracts/tholos/src/lib.rs to use the AssertionEscrow tracking established in #180.

    I will mirror the escrow-capped payout pattern applied in finalize/resolve, ensuring both the asserter and disputer payout transfers are capped against the actual balance deposited rather than the nominal assertion.bond. This prevents fee-on-transfer tokens from causing transfer traps or drawing down funds pooled from other assertions.

    I will also add test coverage utilizing a fee-on-transfer token mock to verify that stalled dispute reclaims execute safely and accurately reflect real escrowed amounts. All contract tests will pass cleanly. PR ready in 1 day. Closes #.

  3. JohnArayaE commented on Sep 7, 2026

    @JohnArayaE
    Contributor

    I would like to work on this issue because reclaim_stalled_dispute currently bypasses the escrow-aware accounting being introduced for finalize and resolve, which can either break the liveness fallback on fee-on-transfer tokens or cause one assertion to consume funds belonging to another. Once #180 lands, I can mirror its AssertionEscrow payout-capping pattern in reclaim_stalled_dispute so both parties are paid only from the amount actually escrowed for that assertion rather than the nominal bond value. I can also add a focused fee-on-transfer regression test covering the stalled-dispute path and verify that reclaim either succeeds with the correct tracked amounts or fails cleanly without trapping or overpaying from pooled contract balances.

  4. gloskull commented on Sep 8, 2026

    @gloskull

    Hi, I’d love to work on this issue. I have 4 years of experience across backend, frontend, full-stack, and smart contract development. I understand the task clearly and can deliver a clean, efficient, well-tested solution on time, with strong focus on code quality and maintainability. My PR will be submitted in 3days

  5. grantfox-oss commented on Sep 8, 2026

    @grantfox-oss

    🦊 GrantFox — @gloskull has been assigned to this issue!

    Next steps:

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

    Good luck! Track your progress on GrantFox.

  6. grantfox-oss commented on Sep 15, 2026

    @grantfox-oss

    🎉 This issue has been marked as completed on GrantFox!

    @gloskull's PR #211 was approved and merged by @collinsezedike.

    🏆 @gloskull: You earned 50 FoxPoints for this contribution! Your current tier: Pro (10,228 total points). Track your full progress on GrantFox.

    👏 Great work, @gloskull! Keep contributing to drydocs.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingeasySmall, low-risk change

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions