Skip to content

test(events): escrow fee + release math — rounding & override bps#50

Open
JamesVictor-O wants to merge 1 commit into
boundlessfi:testnetfrom
JamesVictor-O:test/escrow-fee-math
Open

test(events): escrow fee + release math — rounding & override bps#50
JamesVictor-O wants to merge 1 commit into
boundlessfi:testnetfrom
JamesVictor-O:test/escrow-fee-math

Conversation

@JamesVictor-O

@JamesVictor-O JamesVictor-O commented Jun 24, 2026

Copy link
Copy Markdown

Summary

  • Adds tests/escrow_fee_math.rs with 32 integration tests covering every function in escrow.rs plus the payout-split math in select_winners (Single) and claim_milestone (Multi/Crowdfunding)
  • Tests cover happy paths, each relevant Error variant, edge cases (rounding, zero bps, max boundary, large amounts), idempotency, and mid-flight global bps isolation
  • All existing tests continue to pass (cargo test --all = 121 tests green); snapshots regenerated and committed

Test plan

  • cargo test -p boundless-events -- escrow_fee_math — 32 passed
  • cargo test --all — 121 passed, 0 failed
  • cargo build --target wasm32-unknown-unknown --release — clean

Closes #31

Summary by CodeRabbit

  • Tests
    • Added comprehensive test coverage for escrow fee calculations, payout distributions, and contribution scenarios including deposits, cancellations, and multi-milestone payouts with correct rounding and pro-rata splitting logic.
    • Updated test snapshots to reflect current contract state expectations across admin, contribution, cross-contract, and crowdfunding workflows.

…e bps)

Closes boundlessfi#31

New `tests/escrow_fee_math.rs` covering every function in `escrow.rs`
plus the payout-split math in `select_winners` (Single) and
`claim_milestone` (Multi / Crowdfunding).

32 tests covering:
- effective_fee_bps: global vs per-event override, zero bps, max boundary
- compute_fee_at: truncation rounding on non-divisible amounts
- deposit_with_fee: override flows through add_funds, zero-fee skip
- release (Single): 100%, multi-position, 33/33/34 rounding, partial fill
- release (Grant milestone): floored per-milestone, last-sweep correction,
  double-claim rejection, out-of-range rejection
- release (Crowdfunding): dynamic split, rounding with no dust stranded
- Error variants: InvalidFeeBps, WinnersAlreadySelected, EventNotFound,
  DuplicateWinnerPosition, InvalidWinnerPosition, NoSubmissions,
  MilestoneAlreadyClaimed, InvalidMilestone
- Idempotency: replayed create_event, replayed select_winners
- Mid-flight global bps change isolation
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb970ce2-8ca7-4532-926a-e01ddac569cd

📥 Commits

Reviewing files that changed from the base of the PR and between d3a32bd and de6cc7a.

📒 Files selected for processing (102)
  • contracts/events/src/tests/escrow_fee_math.rs
  • contracts/events/src/tests/mod.rs
  • contracts/events/test_snapshots/tests/admin/apply_upgrade_after_expiry_reverts.1.json
  • contracts/events/test_snapshots/tests/admin/apply_upgrade_before_timelock_reverts.1.json
  • contracts/events/test_snapshots/tests/admin/cancel_pending_upgrade_clears_proposal.1.json
  • contracts/events/test_snapshots/tests/admin/propose_upgrade_records_pending_and_emits.1.json
  • contracts/events/test_snapshots/tests/contributions/add_funds_paged_storage_round_trip.1.json
  • contracts/events/test_snapshots/tests/contributions/add_funds_to_cancelled_event_reverts.1.json
  • contracts/events/test_snapshots/tests/contributions/anyone_can_top_up_an_active_event.1.json
  • contracts/events/test_snapshots/tests/contributions/below_minimum_contribution_reverts.1.json
  • contracts/events/test_snapshots/tests/contributions/cancel_at_boundary_pays_partners_full_no_owner_residual.1.json
  • contracts/events/test_snapshots/tests/contributions/cancel_clears_contributor_amounts_so_replay_state_is_clean.1.json
  • contracts/events/test_snapshots/tests/contributions/cancel_with_no_contributors_refunds_owner_in_full.1.json
  • contracts/events/test_snapshots/tests/contributions/cancel_with_owner_top_up_keeps_owner_residual_correct.1.json
  • contracts/events/test_snapshots/tests/contributions/cancel_with_partner_pool_refunds_partners_then_owner_residual.1.json
  • contracts/events/test_snapshots/tests/contributions/multiple_top_ups_from_same_contributor_aggregate_and_dont_duplicate_list.1.json
  • contracts/events/test_snapshots/tests/contributions/owner_top_up_grows_escrow_without_recording_contribution_entry.1.json
  • contracts/events/test_snapshots/tests/contributions/paged_cancel_owner_only_settles_inside_start.1.json
  • contracts/events/test_snapshots/tests/contributions/paged_cancel_processes_in_batches.1.json
  • contracts/events/test_snapshots/tests/contributions/replayed_add_funds_reverts.1.json
  • contracts/events/test_snapshots/tests/contributions/zero_or_negative_contribution_reverts.1.json
  • contracts/events/test_snapshots/tests/cross_contract/add_funds_uses_event_override_not_global.1.json
  • contracts/events/test_snapshots/tests/cross_contract/apply_charges_credits_via_profile.1.json
  • contracts/events/test_snapshots/tests/cross_contract/bounty_submit_requires_prior_application.1.json
  • contracts/events/test_snapshots/tests/cross_contract/bounty_submit_succeeds_after_apply.1.json
  • contracts/events/test_snapshots/tests/cross_contract/cancel_after_select_winners_refunds_only_remaining.1.json
  • contracts/events/test_snapshots/tests/cross_contract/cancel_already_cancelled_reverts.1.json
  • contracts/events/test_snapshots/tests/cross_contract/cancel_refunds_remaining_escrow_to_owner.1.json
  • contracts/events/test_snapshots/tests/cross_contract/claim_milestone_final_milestone_marks_event_completed.1.json
  • contracts/events/test_snapshots/tests/cross_contract/claim_milestone_idempotent_per_recipient_and_milestone.1.json
  • contracts/events/test_snapshots/tests/cross_contract/claim_milestone_invalid_milestone_index_reverts.1.json
  • contracts/events/test_snapshots/tests/cross_contract/claim_milestone_pays_per_milestone_amount.1.json
  • contracts/events/test_snapshots/tests/cross_contract/claim_milestone_rejects_non_grant_events.1.json
  • contracts/events/test_snapshots/tests/cross_contract/create_event_charges_override_rate_when_provided.1.json
  • contracts/events/test_snapshots/tests/cross_contract/create_event_omitted_override_falls_back_to_global_default.1.json
  • contracts/events/test_snapshots/tests/cross_contract/create_event_with_waiver_charges_no_fee.1.json
  • contracts/events/test_snapshots/tests/cross_contract/duplicate_apply_reverts.1.json
  • contracts/events/test_snapshots/tests/cross_contract/grant_last_milestone_sweeps_rounding_residue.1.json
  • contracts/events/test_snapshots/tests/cross_contract/hackathon_submit_creates_anchor_without_prior_apply.1.json
  • contracts/events/test_snapshots/tests/cross_contract/insufficient_credits_reverts.1.json
  • contracts/events/test_snapshots/tests/cross_contract/replayed_apply_reverts_idempotently.1.json
  • contracts/events/test_snapshots/tests/cross_contract/resubmit_preserves_original_submitted_at_and_updates_uri.1.json
  • contracts/events/test_snapshots/tests/cross_contract/select_winners_handles_multi_recipient_distribution.1.json
  • contracts/events/test_snapshots/tests/cross_contract/select_winners_pays_against_remaining_escrow_including_top_ups.1.json
  • contracts/events/test_snapshots/tests/cross_contract/select_winners_pays_recipient_and_bumps_profile.1.json
  • contracts/events/test_snapshots/tests/cross_contract/select_winners_rejects_duplicate_position.1.json
  • contracts/events/test_snapshots/tests/cross_contract/select_winners_rejects_second_call_winners_already_selected.1.json
  • contracts/events/test_snapshots/tests/cross_contract/select_winners_replayed_reverts.1.json
  • contracts/events/test_snapshots/tests/cross_contract/select_winners_requires_position_in_distribution.1.json
  • contracts/events/test_snapshots/tests/cross_contract/submit_replayed_reverts.1.json
  • contracts/events/test_snapshots/tests/cross_contract/withdraw_refunds_half_credits.1.json
  • contracts/events/test_snapshots/tests/cross_contract/withdraw_submission_removes_anchor.1.json
  • contracts/events/test_snapshots/tests/cross_contract/withdraw_submission_without_submission_reverts.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/builder_top_up_does_not_appear_in_contributor_list.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/cancel_after_partial_claim_pro_rates_remaining.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/cancel_refunds_all_partners_no_owner_residual.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/cancel_with_no_contributions_just_marks_cancelled.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/claim_milestone_last_drains_dust_remainder.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/claim_milestone_out_of_range_reverts.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/claim_milestone_replay_reverts.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/claim_milestone_splits_evenly_across_remaining.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/claim_milestone_with_empty_escrow_reverts.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/community_top_ups_raise_escrow_from_zero.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/create_with_zero_owner_deposit_and_auto_registered_winner.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/crowdfunding_claim_milestone_requires_admin_auth.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/select_winners_on_crowdfunding_reverts.1.json
  • contracts/events/test_snapshots/tests/crowdfunding/submit_on_crowdfunding_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/add_funds_uses_event_override_bps.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/add_funds_zero_override_bps_charges_no_fee.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/crowdfunding_dynamic_milestone_split.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/crowdfunding_dynamic_rounding_no_dust.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/fee_account_accumulates_across_create_and_add_funds.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/fee_and_winner_balances_consistent.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/fee_rounding_on_odd_amounts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/fee_rounds_down_non_divisible_amount.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/global_fee_bps_used_when_no_override.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/grant_milestone_double_claim_rejected.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/grant_milestone_out_of_range_rejected.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/grant_milestone_pays_floored_per_milestone.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/large_budget_fee_does_not_overflow.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/mid_flight_global_bps_change_does_not_affect_override_event.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/multi_position_split_pays_correct_amounts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/override_at_max_bps_boundary_succeeds.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/override_bps_above_max_rejected.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/override_bps_used_on_create.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/partial_position_fill_leaves_residual_escrow.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/partner_funds_grow_winner_payout.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/replayed_create_event_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/replayed_select_winners_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/select_winners_duplicate_position_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/select_winners_empty_list_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/select_winners_invalid_position_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/select_winners_on_cancelled_event_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/select_winners_on_nonexistent_event_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/select_winners_twice_reverts.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/single_release_pays_full_escrow_for_100_percent.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/three_way_33_33_34_split_rounding.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/zero_global_bps_no_override_charges_no_fee.1.json
  • contracts/events/test_snapshots/tests/escrow_fee_math/zero_override_bps_skips_fee.1.json
  • contracts/profile/test_snapshots/tests/admin/apply_upgrade_after_expiry_reverts_profile.1.json
  • contracts/profile/test_snapshots/tests/admin/apply_upgrade_before_timelock_reverts_profile.1.json
  • contracts/profile/test_snapshots/tests/admin/propose_upgrade_records_pending.1.json

📝 Walkthrough

Walkthrough

Adds a new Rust test module escrow_fee_math.rs (~998 lines) to the Events contract covering end-to-end fee BPS selection, rounding, payout splitting, milestone claiming, replay rejection, error variants, overflow safety, and integrated consistency checks. The new module declaration is registered in mod.rs. Six new JSON test snapshots are added for the new tests, and all existing test snapshots across admin, contributions, cross_contract, and crowdfunding directories are updated to reflect the changed compiled wasm hash.

Changes

Escrow Fee Math Test Suite and Snapshot Updates

Layer / File(s) Summary
Test environment setup and helper constructors
contracts/events/src/tests/mod.rs, contracts/events/src/tests/escrow_fee_math.rs
Registers the escrow_fee_math submodule, bootstraps the Soroban mock environment with profile/events contracts, mock token, admin/fee accounts, and auth mocking; provides event factory helpers for Hackathon, Grant, and Crowdfunding events with optional BPS overrides and partner funding.
Fee BPS selection, rounding, and add_funds fee routing tests
contracts/events/src/tests/escrow_fee_math.rs
Tests for global-vs-override BPS selection, zero override skipping fees, max-BPS boundary, rejection of out-of-range overrides, fee truncation for odd/non-divisible budgets, and deposit/add_funds fee routing through the event-level override.
Release payout, partner funding, and milestone claiming tests
contracts/events/src/tests/escrow_fee_math.rs
Tests for single and multi-winner pro-rata payout splitting with rounding and residual escrow, partner contribution enlargement of the payout pool, Grant per-milestone floored payouts with last-milestone sweep and error handling, and Crowdfunding dynamic milestone split with no dust accumulation.
Fee accumulation, idempotency, error variants, overflow, and consistency tests
contracts/events/src/tests/escrow_fee_math.rs
Tests for fee account balance accumulation across create and add_funds, create_event/select_winners replay rejection, select_winners negative-case error variants (nonexistent event, duplicate positions, invalid position, empty list, second call), large-budget overflow safety, mid-flight global BPS isolation, cancelled-event auth rejection, and integrated winner+fee balance consistency.
New escrow_fee_math test snapshots
contracts/events/test_snapshots/tests/escrow_fee_math/*
Six new JSON test snapshots encoding the full auth call sequence and expected ledger state for: add_funds with event-override BPS, add_funds with zero-override (no fee), fee account accumulation, fee and winner balance consistency, fee rounding on odd amounts, fee rounds down for non-divisible amounts, and global fee BPS used when no override.
Existing snapshot wasm hash updates
contracts/events/test_snapshots/tests/admin/*, contracts/events/test_snapshots/tests/contributions/*, contracts/events/test_snapshots/tests/cross_contract/*, contracts/events/test_snapshots/tests/crowdfunding/*
All pre-existing test snapshot JSON files update their bytes hash values for auth invocation payloads and OpSeen ledger entries—a cascade caused by the changed compiled contract wasm hash from adding the new test module.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #31 (test(events): escrow fee + release math — rounding & override bps): This PR directly implements all acceptance criteria: adds tests/escrow_fee_math.rs with coverage of every function in scope including happy paths, all Error variants, edge cases, auth rejection, and idempotency tests, with the mod escrow_fee_math; declaration in mod.rs.
  • #25 (contract test-coverage push): The new escrow_fee_math module is explicitly part of the broader contract test-coverage expansion epic referenced in issue #31.
  • #32 (test(events): grant pillar dynamic-release math): The new module includes Grant milestone claiming tests (floored per-milestone amounts, last-milestone sweep, double-claim rejection), which overlaps with grant pillar math testing requested in issue #32, though organized within escrow_fee_math.rs rather than a separate grant_pillar.rs file.

Poem

🐇 A rabbit hops through each escrow fee test,
Checking the BPS from lowest to best.
Rounding truncates — no dust shall remain,
The milestones all claimed, and the winners all gain.
Snapshots refreshed with new hashes in tow,
The ledger stays clean, and the tests all glow! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'test(events): escrow fee + release math — rounding & override bps' clearly and specifically summarizes the main change: comprehensive tests for escrow fee mathematics and release payout logic.
Linked Issues check ✅ Passed The PR fully satisfies all coding requirements from issue #31: new test file covers every function in scope (effective_fee_bps, compute_fee_at, deposit_with_fee, release/claim functions), includes happy paths and all relevant Error variants, covers edge cases (rounding, zero bps, max boundaries), provides idempotency testing, and cargo test passes.
Out of Scope Changes check ✅ Passed All changes are directly scoped to test coverage requirements: new test module (escrow_fee_math.rs), test module registration (mod.rs), and regenerated snapshot files reflecting the new tests' deterministic operation recording.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(events): escrow fee + release math — rounding & override bps

1 participant