Skip to content

Validate InvoiceOptions ranges at invoice creation (#690–#693) - #715

Merged
Kingsman-99 merged 1 commit into
Stellar-split:mainfrom
gideonpius7-design:feat/validate-invoice-options-690-693
Aug 30, 2026
Merged

Validate InvoiceOptions ranges at invoice creation (#690–#693)#715
Kingsman-99 merged 1 commit into
Stellar-split:mainfrom
gideonpius7-design:feat/validate-invoice-options-690-693

Conversation

@gideonpius7-design

Copy link
Copy Markdown

What

Adds creation-time validation of InvoiceOptions numeric ranges in
_create_invoice_inner, before any storage is written.

Closes #690
Closes #691
Closes #692
Closes #693

Issue Rule Error
#690 penalty_bps > 10_000 ContractError::InvalidAmount
#691 non-empty tranches: sum(basis_points) != 10_000 ContractError::InvalidRatioSum
#692 non-empty release_stages: sum != 10_000 ContractError::InvalidRatioSum
#693 required_signatures > co_signers.len(), or == 0 with non-empty co_signers ContractError::InvalidAmount

Empty tranches / release_stages are skipped (release-all-at-once stays valid).

The tranche and release-stage sum checks already existed but panicked with a
host string via .expect(). They now surface the proper ContractError, so
try_create_invoice callers receive a typed error instead of an opaque
InvokeError. A new validation::assert_valid_bps helper backs the
penalty_bps check.

Tests

New unit tests in contracts/split/src/test.rs:

  • penalty_bps = 10_001 rejected / = 10_000 accepted
  • tranches sum 9_999 rejected / 10_000 accepted
  • release_stages sum 9_500 rejected / three stages summing 10_000 accepted
  • required_signatures 2-of-1 rejected, 0-of-2 rejected, valid 2-of-3 accepted

test_create_invoice_invalid_release_stages_panics updated to assert the
typed InvalidRatioSum error via try_create_invoice.

⚠️ Pre-existing breakage on main (not caused by this PR)

cargo test --workspace / cargo test -p split does not compile on main
today
— CI has been red for a while. This PR fixes the four blockers that
sit directly on the invoice-creation / validation path so the changes here
are coherent:

  • duplicate mod validation; in lib.rs
  • use validation::assert_valid_bps; referencing a function that did not exist
  • a spliced/duplicated invoice_expired in events.rs with an unclosed
    delimiter (botched merge)
  • a duplicated import line in test.rs

Remaining unrelated errors still block a green build (~20+ across
lib.rs, types.rs, storage.rs, events.rs): soroban-sdk API drift
(Persistent::bump, Map::has, Vec::to_vec), a missing calc_platform_fee
fn, a missing ContractError::TooFewRecipients variant, non-exhaustive
matches on InvoiceStatus::PayoutInProgress, and .expect() on non-Option
getters in test.rs. These are out of scope for #690#693 and should be
addressed by a dedicated repair PR; until then cargo test cannot be run to
green and the new tests here are unverified by execution (logic is
straightforward range checks).

🤖 Generated with Claude Code

…Stellar-split#691, Stellar-split#692, Stellar-split#693)

Add creation-time validation to `_create_invoice_inner`, before any storage
is written:

* Stellar-split#690 penalty_bps: reject `penalty_bps > 10_000` with
  `ContractError::InvalidAmount` (via `assert_valid_bps`), so a late-payment
  penalty can never exceed 100% of the payment.
* Stellar-split#691 tranches: when `tranches` is non-empty, its `basis_points` must sum to
  exactly 10_000, else `ContractError::InvalidRatioSum`. Empty schedule is
  skipped.
* Stellar-split#692 release_stages: when non-empty, entries must sum to exactly 10_000,
  else `ContractError::InvalidRatioSum`. Empty schedule is skipped.
* Stellar-split#693 required_signatures: reject `required_signatures > co_signers.len()`
  and `required_signatures == 0` with non-empty `co_signers`, both with
  `ContractError::InvalidAmount`, so the multi-sig release gate is always
  satisfiable.

The tranche / release-stage checks already existed but panicked with a host
string via `.expect()`; they now surface the proper `ContractError` so
`try_create_invoice` callers get a typed error.

Tests: add unit tests for each boundary (10_001 vs 10_000; sum 9_999 vs
10_000; sum 9_500 vs three stages summing 10_000; 2-of-1 and 0-of-2 rejected
vs valid 2-of-3). Existing `test_create_invoice_invalid_release_stages_panics`
updated to assert the typed error.

Also repaired pre-existing compile blockers on `main` that sit directly on
the creation/validation path (unrelated to these issues, noted in the PR):
duplicate `mod validation;`, missing `validation::assert_valid_bps`, a
spliced/duplicated `invoice_expired` with an unclosed delimiter in events.rs,
and a duplicate import line in test.rs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GPTytjBS9tuuaywXrcQwRN
@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@gideonpius7-design Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Kingsman-99
Kingsman-99 merged commit 41aa26d into Stellar-split:main Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants