Fix/fee distribution rounding error#82
Fix/fee distribution rounding error#82caxtonacollins wants to merge 4 commits intoTrustless-Work:single-release-develop_v2from
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@armandocodecr please review |
|
@techrebelgit please review |
|
@techrebelgit hellooo |
armandocodecr
left a comment
There was a problem hiding this comment.
The fix in dispute.rs is correct in both functions (withdraw_remaining_funds and resolve_dispute). The approach of accumulating the actual fees per recipient before transferring (“accumulate-then-transfer”) solves the root bug: now sum(actual_fees) + sum(net_amounts) = total, so the contract never attempts to move more funds than it has. Good work there.
What needs to be corrected
-
The test does not reproduce the bug.
With total = 2 and fees of 30 bps + 300 bps, both fees round to 0 (floor(2 * 30 / 10000) = 0). That means the test passes trivially without exercising the rounding vulnerability — the old code would have passed it too. You need to use values where the fees are > 0 and the rounding difference is observable. For example: total = 100_003 with distributions {A: 50_001, B: 50_002} or something similar where sum(floor(amount_i * fee / total)) is strictly less than the calculated total fee. -
Missing test for withdraw_remaining_funds.
The test only covers resolve_dispute, but the same bug existed in withdraw_remaining_funds. Add an equivalent test for that function as well. -
Minor cleanup of the test.
The comment “// Actually, let's use slightly larger small amounts to see some rounding” looks like a draft thought that was left there. Clean it up before merging. -
Suggestion (non-blocking): The logic for accumulating fees + net distributions is identical in both functions (~30 lines). It would be good to extract it to a helper function to avoid code duplication, but that can be left for a later refactor.
In summary: the fix is fine, the test needs to be redone with values that actually trigger the rounding error, and coverage needs to be added for withdraw_remaining_funds.
|
Hi @caxtonacollins! I've left you a couple of comments. |
@armandocodecr working on it |
|
@armandocodecr i have made the changes |
Pull Request | Trustless Work
1. Issue Link
2. Brief Description of the Issue
A critical accounting vulnerability was identified in the
withdraw_remaining_fundsandresolve_disputefunctions. The contract transferred total fees upfront and then calculated each recipient's share using floor division. Due to rounding, the sum of individual fee shares was often less than the total fees transferred, leading to the contract attempting to distribute more funds than were actually available in its balance. This caused transaction reverts and potentially locked funds.Solution
Implemented Strategy 1: Deduct Individual Fees First.
Instead of transferring the total estimated fees upfront, the contract now:
actual_trustless_feesandactual_platform_fees.net_amountfor each recipient by subtracting their individual fee shares.This ensures that
actual_fees + sum(net_amounts)exactly equals the total amount being distributed, maintaining perfect accounting balance.Changes
contracts/escrow/src/core/dispute.rs: Refactoredwithdraw_remaining_fundsandresolve_disputeto use the new fee accumulation logic.contracts/escrow/src/tests/dispute_tests.rs: Addedtest_dispute_resolution_rounding_edge_caseto verify the fix with small amounts (2i128) that previously triggered reverts.Verification
cargo test): Passed (19 tests).Branch
fix/fee-distribution-rounding-error