From dfef6419d3c4f6605fde6c70e0c7d9fdb740894e Mon Sep 17 00:00:00 2001 From: fejilaup-cloud Date: Thu, 27 Aug 2026 03:46:42 +0000 Subject: [PATCH 1/4] feat: add get_invoice_deadline view function with test - Add get_invoice_deadline(invoice_id: u64) -> Result - Returns deadline timestamp from InvoiceCore - Returns ContractError::InvoiceNotFound for unknown invoice IDs - Includes unit tests verifying deadline value and error handling - Enables efficient frontend expiry countdown UI without loading full struct Closes #590 --- contracts/split/src/lib.rs | 10 ++++++++++ contracts/split/src/test.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/contracts/split/src/lib.rs b/contracts/split/src/lib.rs index b2fe796..d4cfc4e 100644 --- a/contracts/split/src/lib.rs +++ b/contracts/split/src/lib.rs @@ -4032,6 +4032,16 @@ impl SplitContract { } } + pub fn get_invoice_deadline(env: Env, invoice_id: u64) -> Result { + if let Some(core) = env.storage().persistent().get(&invoice_key(invoice_id)) { + Ok(core.deadline) + } else if let Some(core) = env.storage().instance().get(&invoice_key(invoice_id)) { + Ok(core.deadline) + } else { + Err(ContractError::InvoiceNotFound) + } + } + /// Get a consolidated invoice snapshot for off-chain audit. pub fn get_invoice_snapshot(env: Env, invoice_id: u64) -> types::InvoiceSnapshot { let core: types::InvoiceCore = env diff --git a/contracts/split/src/test.rs b/contracts/split/src/test.rs index cca8b97..967b7d4 100644 --- a/contracts/split/src/test.rs +++ b/contracts/split/src/test.rs @@ -8017,3 +8017,29 @@ fn test_cancel_invoice_on_deleted_invoice_panics() { c.delete_invoice(&creator, &id); c.cancel_invoice(&creator, &id); } + +#[test] +fn test_get_invoice_deadline() { + let (env, contract_id, token_id) = setup_initialized(); + let c = client(&env, &contract_id); + + let creator = Address::generate(&env); + let recipient = Address::generate(&env); + let deadline: u64 = 5_000; + + env.ledger().set_timestamp(1_000); + + let id = make_invoice(&env, &c, &creator, &recipient, 100, &token_id, deadline); + + let returned_deadline = c.get_invoice_deadline(&id).expect("should return deadline"); + assert_eq!(returned_deadline, deadline); +} + +#[test] +fn test_get_invoice_deadline_not_found() { + let (env, contract_id, _token_id) = setup_initialized(); + let c = client(&env, &contract_id); + + let result = c.try_get_invoice_deadline(&999); + assert!(result.is_err()); +} From 7689087c5c78f4b30e066b1cd1ed6138f6f0ef8d Mon Sep 17 00:00:00 2001 From: fejilaup-cloud Date: Thu, 27 Aug 2026 03:46:59 +0000 Subject: [PATCH 2/4] feat: add get_invoice_funded view function with test - Add get_invoice_funded(invoice_id: u64) -> Result - Reads funded amount from InvoiceHot (instance storage) if available, falls back to InvoiceCore - Returns ContractError::InvoiceNotFound if invoice does not exist - Includes unit tests verifying funded value increases after payment and error handling - Enables efficient polling by payment UIs without loading full struct Closes #589 --- contracts/split/src/lib.rs | 12 ++++++++++++ contracts/split/src/test.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/contracts/split/src/lib.rs b/contracts/split/src/lib.rs index d4cfc4e..d5137bb 100644 --- a/contracts/split/src/lib.rs +++ b/contracts/split/src/lib.rs @@ -4042,6 +4042,18 @@ impl SplitContract { } } + pub fn get_invoice_funded(env: Env, invoice_id: u64) -> Result { + if let Some(hot) = env.storage().instance().get(&invoice_hot_key(invoice_id)) { + Ok(hot.funded) + } else if let Some(core) = env.storage().persistent().get(&invoice_key(invoice_id)) { + Ok(core.funded) + } else if let Some(core) = env.storage().instance().get(&invoice_key(invoice_id)) { + Ok(core.funded) + } else { + Err(ContractError::InvoiceNotFound) + } + } + /// Get a consolidated invoice snapshot for off-chain audit. pub fn get_invoice_snapshot(env: Env, invoice_id: u64) -> types::InvoiceSnapshot { let core: types::InvoiceCore = env diff --git a/contracts/split/src/test.rs b/contracts/split/src/test.rs index 967b7d4..dd780df 100644 --- a/contracts/split/src/test.rs +++ b/contracts/split/src/test.rs @@ -8043,3 +8043,36 @@ fn test_get_invoice_deadline_not_found() { let result = c.try_get_invoice_deadline(&999); assert!(result.is_err()); } + +#[test] +fn test_get_invoice_funded() { + let (env, contract_id, token_id) = setup_initialized(); + let c = client(&env, &contract_id); + let tk = token_client(&env, &token_id); + + let creator = Address::generate(&env); + let payer = Address::generate(&env); + let recipient = Address::generate(&env); + + StellarAssetClient::new(&env, &token_id).mint(&payer, &500); + env.ledger().set_timestamp(1_000); + + let id = make_invoice(&env, &c, &creator, &recipient, 200, &token_id, 9_999); + + let funded_before = c.get_invoice_funded(&id).expect("should return funded"); + assert_eq!(funded_before, 0); + + c.pay(&payer, &id, &150_i128, &0_u64, &false, &false, &None); + + let funded_after = c.get_invoice_funded(&id).expect("should return funded"); + assert_eq!(funded_after, 150); +} + +#[test] +fn test_get_invoice_funded_not_found() { + let (env, contract_id, _token_id) = setup_initialized(); + let c = client(&env, &contract_id); + + let result = c.try_get_invoice_funded(&999); + assert!(result.is_err()); +} From a7c5200505973a0f70bdf113c932b1d6271a160a Mon Sep 17 00:00:00 2001 From: fejilaup-cloud Date: Thu, 27 Aug 2026 03:47:15 +0000 Subject: [PATCH 3/4] feat: add get_invoice_status view function with test - Add get_invoice_status(invoice_id: u64) -> Result - Loads only the InvoiceHot (or InvoiceCore) struct and returns status field - Returns ContractError::InvoiceNotFound if invoice does not exist - Includes unit tests verifying correct status for Pending and Released invoices - Reduces data fetched and makes intent explicit for clients and integrations Closes #588 --- contracts/split/src/lib.rs | 12 ++++++++++++ contracts/split/src/test.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/contracts/split/src/lib.rs b/contracts/split/src/lib.rs index d5137bb..b91f0ae 100644 --- a/contracts/split/src/lib.rs +++ b/contracts/split/src/lib.rs @@ -4054,6 +4054,18 @@ impl SplitContract { } } + pub fn get_invoice_status(env: Env, invoice_id: u64) -> Result { + if let Some(hot) = env.storage().instance().get(&invoice_hot_key(invoice_id)) { + Ok(hot.status) + } else if let Some(core) = env.storage().persistent().get(&invoice_key(invoice_id)) { + Ok(core.status) + } else if let Some(core) = env.storage().instance().get(&invoice_key(invoice_id)) { + Ok(core.status) + } else { + Err(ContractError::InvoiceNotFound) + } + } + /// Get a consolidated invoice snapshot for off-chain audit. pub fn get_invoice_snapshot(env: Env, invoice_id: u64) -> types::InvoiceSnapshot { let core: types::InvoiceCore = env diff --git a/contracts/split/src/test.rs b/contracts/split/src/test.rs index dd780df..e895a53 100644 --- a/contracts/split/src/test.rs +++ b/contracts/split/src/test.rs @@ -8076,3 +8076,36 @@ fn test_get_invoice_funded_not_found() { let result = c.try_get_invoice_funded(&999); assert!(result.is_err()); } + +#[test] +fn test_get_invoice_status() { + let (env, contract_id, token_id) = setup_initialized(); + let c = client(&env, &contract_id); + let tk = token_client(&env, &token_id); + + let creator = Address::generate(&env); + let payer = Address::generate(&env); + let recipient = Address::generate(&env); + + StellarAssetClient::new(&env, &token_id).mint(&payer, &500); + env.ledger().set_timestamp(1_000); + + let id = make_invoice(&env, &c, &creator, &recipient, 200, &token_id, 9_999); + + let status_pending = c.get_invoice_status(&id).expect("should return status"); + assert_eq!(status_pending, InvoiceStatus::Pending); + + c.pay(&payer, &id, &200_i128, &0_u64, &false, &false, &None); + + let status_released = c.get_invoice_status(&id).expect("should return status"); + assert_eq!(status_released, InvoiceStatus::Released); +} + +#[test] +fn test_get_invoice_status_not_found() { + let (env, contract_id, _token_id) = setup_initialized(); + let c = client(&env, &contract_id); + + let result = c.try_get_invoice_status(&999); + assert!(result.is_err()); +} From 7adaf5f510ad0f650708dfb14a0c2d74f146f313 Mon Sep 17 00:00:00 2001 From: fejilaup-cloud Date: Thu, 27 Aug 2026 03:47:27 +0000 Subject: [PATCH 4/4] test: verify fee_paid event carries correct amount and treasury address - Add test named fee_paid_event_carries_amount_and_treasury in event_log_tests.rs - Generate random treasury address and verify fee_paid event emits correct fields - Assert amount and treasury address match what was passed to fee_paid function - Treasury address is critical for financial auditing Closes #587 --- tests/event_log_tests.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/event_log_tests.rs b/tests/event_log_tests.rs index 4954f84..d5aafe4 100644 --- a/tests/event_log_tests.rs +++ b/tests/event_log_tests.rs @@ -240,6 +240,28 @@ fn test_event_log_with_multiple_recipients() { // Create invoice with 3 recipients // Full fund and release - + // Verify release event includes all 3 recipient addresses } + +#[test] +fn fee_paid_event_carries_amount_and_treasury() { + let env = Env::default(); + env.mock_all_auths(); + + let treasury = Address::generate(&env); + let expected_amount: i128 = 500; + + env.ledger().set_sequence(100); + + split_contracts::events::fee_paid(&env, 1, expected_amount, &treasury); + + let events = env.events().all(); + assert!(!events.is_empty(), "should have at least one event"); + + let fee_paid_event = events.last().expect("should have fee_paid event"); + let (topics, data): (Vec, (i128, Address, u32)) = fee_paid_event.parsed_data(); + + assert_eq!(data.0, expected_amount, "amount should match"); + assert_eq!(data.1, treasury, "treasury should match"); +}