Skip to content

Implement #163: dynamic recipient management (cap + replacement + quorum)#342

Open
jjb9707 wants to merge 1 commit into
Stellar-split:mainfrom
jjb9707:test/issue-163-recipient-management
Open

Implement #163: dynamic recipient management (cap + replacement + quorum)#342
jjb9707 wants to merge 1 commit into
Stellar-split:mainfrom
jjb9707:test/issue-163-recipient-management

Conversation

@jjb9707

@jjb9707 jjb9707 commented Jul 13, 2026

Copy link
Copy Markdown

Summary

Implements GrantFox issue #163 — Dynamic recipient management for the split contract. Adds an optional recipient cap at creation time and a co-signer-gated recipient replacement flow, so a split invoice's payout targets can evolve without recreating the invoice.

Acceptance criteria

  1. Recipient capInvoiceOptions.max_recipients: Option<u32> is enforced in create_invoice: creating an invoice with more recipients than the cap panics with "exceeds max recipients".
  2. Propose replacementpropose_recipient_replacement lets the creator or a co-creator propose swapping an existing recipient (old_recipient) for a new one (new_recipient). Only allowed while the invoice is Pending and not a streaming (drip) invoice.
  3. Approve / execute with quorumapprove_recipient_replacement lets each authorized co-signer approve a pending proposal; once required_signatures distinct co-signers have approved, the replacement is applied automatically. When required_signatures == 0, the proposal executes immediately on propose.
  4. Slot-preserving swapexecute_recipient_replacement overwrites the same recipient slot (recipients.set(idx, new)), so amounts / claimed stay index-aligned, and migrates the paid set (the new recipient is marked paid if the old one already was). Emits recipient_replacement_proposed / recipient_replacement_executed events.

Tests added (test.rs)

  • test_recipient_replacement_requires_quorum — 2 co-signers + required_signatures = 2; first approval does not execute, second does.
  • test_recipient_replacement_preserves_claimed_amounts — after a paid release, replacing a recipient keeps the claimed amount on the new slot and blocks a double release_to_recipient.
  • test_recipient_replacement_blocked_on_released_invoice — proposing on an already-released invoice panics (replacement requires pending invoice).
  • test_recipient_cap_enforced_at_creation — 3 recipients with max_recipients = 2 panics at creation.

Verification

  • cargo check -p split (lib) and cargo check --tests -p split both compile cleanly on the local GNU toolchain.
  • The diff is purely additive (4 files, +445 / -0) — no unrelated reformatting.
  • CI should run the full cargo test suite against the committed toolchain; the local environment could not link the test binary (no MSVC / incomplete GNU binutils) but type-checking of the new code and tests passes.

This should be reviewed for on-chain storage compatibility of the InvoiceOptions struct change before merge.

…+ replacement + quorum)

- Add optional max_recipients cap on InvoiceOptions, enforced at
  create_invoice time.
- Add propose_recipient_replacement / approve_recipient_replacement
  (co-signer quorum) + private execute_recipient_replacement that
  inherits the recipient slot (keeps amounts/claimed aligned) and
  migrates the paid set.
- Emit recipient_replacement_proposed / _executed events.
- Add 4 tests covering quorum, claimed-amount preservation,
  released-invoice rejection, and the recipient cap.
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.

1 participant