feat: multi-organizer revenue split and co-host wallet management - #1
Closed
josephchimebuka wants to merge 1 commit into
Closed
feat: multi-organizer revenue split and co-host wallet management#1josephchimebuka wants to merge 1 commit into
josephchimebuka wants to merge 1 commit into
Conversation
Replaces the single-organizer payout assumption with configurable revenue splits and co-host escrow handling (closes BuidlZone-Labs#122). - Event creation accepts revenue_splits: Vec<(Address, u32)> (basis points), validated to 1-5 recipients summing to 10000, no duplicates/zeros, with the primary organizer pinned at index 0. Splits are set once and immutable. - The split is synced to the payments contract, which settles each event once (deducting the platform fee first) and lets every recipient withdraw their allocated share independently via withdraw_split. Rounding dust accrues to the primary organizer so the full net is always distributed. - Primary organizer can flag a compromised co-host wallet; the flagged share is held in escrow and cannot be withdrawn. Admin resolves a dispute by either releasing the share to the recipient or reassigning it to the primary. - Legacy single-organizer withdrawal paths are rejected for split events to prevent double payout. Adds 17 payments unit tests and 3 event integration tests covering the happy path, fee ordering, independent withdrawals, the delay/dispute windows, split validation, immutability, flagging, and dispute resolution. Co-authored-by: Cursor <cursoragent@cursor.com>
Owner
Author
|
Superseded by the PR against upstream: BuidlZone-Labs#131. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked issue
Closes BuidlZone-Labs#122
What this PR does
Events are no longer locked to a single organizer wallet. An event can now be created with a revenue split — up to five recipients, each with a basis-point allocation summing to 10000. After the platform fee is deducted, each recipient withdraws their own share independently from the payments contract; no single party can drain the others' funds. The primary organizer (split index 0) keeps full admin rights and can flag a compromised co-host wallet, which freezes that recipient's share in escrow until an admin resolves the dispute by either releasing it to the recipient or reassigning it to the primary organizer.
Change type
Storage impact
CreateEventParams.revenue_splits/Event.revenue_splitsVec<(Address, u32)>DataKey::EventSplits(Symbol)(payments)Vec<RevenueSplit>DataKey::SplitSettlement(Symbol)(payments)SplitSettlementDataKey::SplitWithdrawn(Symbol, Address)(payments)i128DataKey::SplitFlagged(Symbol, Address)(payments)boolIs this a breaking storage change?
revenue_splitsfield is set on every newCreateEventParams(emptyVecfor the single-organizer case).On-chain vs. off-chain behaviour
ensure_split_settled;PlatformFeeCollectedemitted onceSplitWithdrawnguards double-withdrawal;RevenueWithdrawnemitted per recipientCohostFlagged/FlaggedShareResolvedemittedsync_revenue_splitsrejects any re-set; no setter existsCross-contract impact
PaymentsContract::sync_revenue_splits(event_contract, event_id, splits), called by the event contract duringcreate_event.event-contract(create_eventnow syncs the split;withdraw_splitandflag_cohostproxy to payments).Security checklist
sync_revenue_splitsrequires the linked event contract;withdraw_splitrequires the recipient;flag_cohostrequires the primary organizer;resolve_flagged_sharerequires the payments admin.event_end_ledger + withdrawal_delay + admin_extension; cancelled events respect the dispute window and the time-based withdrawable ratio (mirrorswithdraw).withdraw/withdraw_token/withdraw_all_tokens/withdraw_revenue/release_if_expiredare rejected for split events, preventing double payout.Test coverage
New tests added (payments —
revenue_split_test.rs):test_sync_revenue_splits_stores_and_reads_back(Address, u32)test_sync_revenue_splits_rejects_bad_sum/_more_than_five/_duplicate_and_zerotest_revenue_splits_are_immutable_once_settest_sync_revenue_splits_rejects_foreign_callertest_platform_fee_deducted_before_split_and_independent_withdrawalstest_withdraw_split_rejects_double_withdraw_and_non_recipienttest_withdraw_split_respects_withdrawal_delaytest_rounding_dust_accrues_to_primary_organizertest_only_primary_can_flag_and_cannot_flag_selftest_flagged_cohost_share_held_in_escrowtest_resolve_flag_release_to_recipient_allows_withdrawaltest_resolve_flag_reassign_to_primary_pays_primary_and_blocks_recipienttest_resolve_requires_flagged_recipienttest_legacy_withdraw_paths_rejected_for_split_eventstest_cancelled_split_event_distributes_only_withdrawable_ratioNew tests added (event —
integration_tests.rs):test_event_split_end_to_end_distribution,test_event_rejects_invalid_split_configurations,test_event_flag_cohost_through_front_door.Test count: 20 new, 18 updated (existing
CreateEventParamsliterals), 180 total passing (event 77, payments 103).cargo fmt --checkandcargo clippy -D warningsclean;cargo build --releasesucceeds.Acceptance criteria sign-off
revenue_splits: Vec<(Address, u32)>summing to 10000 —validate_revenue_splitsinevent/lib.rs;test_event_split_end_to_end_distribution.test_sync_revenue_splits_rejects_more_than_five.withdraw_split;test_platform_fee_deducted_before_split_and_independent_withdrawals.flag_cohostis primary-only; event admin ops keyed offevent.organizer.sync_revenue_splitsrejects re-set;test_revenue_splits_are_immutable_once_set.ensure_split_settleddeducts fee before computing shares; asserted in the fee test.flag_cohost+resolve_flagged_share; flagging/escrow/resolution tests.What this PR deliberately does NOT cover
withdraw.Reviewer focus areas
ensure_split_settledinpayments/lib.rs— fee-first ordering and the full vs. partial (cancelled) accounting againstvalidate_revenue_invariant.recipient_share— primary absorbs rounding dust; confirm sum of shares equals net.ensure_no_splitsguards on every legacy withdrawal path.Made with Cursor