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
[Bug] No exact-amount transfer verification permanently deadlocks a disputed assertion #164
assert_outcome, dispute, and resolve (contracts/tholos/src/lib.rs:581-833) each call token::Client::transfer(...) and trust that the requested amount actually moved, without verifying the contract's real balance delta. Assertion.bond records the nominalbond_amount requested at deposit time, not whatever the contract actually received.
With a non-standard, fee-on-transfer token, the two incoming deposits (assert_outcome's and dispute's) each land short of the full bond_amount by whatever cut the token takes. resolve's payout, once a majority is reached, writes Status::Resolved to storage and then calls transfer(contract, winner, assertion.bond * 2), the full nominal amount, not the actual (short) balance. That transfer panics on insufficient balance, reverting the whole transaction, including the state write, so the assertion remains Disputed forever.
Impact: every future attempt to reach majority and pay out hits the identical panic, since the deficit is permanent and assertion.bond never reflects the real shortfall. Both bonds are permanently locked with no way to resolve or reclaim them, for any dispute funded with such a token.
Scope
Verify the contract's actual balance delta around each incoming transfer (assert_outcome, dispute) and either reject tokens that don't deliver the full requested amount, or record the actually-received amount instead of the nominal request.
Ensure resolve's payout can never request more than the contract's real, verified balance for that assertion's token.
Add a test using a mock fee-on-transfer token confirming a dispute funded with it either gets rejected up front or resolves correctly instead of deadlocking.
Proposed approach
The most direct fix is to check token_client.balance(&env.current_contract_address()) before and after each incoming transfer in assert_outcome/dispute, and store the actual received delta (not the requested bond_amount) as assertion.bond. This keeps the rest of the payout math unchanged, since it already operates purely on assertion.bond, while ensuring that value always reflects what the contract genuinely holds for that assertion.
Activity
odiliflash-ops commentedon Sep 3, 2026
I would love to work on this issue
xtep103 commentedon Sep 3, 2026
Hi there, I’ve carefully reviewed the issue details and I’m confident I can provide a clean, efficient, and maintainable solution.
grantfox-oss commentedon Sep 4, 2026
🦊 GrantFox — @xtep103 has been assigned to this issue!
Next steps:
Closes #164)Good luck! Track your progress on GrantFox.
grantfox-oss commentedon Sep 15, 2026
🎉 This issue has been marked as completed on GrantFox!
@xtep103's PR #216 was approved and merged by @collinsezedike.
🏆 @xtep103: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (140 total points). Track your full progress on GrantFox.
👏 Great work, @xtep103! Keep contributing to drydocs.
fix(tholos): verify balance deltas for incoming token transfers (dryd…
fix(tholos): verify balance deltas for incoming token transfers (dryd…