From 35846deb8976752c64f911732bce14dd6d3a7046 Mon Sep 17 00:00:00 2001 From: deborahairtel887-dotcom Date: Sun, 30 Aug 2026 20:56:06 +0000 Subject: [PATCH] fix: validate early_bird_fee_bps does not exceed platform fee at creation (#696) --- contracts/split/src/lib.rs | 26 +++++-------- contracts/split/src/test.rs | 76 +++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/contracts/split/src/lib.rs b/contracts/split/src/lib.rs index f5e1624..4291317 100644 --- a/contracts/split/src/lib.rs +++ b/contracts/split/src/lib.rs @@ -5428,29 +5428,21 @@ impl SplitContract { assert!(min_funding_bps <= 10_000, "min_funding_bps must be ≤ 10000"); assert_valid_bps(tax_bps).expect("tax_bps must be ≤ 10000"); assert_valid_bps(insurance_premium_bps).expect("insurance_premium_bps must be ≤ 10000"); - // Issue #489: early-bird discounted platform fee must not exceed the - // standard fee in effect for this creator at creation time. - assert!( - early_bird_fee_bps <= 10_000, - "early_bird_fee_bps must be ≤ 10000" - ); - if early_bird_window_ledgers > 0 { - let standard_fee_bps = Self::get_applicable_fee(env.clone(), creator.clone()); - assert!( - early_bird_fee_bps <= standard_fee_bps, - "early_bird_fee_bps must not exceed the standard platform fee" - ); + // Issue #489 / #696: early-bird discounted platform fee must not exceed the + // platform fee read from contract storage at creation time. + let platform_fee_bps: u32 = env + .storage() + .instance() + .get(&platform_fee_bps_key()) + .unwrap_or(0u32); + if early_bird_fee_bps > platform_fee_bps { + env.panic_with_error(ContractError::InvalidAmount); } // Issue #559: creator fee must be within bounds and not exceed cap with platform fee. assert!( creator_fee_bps <= 10_000, "creator_fee_bps must be ≤ 10000" ); - let platform_fee_bps: u32 = env - .storage() - .instance() - .get(&platform_fee_bps_key()) - .unwrap_or(0u32); assert!( (creator_fee_bps as u64 + platform_fee_bps as u64) <= 10_000, "FeeSumExceedsCap" diff --git a/contracts/split/src/test.rs b/contracts/split/src/test.rs index ca0e831..0ab979a 100644 --- a/contracts/split/src/test.rs +++ b/contracts/split/src/test.rs @@ -8495,3 +8495,79 @@ fn test_create_invoice_valid_multisig_setup_ok() { let id = c.create_invoice(&creator, &recipients, &amounts, &token_id, &9_999_u64, &opts); assert!(id >= 1); } + +// --- Issue #696: early_bird_fee_bps must not exceed platform fee at creation --- + +#[test] +fn test_create_invoice_early_bird_fee_exceeds_platform_fee_rejected() { + let (env, contract_id, token_id) = setup(); + let c = client(&env, &contract_id); + let admin = Address::generate(&env); + let treasury = Address::generate(&env); + c.initialize(&admin, &0_i128, &treasury, &token_id, &500_u32, &None, &0_u32, &0_u32, &0_u64); + env.ledger().set_timestamp(1_000); + + let creator = Address::generate(&env); + let (recipients, amounts) = two_recipients(&env); + + let mut opts = default_options(&env); + opts.ext.early_bird_fee_bps = 501; + + let res = c.try_create_invoice(&creator, &recipients, &amounts, &token_id, &9_999_u64, &opts); + assert_eq!(res, Err(Ok(ContractError::InvalidAmount.into()))); +} + +#[test] +fn test_create_invoice_early_bird_fee_exceeds_default_zero_platform_fee_rejected() { + let (env, contract_id, token_id) = setup_initialized(); + let c = client(&env, &contract_id); + env.ledger().set_timestamp(1_000); + + let creator = Address::generate(&env); + let (recipients, amounts) = two_recipients(&env); + + let mut opts = default_options(&env); + opts.ext.early_bird_fee_bps = 100; + + let res = c.try_create_invoice(&creator, &recipients, &amounts, &token_id, &9_999_u64, &opts); + assert_eq!(res, Err(Ok(ContractError::InvalidAmount.into()))); +} + +#[test] +fn test_create_invoice_early_bird_fee_equals_platform_fee_ok() { + let (env, contract_id, token_id) = setup(); + let c = client(&env, &contract_id); + let admin = Address::generate(&env); + let treasury = Address::generate(&env); + c.initialize(&admin, &0_i128, &treasury, &token_id, &500_u32, &None, &0_u32, &0_u32, &0_u64); + env.ledger().set_timestamp(1_000); + + let creator = Address::generate(&env); + let (recipients, amounts) = two_recipients(&env); + + let mut opts = default_options(&env); + opts.ext.early_bird_fee_bps = 500; + + let id = c.create_invoice(&creator, &recipients, &amounts, &token_id, &9_999_u64, &opts); + assert!(id >= 1); +} + +#[test] +fn test_create_invoice_early_bird_fee_less_than_platform_fee_ok() { + let (env, contract_id, token_id) = setup(); + let c = client(&env, &contract_id); + let admin = Address::generate(&env); + let treasury = Address::generate(&env); + c.initialize(&admin, &0_i128, &treasury, &token_id, &500_u32, &None, &0_u32, &0_u32, &0_u64); + env.ledger().set_timestamp(1_000); + + let creator = Address::generate(&env); + let (recipients, amounts) = two_recipients(&env); + + let mut opts = default_options(&env); + opts.ext.early_bird_fee_bps = 250; + + let id = c.create_invoice(&creator, &recipients, &amounts, &token_id, &9_999_u64, &opts); + assert!(id >= 1); +} +