diff --git a/reporting/README.md b/reporting/README.md index c636b7c3..050613e4 100644 --- a/reporting/README.md +++ b/reporting/README.md @@ -9,7 +9,6 @@ Aggregates financial health data from the remittance_split, savings_goals, bill_ - Admin-only archival and cleanup of old reports - Storage TTL management (instance: ~30 days, archive: ~180 days) -<<<<<<< feature/reporting-address-config-integrity ## Dependency contract address integrity Reporting stores five downstream contract IDs (`remittance_split`, `savings_goals`, @@ -18,8 +17,8 @@ Reporting stores five downstream contract IDs (`remittance_split`, `savings_goal **Validation (on every `configure_addresses` call)**: - **No self-reference** — None of the five addresses may equal the reporting - contract’s own address. Pointing a role at this contract would create ambiguous - cross-contract calls and break the intended “one deployment per role” model. + contract's own address. Pointing a role at this contract would create ambiguous + cross-contract calls and break the intended "one deployment per role" model. - **Pairwise uniqueness** — All five values must differ. Two roles must not share the same contract ID, or aggregation would silently read the wrong deployment twice (audit and correctness risk). @@ -38,11 +37,10 @@ is rejected. its role (that requires off-chain governance / deployment manifests). It only enforces **structural** integrity: distinct callees and no reporting self-loop. -- Soroban/Stellar contract IDs are not an EVM-style “zero address”; “malformed” +- Soroban/Stellar contract IDs are not an EVM-style "zero address"; "malformed" in this layer means duplicate or self-reference as above. -======= + ## Quickstart ->>>>>>> main ```rust // 1. Initialize diff --git a/reporting/src/tests.rs b/reporting/src/tests.rs index bb06b794..f2c4b2a9 100644 --- a/reporting/src/tests.rs +++ b/reporting/src/tests.rs @@ -1,5 +1,6 @@ use soroban_sdk::testutils::storage::Instance as StorageInstance; use soroban_sdk::{ + symbol_short, testutils::{Address as _, Ledger, LedgerInfo}, Address, Env, }; @@ -470,6 +471,78 @@ fn test_verify_dependency_address_set_rejects_self_reference() { )); } +#[test] +fn test_verify_dependency_address_set_does_not_write_storage() { + let env = create_test_env(); + let contract_id = env.register_contract(None, ReportingContract); + let client = ReportingContractClient::new(&env, &contract_id); + let admin = Address::generate(&env); + client.init(&admin); + + let addrs = ContractAddresses { + remittance_split: Address::generate(&env), + savings_goals: Address::generate(&env), + bill_payments: Address::generate(&env), + insurance: Address::generate(&env), + family_wallet: Address::generate(&env), + }; + + let _ = client.try_verify_dependency_address_set(&addrs); + + let instance_snapshot: Option
= env.storage().instance().get(&symbol_short!("ADMIN")); + assert!(instance_snapshot.is_some(), "ADMIN should still exist"); + + let stored_addrs: Option