From 880911a9172e3051abb89dc384a278daa31300ba Mon Sep 17 00:00:00 2001 From: afeez Date: Thu, 23 Jul 2026 20:51:03 +0100 Subject: [PATCH 1/4] feat: add emergency protocol pause mechanism --- .github/PULL_REQUEST_TEMPLATE.md | 24 ---- Cargo.lock | 2 + contracts/creditline-contract/src/errors.rs | 1 + contracts/creditline-contract/src/lib.rs | 33 ++++++ contracts/creditline-contract/src/tests.rs | 106 ++++++++++++++++++ contracts/liquidity-pool-contract/Cargo.toml | 1 + .../liquidity-pool-contract/src/errors.rs | 1 + contracts/liquidity-pool-contract/src/lib.rs | 39 ++++++- .../liquidity-pool-contract/src/storage.rs | 9 ++ .../liquidity-pool-contract/src/tests.rs | 53 +++++++++ contracts/parameters-contract/src/errors.rs | 1 + contracts/parameters-contract/src/lib.rs | 11 ++ contracts/parameters-contract/src/storage.rs | 17 ++- contracts/parameters-contract/src/tests.rs | 47 ++++++++ contracts/parameters-contract/src/types.rs | 1 + contracts/reputation-contract/Cargo.toml | 1 + contracts/reputation-contract/src/errors.rs | 1 + contracts/reputation-contract/src/lib.rs | 35 +++++- contracts/reputation-contract/src/storage.rs | 9 ++ contracts/reputation-contract/src/tests.rs | 67 +++++++++++ 20 files changed, 432 insertions(+), 27 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 0b8fbb3..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,24 +0,0 @@ -# Pull Request - -## Description -Brief description of changes made in this PR. - -## Type of Change -- [ ] Bug fix -- [ ] New feature -- [ ] Breaking change -- [ ] Documentation update - -## Changes Made -- List main changes here - -## Testing -- [ ] Tests pass locally -- [ ] New tests added (if applicable) - -## Checklist -- [ ] Code follows project style guidelines -- [ ] Self-review completed -- [ ] Comments added for complex code -- [ ] Documentation updated -- [ ] No new warnings generated diff --git a/Cargo.lock b/Cargo.lock index 75b1290..8f55d2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -813,6 +813,7 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" name = "liquidity-pool-contract" version = "1.0.0" dependencies = [ + "parameters-contract", "soroban-sdk", ] @@ -1026,6 +1027,7 @@ dependencies = [ name = "reputation-contract" version = "1.0.0" dependencies = [ + "parameters-contract", "soroban-sdk", ] diff --git a/contracts/creditline-contract/src/errors.rs b/contracts/creditline-contract/src/errors.rs index 6125165..a65eb78 100644 --- a/contracts/creditline-contract/src/errors.rs +++ b/contracts/creditline-contract/src/errors.rs @@ -32,4 +32,5 @@ pub enum CreditLineError { InvalidLoanStatus = 25, NotInitialized = 26, InvalidDueDate = 27, + Paused = 28, } diff --git a/contracts/creditline-contract/src/lib.rs b/contracts/creditline-contract/src/lib.rs index b549727..540aebf 100644 --- a/contracts/creditline-contract/src/lib.rs +++ b/contracts/creditline-contract/src/lib.rs @@ -72,6 +72,7 @@ impl CreditLineContract { loan_type: LoanType, ) -> Result { user.require_auth(); + Self::require_not_paused(&env)?; Self::validate_guarantee(&env, total_amount, guarantee_amount)?; Self::validate_vendor(&env, &vendor)?; @@ -124,6 +125,7 @@ impl CreditLineContract { loan_type: LoanType, ) -> Result { user.require_auth(); + Self::require_not_paused(&env)?; Self::validate_guarantee(&env, total_amount, guarantee_amount)?; let score = Self::validate_reputation(&env, &user)?; @@ -182,6 +184,7 @@ impl CreditLineContract { let old_admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); old_admin.require_auth(); access::require_admin(&env, &old_admin); + Self::require_not_paused(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); storage::set_admin(&env, &new_admin); } @@ -190,6 +193,7 @@ impl CreditLineContract { pub fn upgrade(env: Env, new_wasm_hash: soroban_sdk::BytesN<32>) { let admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); admin.require_auth(); + Self::require_not_paused(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); // bump stored version and emit event let old_version = storage::get_version(&env).unwrap_or(1u32); @@ -206,24 +210,28 @@ impl CreditLineContract { pub fn set_reputation_contract(env: Env, admin: Address, address: Address) { admin.require_auth(); access::require_admin(&env, &admin); + Self::require_not_paused(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); storage::set_reputation_contract(&env, &address); } pub fn set_vendor_registry(env: Env, admin: Address, address: Address) { admin.require_auth(); access::require_admin(&env, &admin); + Self::require_not_paused(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); storage::set_vendor_registry(&env, &address); } pub fn set_liquidity_pool(env: Env, admin: Address, address: Address) { admin.require_auth(); access::require_admin(&env, &admin); + Self::require_not_paused(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); storage::set_liquidity_pool(&env, &address); } pub fn set_parameters_contract(env: Env, admin: Address, address: Address) { admin.require_auth(); access::require_admin(&env, &admin); + Self::require_not_paused(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); storage::set_parameters_contract(&env, &address); } @@ -484,6 +492,7 @@ impl CreditLineContract { } pub fn mark_defaulted(env: Env, loan_id: u64) -> Result<(), CreditLineError> { + Self::require_not_paused(&env)?; let mut loan = storage::read_loan(&env, loan_id)?; if loan.status != LoanStatus::Active { @@ -561,6 +570,7 @@ impl CreditLineContract { // 1. Admin auth - must be first let admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); admin.require_auth(); + Self::require_not_paused(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); // 2. Load loan — panic if not found let mut loan = @@ -595,6 +605,7 @@ impl CreditLineContract { pub fn cancel_loan(env: Env, caller: Address, loan_id: u64) { caller.require_auth(); + Self::require_not_paused(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); let mut loan = storage::read_loan(&env, loan_id).unwrap_or_else(|err| panic_with_error!(&env, err)); @@ -630,6 +641,7 @@ impl CreditLineContract { amount: i128, ) -> Result { borrower.require_auth(); + Self::require_not_paused(&env)?; let mut loan = storage::read_loan(&env, loan_id)?; @@ -760,6 +772,7 @@ impl CreditLineContract { amount: i128, ) -> Result { borrower.require_auth(); + Self::require_not_paused(&env)?; let mut loan = storage::read_loan(&env, loan_id)?; @@ -896,6 +909,7 @@ impl CreditLineContract { /// `LOANLTFE` event when fees are accrued; is a no-op when no full day has /// elapsed since the last accrual or when no installment is overdue. pub fn apply_late_fees(env: Env, loan_id: u64) -> Result<(), CreditLineError> { + Self::require_not_paused(&env)?; let mut loan = storage::read_loan(&env, loan_id)?; if loan.status != LoanStatus::Active { @@ -937,6 +951,25 @@ impl CreditLineContract { ); } + fn require_not_paused(env: &Env) -> Result<(), CreditLineError> { + match storage::get_parameters_contract(env) + .unwrap_or_else(|err| panic_with_error!(env, err)) + { + Some(address) => { + let paused: bool = env.invoke_contract( + &address, + &Symbol::new(env, "is_paused"), + ().into_val(env), + ); + if paused { + return Err(CreditLineError::Paused); + } + Ok(()) + } + None => Ok(()), + } + } + fn get_protocol_parameters(env: &Env) -> ProtocolParameters { match storage::get_parameters_contract(env) .unwrap_or_else(|err| panic_with_error!(env, err)) diff --git a/contracts/creditline-contract/src/tests.rs b/contracts/creditline-contract/src/tests.rs index b9262f8..ffc7023 100644 --- a/contracts/creditline-contract/src/tests.rs +++ b/contracts/creditline-contract/src/tests.rs @@ -3440,6 +3440,112 @@ fn test_repay_installment_zero_amount_rejected() { t.client.repay_installment(&user, &loan_id, &0, &0); } +// ─── pause ───────────────────────────────────────────────────────────────────── + +struct PauseCtx { + env: Env, + client: CreditLineContractClient<'static>, + admin: Address, + parameters_id: Address, + lp_id: Address, +} + +impl PauseCtx { + fn setup() -> Self { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(CreditLineContract, ()); + let client = CreditLineContractClient::new(&env, &contract_id); + let client: CreditLineContractClient<'static> = unsafe { core::mem::transmute(client) }; + + let admin = Address::generate(&env); + let rep_id = env.register(MockReputation, ()); + let vendor_registry_id = env.register(VendorRegistryContract, ()); + use soroban_sdk::{IntoVal, Symbol}; + let _: Result<(), vendor_registry_contract::VendorRegistryError> = env.invoke_contract( + &vendor_registry_id, + &Symbol::new(&env, "initialize"), + (&admin,).into_val(&env), + ); + let lp_id = env.register(MockLiquidityPool, ()); + let token_admin = Address::generate(&env); + let token_id = env + .register_stellar_asset_contract_v2(token_admin.clone()) + .address(); + client.initialize(&admin, &rep_id, &vendor_registry_id, &lp_id, &token_id); + + let parameters_id = env.register(ParametersContract, ()); + let params_client = ParametersContractClient::new(&env, ¶meters_id); + params_client.initialize_defaults(&admin); + client.set_parameters_contract(&admin, ¶meters_id); + + PauseCtx { + env, + client, + admin, + parameters_id, + lp_id, + } + } +} + +#[test] +fn test_mutating_functions_fail_while_paused() { + let ctx = PauseCtx::setup(); + let params = ParametersContractClient::new(&ctx.env, &ctx.parameters_id); + + // Pause + params.set_paused(&ctx.admin, &true); + + let user = Address::generate(&ctx.env); + let vendor = Address::generate(&ctx.env); + + // create_loan should fail + let due = ctx.env.ledger().timestamp() + 10_000; + let schedule = ctx.single_installment_for(due); + assert_eq!( + ctx.client.try_create_loan( + &user, + &vendor, + &1_000, + &200, + &schedule, + &LoanType::Standard, + ), + Err(Ok(CreditLineError::Paused)) + ); +} + +#[test] +fn test_read_only_functions_continue_while_paused() { + let ctx = PauseCtx::setup(); + let params = ParametersContractClient::new(&ctx.env, &ctx.parameters_id); + + // Pause + params.set_paused(&ctx.admin, &true); + + // get_version should work + assert_eq!(ctx.client.get_version(), 1u32); + + // get_admin should work + assert_eq!(ctx.client.get_admin(), ctx.admin); +} + +// Helper for the PauseCtx since we can't call TestCtx methods directly +impl PauseCtx { + fn single_installment_for(&self, due_date: u64) -> soroban_sdk::Vec { + let mut s = soroban_sdk::Vec::new(&self.env); + s.push_back(RepaymentInstallment { + amount: 1000, + due_date, + paid: false, + paid_at: 0, + }); + s + } +} + #[test] fn test_safe_math_boundaries() { use crate::safe_math; diff --git a/contracts/liquidity-pool-contract/Cargo.toml b/contracts/liquidity-pool-contract/Cargo.toml index 2880292..a9fc262 100644 --- a/contracts/liquidity-pool-contract/Cargo.toml +++ b/contracts/liquidity-pool-contract/Cargo.toml @@ -11,4 +11,5 @@ soroban-sdk = "22.0.0" [dev-dependencies] soroban-sdk = { version = "22.0.0", features = ["testutils"] } +parameters-contract = { path = "../parameters-contract" } diff --git a/contracts/liquidity-pool-contract/src/errors.rs b/contracts/liquidity-pool-contract/src/errors.rs index 219f0d5..587a182 100644 --- a/contracts/liquidity-pool-contract/src/errors.rs +++ b/contracts/liquidity-pool-contract/src/errors.rs @@ -15,4 +15,5 @@ pub enum LiquidityPoolError { NotCreditLine = 9, ZeroTotalShares = 10, ReentrancyDetected = 11, + Paused = 12, } diff --git a/contracts/liquidity-pool-contract/src/lib.rs b/contracts/liquidity-pool-contract/src/lib.rs index 6b89594..2fd66e2 100644 --- a/contracts/liquidity-pool-contract/src/lib.rs +++ b/contracts/liquidity-pool-contract/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -use soroban_sdk::{contract, contractimpl, panic_with_error, token, Address, Env}; +use soroban_sdk::{contract, contractimpl, panic_with_error, token, Address, Env, IntoVal, Symbol}; mod errors; mod events; @@ -50,25 +50,36 @@ impl LiquidityPoolContract { pub fn set_creditline(env: Env, admin: Address, creditline: Address) { admin.require_auth(); Self::require_admin(&env, &admin); + Self::require_not_paused(&env); storage::set_creditline(&env, &creditline); } pub fn set_treasury(env: Env, admin: Address, treasury: Address) { admin.require_auth(); Self::require_admin(&env, &admin); + Self::require_not_paused(&env); storage::set_treasury(&env, &treasury); } pub fn set_merchant_fund(env: Env, admin: Address, merchant_fund: Address) { admin.require_auth(); Self::require_admin(&env, &admin); + Self::require_not_paused(&env); storage::set_merchant_fund(&env, &merchant_fund); } + pub fn set_parameters_contract(env: Env, admin: Address, address: Address) { + admin.require_auth(); + Self::require_admin(&env, &admin); + Self::require_not_paused(&env); + storage::set_parameters_contract(&env, &address); + } + pub fn set_admin(env: Env, new_admin: Address) { let old_admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); old_admin.require_auth(); Self::require_admin(&env, &old_admin); + Self::require_not_paused(&env); storage::set_admin(&env, &new_admin); } @@ -76,6 +87,7 @@ impl LiquidityPoolContract { pub fn upgrade(env: Env, new_wasm_hash: soroban_sdk::BytesN<32>) { let admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err)); admin.require_auth(); + Self::require_not_paused(&env); // bump and persist version let old_version = storage::get_version(&env).unwrap_or(1u32); let new_version = old_version.checked_add(1).unwrap_or(old_version); @@ -106,6 +118,7 @@ impl LiquidityPoolContract { /// Returns the number of shares issued. pub fn deposit(env: Env, provider: Address, amount: i128) -> Result { provider.require_auth(); + Self::require_not_paused(&env); if amount < types::MIN_AMOUNT { return Err(LiquidityPoolError::InvalidAmount); @@ -160,6 +173,7 @@ impl LiquidityPoolContract { /// Returns the number of tokens returned. pub fn withdraw(env: Env, provider: Address, shares: i128) -> Result { provider.require_auth(); + Self::require_not_paused(&env); if shares < types::MIN_AMOUNT { return Err(LiquidityPoolError::InvalidAmount); @@ -225,6 +239,7 @@ impl LiquidityPoolContract { ) -> Result<(), LiquidityPoolError> { creditline.require_auth(); Self::require_creditline(&env, &creditline); + Self::require_not_paused(&env); if amount <= 0 { return Err(LiquidityPoolError::InvalidAmount); @@ -267,6 +282,7 @@ impl LiquidityPoolContract { ) -> Result<(), LiquidityPoolError> { creditline.require_auth(); Self::require_creditline(&env, &creditline); + Self::require_not_paused(&env); if principal < 0 || interest < 0 { return Err(LiquidityPoolError::InvalidAmount); @@ -309,6 +325,7 @@ impl LiquidityPoolContract { ) -> Result<(), LiquidityPoolError> { creditline.require_auth(); Self::require_creditline(&env, &creditline); + Self::require_not_paused(&env); if amount <= 0 { return Err(LiquidityPoolError::InvalidAmount); @@ -349,6 +366,7 @@ impl LiquidityPoolContract { /// This function is called internally by `receive_repayment`, but it is also /// `pub` so that the CreditLine (or admin, in edge-case) can call it directly. pub fn distribute_interest(env: Env, interest_amount: i128) -> Result<(), LiquidityPoolError> { + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); let res = Self::distribute_interest_internal(&env, interest_amount); Self::exit_non_reentrant(&env); @@ -367,6 +385,7 @@ impl LiquidityPoolContract { /// - 10 % → Protocol Treasury /// - 5 % → Merchant Incentive Fund pub fn accumulate_interest(env: Env, interest_amount: i128) -> Result<(), LiquidityPoolError> { + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); let res = Self::distribute_interest_internal(&env, interest_amount); Self::exit_non_reentrant(&env); @@ -517,6 +536,24 @@ impl LiquidityPoolContract { } } + fn require_not_paused(env: &Env) { + match storage::get_parameters_contract(env) + .unwrap_or_else(|err| panic_with_error!(env, err)) + { + Some(address) => { + let paused: bool = env.invoke_contract( + &address, + &Symbol::new(env, "is_paused"), + ().into_val(env), + ); + if paused { + panic_with_error!(env, LiquidityPoolError::Paused); + } + } + None => (), + } + } + fn require_creditline(env: &Env, caller: &Address) { let creditline = storage::get_creditline(env) .unwrap_or_else(|err| panic_with_error!(env, err)) diff --git a/contracts/liquidity-pool-contract/src/storage.rs b/contracts/liquidity-pool-contract/src/storage.rs index 5841059..abe17b9 100644 --- a/contracts/liquidity-pool-contract/src/storage.rs +++ b/contracts/liquidity-pool-contract/src/storage.rs @@ -19,6 +19,7 @@ pub const PERSISTENT_TTL_THRESHOLD: u32 = 1_036_800; pub const PERSISTENT_TTL_EXTEND_TO: u32 = 2_073_600; // Version key (instance storage) pub const VERSION_KEY: Symbol = symbol_short!("VERSION"); +pub const PARAMETERS_KEY: Symbol = symbol_short!("PARAMS"); // --- Admin --- @@ -157,3 +158,11 @@ pub fn get_version(env: &Env) -> Result { pub fn set_version(env: &Env, v: u32) { env.storage().instance().set(&VERSION_KEY, &v); } + +pub fn get_parameters_contract(env: &Env) -> Result, LiquidityPoolError> { + Ok(env.storage().instance().get(&PARAMETERS_KEY)) +} + +pub fn set_parameters_contract(env: &Env, address: &Address) { + env.storage().instance().set(&PARAMETERS_KEY, address); +} diff --git a/contracts/liquidity-pool-contract/src/tests.rs b/contracts/liquidity-pool-contract/src/tests.rs index c2aff34..c9594f4 100644 --- a/contracts/liquidity-pool-contract/src/tests.rs +++ b/contracts/liquidity-pool-contract/src/tests.rs @@ -105,6 +105,59 @@ fn test_initialize_twice_fails() { ); } +// ─── pause ───────────────────────────────────────────────────────────────────── + +#[test] +fn test_pause_defaults_to_false() { + let t = TestEnv::setup(); + let params_id = t.env.register(parameters_contract::ParametersContract, ()); + let params = parameters_contract::ParametersContractClient::new(&t.env, ¶ms_id); + params.initialize_defaults(&t.admin); + t.client.set_parameters_contract(&t.admin, ¶ms_id); + + assert!(!params.is_paused()); +} + +#[test] +fn test_mutating_functions_fail_while_paused() { + let t = TestEnv::setup(); + let params_id = t.env.register(parameters_contract::ParametersContract, ()); + let params = parameters_contract::ParametersContractClient::new(&t.env, ¶ms_id); + params.initialize_defaults(&t.admin); + t.client.set_parameters_contract(&t.admin, ¶ms_id); + + // Pause via params contract + params.set_paused(&t.admin, &true); + + let provider = Address::generate(&t.env); + t.mint(&provider, 1_000); + + // deposit should fail + assert_eq!( + t.client.try_deposit(&provider, &1_000), + Err(Ok(LiquidityPoolError::Paused)) + ); +} + +#[test] +fn test_read_only_functions_continue_while_paused() { + let t = TestEnv::setup(); + let params_id = t.env.register(parameters_contract::ParametersContract, ()); + let params = parameters_contract::ParametersContractClient::new(&t.env, ¶ms_id); + params.initialize_defaults(&t.admin); + t.client.set_parameters_contract(&t.admin, ¶ms_id); + + // Pause + params.set_paused(&t.admin, &true); + + // get_version should work + assert_eq!(t.client.get_version(), 1u32); + + // get_pool_stats should work (read-only) + let stats = t.client.get_pool_stats(); + assert_eq!(stats.total_liquidity, 0); +} + // ─── deposit ────────────────────────────────────────────────────────────────── #[test] diff --git a/contracts/parameters-contract/src/errors.rs b/contracts/parameters-contract/src/errors.rs index ce27739..a10ce4e 100644 --- a/contracts/parameters-contract/src/errors.rs +++ b/contracts/parameters-contract/src/errors.rs @@ -21,4 +21,5 @@ pub enum ParametersError { ProposalAlreadyExecuted = 15, DuplicateSignature = 16, ThresholdNotMet = 17, + Paused = 18, } diff --git a/contracts/parameters-contract/src/lib.rs b/contracts/parameters-contract/src/lib.rs index 837b6bc..44e7eb0 100644 --- a/contracts/parameters-contract/src/lib.rs +++ b/contracts/parameters-contract/src/lib.rs @@ -139,6 +139,7 @@ impl ParametersContract { ProposalAction::SetAdmin(a) => Self::do_set_admin(&env, &a), ProposalAction::Upgrade(h) => Self::do_upgrade(&env, h), ProposalAction::UpdateSigners(c) => Self::do_update_signers(&env, &c), + ProposalAction::SetPaused(paused) => storage::set_paused(&env, paused), } proposal.executed = true; @@ -164,6 +165,16 @@ impl ParametersContract { storage::get_parameters(&env) } + pub fn set_paused(env: Env, admin: Address, paused: bool) { + admin.require_auth(); + access::require_admin(&env, &admin); + storage::set_paused(&env, paused); + } + + pub fn is_paused(env: Env) -> bool { + storage::is_paused(&env) + } + fn do_update_parameters(env: &Env, params: &ProtocolParameters) { Self::validate_parameters(env, params); diff --git a/contracts/parameters-contract/src/storage.rs b/contracts/parameters-contract/src/storage.rs index 177ff59..378329d 100644 --- a/contracts/parameters-contract/src/storage.rs +++ b/contracts/parameters-contract/src/storage.rs @@ -9,6 +9,11 @@ pub const REENTRANCY_LOCK: Symbol = symbol_short!("LOCKED"); pub const VERSION_KEY: Symbol = symbol_short!("VERSION"); pub const MULTISIG_KEY: Symbol = symbol_short!("MSIG"); pub const PROP_CNT_KEY: Symbol = symbol_short!("PROPCNT"); +pub const PAUSED_KEY: Symbol = symbol_short!("PAUSED"); + +// TTL constants (in ledgers — 1 ledger ≈ 5 seconds on mainnet) +pub const PERSISTENT_TTL_THRESHOLD: u32 = 1_036_800; // 60 days +pub const PERSISTENT_TTL_EXTEND_TO: u32 = 2_073_600; // 120 days pub fn has_admin(env: &Env) -> bool { env.storage().instance().has(&ADMIN_KEY) @@ -88,7 +93,17 @@ pub fn get_proposal(env: &Env, id: u64) -> Result { } pub fn set_proposal(env: &Env, proposal: &Proposal) { + let key = DataKey::Proposal(proposal.id); + env.storage().persistent().set(&key, proposal); env.storage() .persistent() - .set(&DataKey::Proposal(proposal.id), proposal); + .extend_ttl(&key, PERSISTENT_TTL_THRESHOLD, PERSISTENT_TTL_EXTEND_TO); +} + +pub fn is_paused(env: &Env) -> bool { + env.storage().instance().get(&PAUSED_KEY).unwrap_or(false) +} + +pub fn set_paused(env: &Env, paused: bool) { + env.storage().instance().set(&PAUSED_KEY, &paused); } diff --git a/contracts/parameters-contract/src/tests.rs b/contracts/parameters-contract/src/tests.rs index 41fd4ed..cf74c62 100644 --- a/contracts/parameters-contract/src/tests.rs +++ b/contracts/parameters-contract/src/tests.rs @@ -285,6 +285,53 @@ fn test_upgrade_via_proposal_increments_version() { assert!(found, "CONTRACTUPGRADED event not found"); } +#[test] +fn test_pause_defaults_to_false() { + let (_env, client, admin) = setup(); + client.initialize_defaults(&admin); + assert!(!client.is_paused()); +} + +#[test] +fn test_admin_can_pause() { + let (_env, client, admin) = setup(); + client.initialize_defaults(&admin); + client.set_paused(&admin, &true); + assert!(client.is_paused()); +} + +#[test] +fn test_admin_can_unpause() { + let (_env, client, admin) = setup(); + client.initialize_defaults(&admin); + client.set_paused(&admin, &true); + assert!(client.is_paused()); + client.set_paused(&admin, &false); + assert!(!client.is_paused()); +} + +#[test] +#[should_panic(expected = "Error(Contract, #2)")] // NotAdmin +fn test_unauthorized_caller_cannot_pause() { + let (env, client, admin) = setup(); + client.initialize_defaults(&admin); + let intruder = Address::generate(&env); + client.set_paused(&intruder, &true); +} + +#[test] +fn test_set_paused_via_proposal() { + let (env, client, _admin, s1, s2, _s3) = setup_multisig(); + + assert!(!client.is_paused()); + + let id = client.propose(&s1, &ProposalAction::SetPaused(true)); + client.approve(&s2, &id); + client.execute(&id); + + assert!(client.is_paused()); +} + #[test] fn test_three_of_three_with_full_committee_approval() { let (env, client, admin) = setup(); diff --git a/contracts/parameters-contract/src/types.rs b/contracts/parameters-contract/src/types.rs index 8d42d23..f11dcea 100644 --- a/contracts/parameters-contract/src/types.rs +++ b/contracts/parameters-contract/src/types.rs @@ -54,6 +54,7 @@ pub enum ProposalAction { SetAdmin(Address), Upgrade(BytesN<32>), UpdateSigners(MultisigConfig), + SetPaused(bool), } #[contracttype] diff --git a/contracts/reputation-contract/Cargo.toml b/contracts/reputation-contract/Cargo.toml index 446cc32..8f3d5ed 100644 --- a/contracts/reputation-contract/Cargo.toml +++ b/contracts/reputation-contract/Cargo.toml @@ -18,6 +18,7 @@ soroban-sdk = "22.0.0" [dev-dependencies] soroban-sdk = { version = "22.0.0", features = ["testutils"] } +parameters-contract = { path = "../parameters-contract" } # OpenZeppelin Testing Helpers (optional) # soroban-test-helpers = { git = "https://github.com/OpenZeppelin/soroban-helpers", branch = "main" } diff --git a/contracts/reputation-contract/src/errors.rs b/contracts/reputation-contract/src/errors.rs index 9685212..df395dc 100644 --- a/contracts/reputation-contract/src/errors.rs +++ b/contracts/reputation-contract/src/errors.rs @@ -12,4 +12,5 @@ pub enum ReputationError { Underflow = 5, NotInitialized = 6, ReentrancyDetected = 7, + Paused = 8, } diff --git a/contracts/reputation-contract/src/lib.rs b/contracts/reputation-contract/src/lib.rs index e125889..7eff8a5 100644 --- a/contracts/reputation-contract/src/lib.rs +++ b/contracts/reputation-contract/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -use soroban_sdk::{contract, contractimpl, symbol_short, Address, Env}; +use soroban_sdk::{contract, contractimpl, symbol_short, Address, Env, IntoVal, Symbol}; // Module imports mod access; @@ -40,6 +40,7 @@ impl ReputationContract { ) -> Result<(), ReputationError> { updater.require_auth(); access::require_updater(&env, &updater); + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); @@ -70,6 +71,7 @@ impl ReputationContract { ) -> Result<(), ReputationError> { updater.require_auth(); access::require_updater(&env, &updater); + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); @@ -91,6 +93,7 @@ impl ReputationContract { pub fn set_score(env: Env, updater: Address, user: Address, new_score: u32) { updater.require_auth(); access::require_updater(&env, &updater); + Self::require_not_paused(&env); if new_score > types::MAX_SCORE { soroban_sdk::panic_with_error!(&env, ReputationError::OutOfBounds); @@ -118,6 +121,7 @@ impl ReputationContract { ) -> Result<(), ReputationError> { updater.require_auth(); access::require_updater(&env, &updater); + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); @@ -148,6 +152,7 @@ impl ReputationContract { ) -> Result<(), ReputationError> { updater.require_auth(); access::require_updater(&env, &updater); + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); @@ -169,6 +174,7 @@ impl ReputationContract { pub fn set_updater(env: Env, admin: Address, updater: Address, allowed: bool) { admin.require_auth(); access::require_admin(&env, &admin); + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); @@ -186,6 +192,13 @@ impl ReputationContract { /// Set the admin address for this contract /// Requires authorization from current admin (or allows initial setup) + pub fn set_parameters_contract(env: Env, admin: Address, address: Address) { + admin.require_auth(); + access::require_admin(&env, &admin); + Self::require_not_paused(&env); + storage::set_parameters_contract(&env, &address); + } + pub fn set_admin(env: Env, new_admin: Address) { let old_admin_opt: Option
= env.storage().instance().get(&storage::ADMIN_KEY); @@ -193,6 +206,7 @@ impl ReputationContract { // Admin exists, require current admin authorization old_admin.require_auth(); access::require_admin(&env, &old_admin); + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); @@ -213,6 +227,7 @@ impl ReputationContract { let admin = storage::get_admin(&env) .unwrap_or_else(|err| soroban_sdk::panic_with_error!(&env, err)); admin.require_auth(); + Self::require_not_paused(&env); Self::enter_non_reentrant(&env); let old = storage::get_version(&env).unwrap_or(1u32); @@ -226,6 +241,24 @@ impl ReputationContract { storage::get_admin(&env) } + fn require_not_paused(env: &Env) { + let params_contract = match storage::get_parameters_contract(env) + .unwrap_or_else(|err| soroban_sdk::panic_with_error!(env, err)) + { + Some(address) => address, + None => return, + }; + + let paused: bool = env.invoke_contract( + ¶ms_contract, + &Symbol::new(env, "is_paused"), + ().into_val(env), + ); + if paused { + soroban_sdk::panic_with_error!(env, ReputationError::Paused); + } + } + fn enter_non_reentrant(env: &Env) { if storage::is_reentrancy_locked(env) .unwrap_or_else(|err| soroban_sdk::panic_with_error!(env, err)) diff --git a/contracts/reputation-contract/src/storage.rs b/contracts/reputation-contract/src/storage.rs index c099f44..2c264e6 100644 --- a/contracts/reputation-contract/src/storage.rs +++ b/contracts/reputation-contract/src/storage.rs @@ -8,6 +8,7 @@ pub const UPDATERS_MAP: Symbol = symbol_short!("UPDATERS"); pub const SCORES_MAP: Symbol = symbol_short!("SCORES"); pub const REENTRANCY_LOCK: Symbol = symbol_short!("LOCKED"); pub const VERSION_KEY: Symbol = symbol_short!("VERSION"); +pub const PARAMETERS_KEY: Symbol = symbol_short!("PARAMS"); /// Get the admin address from storage pub fn get_admin(env: &Env) -> Result { @@ -92,3 +93,11 @@ pub fn get_version(env: &Env) -> Result { pub fn set_version(env: &Env, v: u32) { env.storage().instance().set(&VERSION_KEY, &v); } + +pub fn get_parameters_contract(env: &Env) -> Result, ReputationError> { + Ok(env.storage().instance().get(&PARAMETERS_KEY)) +} + +pub fn set_parameters_contract(env: &Env, address: &Address) { + env.storage().instance().set(&PARAMETERS_KEY, address); +} diff --git a/contracts/reputation-contract/src/tests.rs b/contracts/reputation-contract/src/tests.rs index 8a9b64d..a9b3f78 100644 --- a/contracts/reputation-contract/src/tests.rs +++ b/contracts/reputation-contract/src/tests.rs @@ -52,6 +52,73 @@ fn it_gets_admin() { assert_eq!(retrieved, admin); } +// ─── pause ───────────────────────────────────────────────────────────────────── + +struct PauseTestCtx { + env: Env, + client: ReputationContractClient<'static>, + admin: Address, + params: parameters_contract::ParametersContractClient<'static>, +} + +fn setup_pause() -> PauseTestCtx { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(ReputationContract, ()); + let client = ReputationContractClient::new(&env, &contract_id); + let client: ReputationContractClient<'static> = unsafe { core::mem::transmute(client) }; + let admin = Address::generate(&env); + client.set_admin(&admin); + client.set_updater(&admin, &admin, &true); + + let params_id = env.register(parameters_contract::ParametersContract, ()); + let params = parameters_contract::ParametersContractClient::new(&env, ¶ms_id); + let params: parameters_contract::ParametersContractClient<'static> = + unsafe { core::mem::transmute(params) }; + params.initialize_defaults(&admin); + client.set_parameters_contract(&admin, ¶ms_id); + + PauseTestCtx { + env, + client, + admin, + params, + } +} + +#[test] +fn test_mutating_functions_fail_while_paused() { + let ctx = setup_pause(); + + // Pause + ctx.params.set_paused(&ctx.admin, &true); + + let user = Address::generate(&ctx.env); + + // increase_score should fail + assert_eq!( + ctx.client + .try_increase_score(&ctx.admin, &user, &10u32), + Err(Ok(ReputationError::Paused)) + ); +} + +#[test] +fn test_read_only_functions_continue_while_paused() { + let ctx = setup_pause(); + + // Pause + ctx.params.set_paused(&ctx.admin, &true); + + // get_score should work (read-only) + let user = Address::generate(&ctx.env); + assert_eq!(ctx.client.get_score(&user), 0u32); + + // get_version should work + assert_eq!(ctx.client.get_version(), 1u32); +} + /// Test: Assigns updater permissions #[test] fn it_sets_updater() { From aa8a7d1e5bf8675969d883d6f52557a395cbfb86 Mon Sep 17 00:00:00 2001 From: afeez Date: Thu, 23 Jul 2026 22:00:42 +0100 Subject: [PATCH 2/4] chore: update Cargo.lock --- Cargo.lock | 455 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 304 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f55d2a..8ad6231 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,7 +72,7 @@ dependencies = [ "ark-serialize", "ark-std", "derivative", - "digest", + "digest 0.10.7", "itertools", "num-bigint", "num-traits", @@ -125,7 +125,7 @@ checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-serialize-derive", "ark-std", - "digest", + "digest 0.10.7", "num-bigint", ] @@ -152,9 +152,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base16ct" @@ -189,11 +189,29 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytes-lit" @@ -204,14 +222,14 @@ dependencies = [ "num-bigint", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "cc" -version = "1.2.61" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +checksum = "c89588d05638b5b4594a3348a2d6c20277e43a7f5c5202b05cc56888475a47b8" dependencies = [ "find-msvc-tools", "shlex", @@ -225,9 +243,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "num-traits", @@ -256,6 +274,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crate-git-revision" version = "0.0.6" @@ -285,7 +312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -300,6 +327,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", + "rand_core 0.10.1", +] + [[package]] name = "ctor" version = "0.2.9" @@ -307,7 +344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -317,10 +354,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest", - "fiat-crypto", + "digest 0.10.7", + "fiat-crypto 0.2.9", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "curve25519-dalek-derive", + "digest 0.11.3", + "fiat-crypto 0.3.0", + "rand_core 0.10.1", "rustc_version", "subtle", "zeroize", @@ -334,7 +388,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -368,7 +422,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -381,7 +435,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -392,7 +446,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -403,7 +457,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -428,7 +482,6 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", "serde_core", ] @@ -451,7 +504,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -460,12 +513,22 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", - "crypto-common", + "crypto-common 0.1.6", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -485,10 +548,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest", + "digest 0.10.7", "elliptic-curve", "rfc6979", - "signature", + "signature 2.2.0", ] [[package]] @@ -498,7 +561,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", - "signature", + "signature 2.2.0", +] + +[[package]] +name = "ed25519" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" +dependencies = [ + "signature 3.0.0", ] [[package]] @@ -507,20 +579,35 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "rand_core 0.6.4", "serde", - "sha2", + "sha2 0.10.9", + "subtle", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" +dependencies = [ + "curve25519-dalek 5.0.0", + "ed25519 3.0.0", + "rand_core 0.10.1", + "sha2 0.11.0", + "signature 3.0.0", "subtle", "zeroize", ] [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] name = "elliptic-curve" @@ -530,11 +617,11 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "digest 0.10.7", "ff", "generic-array", "group", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -564,7 +651,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -574,6 +661,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "fiat-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -588,21 +681,21 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" dependencies = [ "futures-core", "futures-task", @@ -641,7 +734,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -662,9 +755,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "hex" @@ -687,7 +780,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", ] [[package]] @@ -738,7 +840,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -766,13 +868,12 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.97" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -785,7 +886,7 @@ dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -794,14 +895,14 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libm" @@ -819,21 +920,21 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -841,9 +942,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-derive" @@ -853,7 +954,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -889,7 +990,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -943,7 +1044,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -957,31 +1058,31 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -991,7 +1092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1003,24 +1104,30 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "ref-cast" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -1052,9 +1159,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "schemars" @@ -1101,9 +1208,9 @@ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -1111,29 +1218,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -1144,11 +1251,12 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.18.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ "base64 0.22.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", @@ -1163,14 +1271,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.18.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1180,8 +1288,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -1190,15 +1309,15 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" dependencies = [ - "digest", + "digest 0.10.7", "keccak", ] [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signature" @@ -1206,8 +1325,17 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", - "rand_core", + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" +dependencies = [ + "rand_core 0.10.1", ] [[package]] @@ -1218,9 +1346,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "soroban-builtin-sdk-macros" @@ -1231,7 +1359,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1273,9 +1401,9 @@ dependencies = [ "ark-ec", "ark-ff", "ark-serialize", - "curve25519-dalek", + "curve25519-dalek 5.0.0", "ecdsa", - "ed25519-dalek", + "ed25519-dalek 3.0.0", "elliptic-curve", "generic-array", "getrandom", @@ -1289,7 +1417,7 @@ dependencies = [ "rand", "rand_chacha", "sec1", - "sha2", + "sha2 0.10.9", "sha3", "soroban-builtin-sdk-macros", "soroban-env-common", @@ -1311,7 +1439,7 @@ dependencies = [ "serde", "serde_json", "stellar-xdr", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1338,7 +1466,7 @@ dependencies = [ "bytes-lit", "ctor", "derive_arbitrary", - "ed25519-dalek", + "ed25519-dalek 2.2.0", "rand", "rustc_version", "serde", @@ -1362,12 +1490,12 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "sha2", + "sha2 0.10.9", "soroban-env-common", "soroban-spec", "soroban-spec-rust", "stellar-xdr", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1391,10 +1519,10 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "sha2", + "sha2 0.10.9", "soroban-spec", "stellar-xdr", - "syn 2.0.117", + "syn 2.0.119", "thiserror", ] @@ -1413,9 +1541,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" [[package]] name = "spki" @@ -1485,9 +1613,20 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -1511,17 +1650,16 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "time" -version = "0.3.47" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde_core", @@ -1531,25 +1669,40 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", ] +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-ident" @@ -1585,9 +1738,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.120" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -1598,9 +1751,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.120" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1608,22 +1761,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.120" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.120" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] @@ -1686,7 +1839,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1697,7 +1850,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1726,46 +1879,46 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" From d41604ed50dc253f28c76aadbea133a3859a2b1f Mon Sep 17 00:00:00 2001 From: afeez Date: Thu, 23 Jul 2026 23:23:28 +0100 Subject: [PATCH 3/4] fix(parameters): add missing set_paused/is_paused to storage, remove duplicate constants --- contracts/parameters-contract/src/storage.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/contracts/parameters-contract/src/storage.rs b/contracts/parameters-contract/src/storage.rs index 4f3dd0a..99f6fe3 100644 --- a/contracts/parameters-contract/src/storage.rs +++ b/contracts/parameters-contract/src/storage.rs @@ -15,10 +15,6 @@ pub const PAUSED_KEY: Symbol = symbol_short!("PAUSED"); pub const PERSISTENT_TTL_THRESHOLD: u32 = 1_036_800; // 60 days pub const PERSISTENT_TTL_EXTEND_TO: u32 = 2_073_600; // 120 days -// TTL constants (in ledgers — 1 ledger ≈ 5 seconds on mainnet) -pub const PERSISTENT_TTL_THRESHOLD: u32 = 1_036_800; // 60 days -pub const PERSISTENT_TTL_EXTEND_TO: u32 = 2_073_600; // 120 days - pub fn has_admin(env: &Env) -> bool { env.storage().instance().has(&ADMIN_KEY) } @@ -103,3 +99,11 @@ pub fn set_proposal(env: &Env, proposal: &Proposal) { .persistent() .extend_ttl(&key, PERSISTENT_TTL_THRESHOLD, PERSISTENT_TTL_EXTEND_TO); } + +pub fn set_paused(env: &Env, paused: bool) { + env.storage().instance().set(&PAUSED_KEY, &paused); +} + +pub fn is_paused(env: &Env) -> bool { + env.storage().instance().get(&PAUSED_KEY).unwrap_or(false) +} From d402d916f4dcd48ff1ccfd7b275311e33d758f1a Mon Sep 17 00:00:00 2001 From: afeez Date: Wed, 29 Jul 2026 08:57:12 +0100 Subject: [PATCH 4/4] fix(lp): calculate_withdrawal returns 0 for empty pool (fixes CI) --- Cargo.lock | 192 ++++--------------- contracts/liquidity-pool-contract/src/lib.rs | 4 +- 2 files changed, 39 insertions(+), 157 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ad6231..7830860 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,7 +72,7 @@ dependencies = [ "ark-serialize", "ark-std", "derivative", - "digest 0.10.7", + "digest", "itertools", "num-bigint", "num-traits", @@ -125,7 +125,7 @@ checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-serialize-derive", "ark-std", - "digest 0.10.7", + "digest", "num-bigint", ] @@ -189,15 +189,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-buffer" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" -dependencies = [ - "hybrid-array", -] - [[package]] name = "bs58" version = "0.5.1" @@ -274,15 +265,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - [[package]] name = "crate-git-revision" version = "0.0.6" @@ -312,7 +294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -327,16 +309,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", - "rand_core 0.10.1", -] - [[package]] name = "ctor" version = "0.2.9" @@ -354,27 +326,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", - "curve25519-dalek-derive", - "digest 0.10.7", - "fiat-crypto 0.2.9", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", + "cpufeatures", "curve25519-dalek-derive", - "digest 0.11.3", - "fiat-crypto 0.3.0", - "rand_core 0.10.1", + "digest", + "fiat-crypto", "rustc_version", "subtle", "zeroize", @@ -513,22 +468,12 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "const-oid", - "crypto-common 0.1.6", + "crypto-common", "subtle", ] -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer 0.12.1", - "crypto-common 0.2.2", -] - [[package]] name = "downcast-rs" version = "1.2.1" @@ -548,10 +493,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest 0.10.7", + "digest", "elliptic-curve", "rfc6979", - "signature 2.2.0", + "signature", ] [[package]] @@ -561,16 +506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", - "signature 2.2.0", -] - -[[package]] -name = "ed25519" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" -dependencies = [ - "signature 3.0.0", + "signature", ] [[package]] @@ -579,26 +515,11 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519 2.2.3", - "rand_core 0.6.4", + "curve25519-dalek", + "ed25519", + "rand_core", "serde", - "sha2 0.10.9", - "subtle", - "zeroize", -] - -[[package]] -name = "ed25519-dalek" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" -dependencies = [ - "curve25519-dalek 5.0.0", - "ed25519 3.0.0", - "rand_core 0.10.1", - "sha2 0.11.0", - "signature 3.0.0", + "sha2", "subtle", "zeroize", ] @@ -617,11 +538,11 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.7", + "digest", "ff", "generic-array", "group", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", @@ -651,7 +572,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -661,12 +582,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "fiat-crypto" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" - [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -734,7 +649,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -780,16 +695,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "hybrid-array" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" -dependencies = [ - "typenum", + "digest", ] [[package]] @@ -886,7 +792,7 @@ dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "sha2 0.10.9", + "sha2", ] [[package]] @@ -895,7 +801,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures 0.2.17", + "cpufeatures", ] [[package]] @@ -990,7 +896,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.9", + "sha2", ] [[package]] @@ -1082,7 +988,7 @@ checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -1092,7 +998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -1104,12 +1010,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - [[package]] name = "ref-cast" version = "1.0.26" @@ -1288,19 +1188,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", + "cpufeatures", + "digest", ] [[package]] @@ -1309,7 +1198,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" dependencies = [ - "digest 0.10.7", + "digest", "keccak", ] @@ -1325,17 +1214,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - -[[package]] -name = "signature" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" -dependencies = [ - "rand_core 0.10.1", + "digest", + "rand_core", ] [[package]] @@ -1401,9 +1281,9 @@ dependencies = [ "ark-ec", "ark-ff", "ark-serialize", - "curve25519-dalek 5.0.0", + "curve25519-dalek", "ecdsa", - "ed25519-dalek 3.0.0", + "ed25519-dalek", "elliptic-curve", "generic-array", "getrandom", @@ -1417,7 +1297,7 @@ dependencies = [ "rand", "rand_chacha", "sec1", - "sha2 0.10.9", + "sha2", "sha3", "soroban-builtin-sdk-macros", "soroban-env-common", @@ -1466,7 +1346,7 @@ dependencies = [ "bytes-lit", "ctor", "derive_arbitrary", - "ed25519-dalek 2.2.0", + "ed25519-dalek", "rand", "rustc_version", "serde", @@ -1490,7 +1370,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "sha2 0.10.9", + "sha2", "soroban-env-common", "soroban-spec", "soroban-spec-rust", @@ -1519,7 +1399,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "sha2 0.10.9", + "sha2", "soroban-spec", "stellar-xdr", "syn 2.0.119", diff --git a/contracts/liquidity-pool-contract/src/lib.rs b/contracts/liquidity-pool-contract/src/lib.rs index c937f92..a1118b6 100644 --- a/contracts/liquidity-pool-contract/src/lib.rs +++ b/contracts/liquidity-pool-contract/src/lib.rs @@ -571,6 +571,7 @@ impl LiquidityPoolContract { } /// Calculate how many tokens `shares` are worth at the current share price. + /// Returns 0 if the pool is empty (no shares issued). pub fn calculate_withdrawal(env: Env, shares: i128) -> i128 { if shares == 0 { return 0; @@ -579,7 +580,8 @@ impl LiquidityPoolContract { if total_shares == 0 { return 0; } - let share_price = Self::calculate_share_price_internal(&env).unwrap_or(types::SHARE_PRICE_PRECISION); + let share_price = Self::calculate_share_price_internal(&env) + .unwrap_or(types::SHARE_PRICE_PRECISION); safe_math::div_i128( safe_math::mul_i128(shares, share_price).unwrap_or(0), types::SHARE_PRICE_PRECISION,