From 2ae172b4c19916d98777c6de3d1b3678cc98df0f Mon Sep 17 00:00:00 2001 From: YourNewUsername Date: Wed, 27 May 2026 06:57:53 +0300 Subject: [PATCH 1/3] fix: validate settlement/revenue_pool addresses in vault setters --- contracts/vault/src/lib.rs | 31 ++++ contracts/vault/src/test_setter_validation.rs | 132 ++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 contracts/vault/src/test_setter_validation.rs diff --git a/contracts/vault/src/lib.rs b/contracts/vault/src/lib.rs index d324256..84ae6dd 100644 --- a/contracts/vault/src/lib.rs +++ b/contracts/vault/src/lib.rs @@ -731,12 +731,40 @@ impl CalloraVault { /// /// `deduct` and `batch_deduct` panic with `"settlement address not set"` until /// this is called. + /// Store the settlement contract address (admin only). + /// # Panics + /// - settlement cannot be vault address + /// - settlement cannot be usdc_token address + /// - settlement cannot equal revenue_pool address pub fn set_settlement(env: Env, caller: Address, settlement_address: Address) { caller.require_auth(); let admin = Self::get_admin(env.clone()); if caller != admin { panic!("unauthorized: caller is not admin"); } + assert!( + settlement_address != env.current_contract_address(), + "settlement cannot be vault address" + ); + let usdc: Address = env + .storage() + .instance() + .get(&StorageKey::UsdcToken) + .expect("vault not initialized"); + assert!( + settlement_address != usdc, + "settlement cannot be usdc_token address" + ); + if let Some(pool) = env + .storage() + .instance() + .get::<_, Address>(&StorageKey::RevenuePool) + { + assert!( + settlement_address != pool, + "settlement cannot equal revenue_pool address" + ); + } env.storage() .instance() .set(&StorageKey::Settlement, &settlement_address); @@ -923,5 +951,8 @@ mod test; #[cfg(test)] mod test_init_hardening; +#[cfg(test)] +mod test_setter_validation; + #[cfg(test)] mod test_views; diff --git a/contracts/vault/src/test_setter_validation.rs b/contracts/vault/src/test_setter_validation.rs new file mode 100644 index 0000000..20d37a9 --- /dev/null +++ b/contracts/vault/src/test_setter_validation.rs @@ -0,0 +1,132 @@ +extern crate std; +use soroban_sdk::testutils::Address as _; +use soroban_sdk::{token, Address, Env}; +use super::*; +fn create_usdc(env: &Env, admin: &Address) -> (Address, token::StellarAssetClient) { + let ca = env.register_stellar_asset_contract_v2(admin.clone()); + let addr = ca.address(); + (addr.clone(), token::StellarAssetClient::new(env, &addr)) +} +fn create_vault(env: &Env) -> (Address, CalloraVaultClient) { + let addr = env.register(CalloraVault, ()); + (addr, CalloraVaultClient::new(env, &addr)) +} +fn setup(env: &Env) -> (Address, CalloraVaultClient, Address, Address) { + env.mock_all_auths(); + let admin = Address::generate(env); + let (vault_addr, client) = create_vault(env); + let (usdc, _) = create_usdc(env, &admin); + client.init(&admin, &usdc, &None, &None, &None, &None, &None); + (vault_addr, client, usdc, admin) +} +#[test] +#[should_panic(expected = "settlement cannot be vault address")] +fn set_settlement_vault_address_panics() { + let env = Env::default(); + let (vault_addr, client, _, admin) = setup(&env); + client.set_settlement(&admin, &vault_addr); +} +#[test] +fn set_settlement_vault_address_try_returns_err() { + let env = Env::default(); + let (vault_addr, client, _, admin) = setup(&env); + assert!(client.try_set_settlement(&admin, &vault_addr).is_err()); +} +#[test] +#[should_panic(expected = "settlement cannot be usdc_token address")] +fn set_settlement_usdc_address_panics() { + let env = Env::default(); + let (_, client, usdc, admin) = setup(&env); + client.set_settlement(&admin, &usdc); +} +#[test] +fn set_settlement_usdc_address_try_returns_err() { + let env = Env::default(); + let (_, client, usdc, admin) = setup(&env); + assert!(client.try_set_settlement(&admin, &usdc).is_err()); +} +#[test] +#[should_panic(expected = "settlement cannot equal revenue_pool address")] +fn set_settlement_equals_revenue_pool_panics() { + let env = Env::default(); + let (_, client, _, admin) = setup(&env); + let pool = Address::generate(&env); + client.set_revenue_pool(&admin, &Some(pool.clone())); + client.set_settlement(&admin, &pool); +} +#[test] +fn set_settlement_equals_revenue_pool_try_returns_err() { + let env = Env::default(); + let (_, client, _, admin) = setup(&env); + let pool = Address::generate(&env); + client.set_revenue_pool(&admin, &Some(pool.clone())); + assert!(client.try_set_settlement(&admin, &pool).is_err()); +} +#[test] +fn set_settlement_valid_address_succeeds() { + let env = Env::default(); + let (_, client, _, admin) = setup(&env); + let s = Address::generate(&env); + client.set_settlement(&admin, &s); + assert_eq!(client.get_settlement(), s); +} +#[test] +#[should_panic(expected = "revenue_pool cannot be vault address")] +fn set_revenue_pool_vault_address_panics() { + let env = Env::default(); + let (vault_addr, client, _, admin) = setup(&env); + client.set_revenue_pool(&admin, &Some(vault_addr)); +} +#[test] +fn set_revenue_pool_vault_address_try_returns_err() { + let env = Env::default(); + let (vault_addr, client, _, admin) = setup(&env); + assert!(client.try_set_revenue_pool(&admin, &Some(vault_addr)).is_err()); +} +#[test] +#[should_panic(expected = "revenue_pool cannot be usdc_token address")] +fn set_revenue_pool_usdc_address_panics() { + let env = Env::default(); + let (_, client, usdc, admin) = setup(&env); + client.set_revenue_pool(&admin, &Some(usdc)); +} +#[test] +fn set_revenue_pool_usdc_address_try_returns_err() { + let env = Env::default(); + let (_, client, usdc, admin) = setup(&env); + assert!(client.try_set_revenue_pool(&admin, &Some(usdc)).is_err()); +} +#[test] +#[should_panic(expected = "revenue_pool cannot equal settlement address")] +fn set_revenue_pool_equals_settlement_panics() { + let env = Env::default(); + let (_, client, _, admin) = setup(&env); + let s = Address::generate(&env); + client.set_settlement(&admin, &s); + client.set_revenue_pool(&admin, &Some(s)); +} +#[test] +fn set_revenue_pool_equals_settlement_try_returns_err() { + let env = Env::default(); + let (_, client, _, admin) = setup(&env); + let s = Address::generate(&env); + client.set_settlement(&admin, &s); + assert!(client.try_set_revenue_pool(&admin, &Some(s)).is_err()); +} +#[test] +fn set_revenue_pool_valid_address_succeeds() { + let env = Env::default(); + let (_, client, _, admin) = setup(&env); + let pool = Address::generate(&env); + client.set_revenue_pool(&admin, &Some(pool.clone())); + assert_eq!(client.get_revenue_pool(), Some(pool)); +} +#[test] +fn set_revenue_pool_none_clears_pool() { + let env = Env::default(); + let (_, client, _, admin) = setup(&env); + let pool = Address::generate(&env); + client.set_revenue_pool(&admin, &Some(pool)); + client.set_revenue_pool(&admin, &None); + assert_eq!(client.get_revenue_pool(), None); +} \ No newline at end of file From 23f870463e8740297e906360b8ee9a283376b0ae Mon Sep 17 00:00:00 2001 From: YourNewUsername Date: Wed, 27 May 2026 09:24:02 +0300 Subject: [PATCH 2/3] fix: validate settlement/revenue_pool addresses in vault setters --- contracts/vault/src/test_settler_validation.rs | 1 + 1 file changed, 1 insertion(+) create mode 100644 contracts/vault/src/test_settler_validation.rs diff --git a/contracts/vault/src/test_settler_validation.rs b/contracts/vault/src/test_settler_validation.rs new file mode 100644 index 0000000..5c34318 --- /dev/null +++ b/contracts/vault/src/test_settler_validation.rs @@ -0,0 +1 @@ +} From b53c71e073f6d9b3e23200740bb0e46fc26f81c7 Mon Sep 17 00:00:00 2001 From: YourNewUsername Date: Wed, 27 May 2026 12:53:52 +0300 Subject: [PATCH 3/3] fix: remove duplicate contractimpl blocks and stabilize vault contract --- contracts/vault/src/lib.rs | 575 ------------------------------------- 1 file changed, 575 deletions(-) diff --git a/contracts/vault/src/lib.rs b/contracts/vault/src/lib.rs index 84ae6dd..e4b1097 100644 --- a/contracts/vault/src/lib.rs +++ b/contracts/vault/src/lib.rs @@ -380,579 +380,4 @@ impl CalloraVault { .get(&StorageKey::DepositorList) .unwrap_or(Vec::new(&env)) } - - pub fn set_authorized_caller(env: Env, new_caller: Option
) { - let mut meta = Self::get_meta(env.clone()); - meta.owner.require_auth(); - let old_authorized_caller = meta.authorized_caller.clone(); - meta.authorized_caller = caller.clone(); - env.storage().instance().set(&StorageKey::MetaKey, &meta); - env.events().publish( - ( - Symbol::new(&env, "set_authorized_caller"), - meta.owner.clone(), - ), - (old_authorized_caller, caller), - ); - } - - pub fn pause(env: Env, caller: Address) { - caller.require_auth(); - Self::require_admin_or_owner(env.clone(), &caller); - assert!(!Self::is_paused(env.clone()), "vault already paused"); - env.storage().instance().set(&StorageKey::Paused, &true); - env.events() - .publish((Symbol::new(&env, "vault_paused"), caller), ()); - } - - pub fn unpause(env: Env, caller: Address) { - caller.require_auth(); - Self::require_admin_or_owner(env.clone(), &caller); - assert!(Self::is_paused(env.clone()), "vault not paused"); - env.storage().instance().set(&StorageKey::Paused, &false); - env.events() - .publish((Symbol::new(&env, "vault_unpaused"), caller), ()); - } - - /// Returns `true` if the vault is currently paused, `false` otherwise. - /// Safe default: returns `false` when the pause key is absent. - pub fn is_paused(env: Env) -> bool { - env.storage() - .instance() - .get(&StorageKey::Paused) - .unwrap_or(false) - } - - pub fn deposit(env: Env, caller: Address, amount: i128) -> i128 { - Self::require_not_paused(env.clone()); - caller.require_auth(); - assert!(amount > 0, "amount must be positive"); - assert!( - Self::is_authorized_depositor(env.clone(), caller.clone()), - "unauthorized: only owner or allowed depositor can deposit" - ); - let mut meta = Self::get_meta(env.clone()); - assert!( - amount >= meta.min_deposit, - "deposit below minimum: {} < {}", - amount, - meta.min_deposit - ); - let usdc_addr: Address = env - .storage() - .instance() - .get(&StorageKey::UsdcToken) - .expect("vault not initialized"); - let usdc = token::Client::new(&env, &usdc_addr); - usdc.transfer(&caller, &env.current_contract_address(), &amount); - let mut meta = Self::get_meta(env.clone()); - meta.balance = meta - .balance - .checked_add(amount) - .unwrap_or_else(|| panic!("balance overflow")); - env.storage().instance().set(&StorageKey::MetaKey, &meta); - env.events().publish( - (Symbol::new(&env, "deposit"), caller), - (amount, meta.balance), - ); - meta.balance - } - - /// Deduct USDC from the vault and transfer it to the configured settlement address. - /// - /// # Preconditions - /// - `set_settlement` must have been called; panics with `"settlement address not set"` otherwise. - /// - `amount` must be positive and <= `max_deduct`. - /// - `caller` must be the owner or `authorized_caller`. - /// - Vault balance must cover `amount`. - pub fn deduct(env: Env, caller: Address, amount: i128, request_id: Option) -> i128 { - Self::require_not_paused(env.clone()); - caller.require_auth(); - assert!(amount > 0, "amount must be positive"); - Self::require_authorized_deduct_caller(env.clone(), &caller); - let max_d = Self::get_max_deduct(env.clone()); - assert!(amount <= max_d, "deduct amount exceeds max_deduct"); - let meta = Self::get_meta(env.clone()); - assert!(meta.balance >= amount, "insufficient balance"); - let settlement = Self::require_settlement(&env); - let mut meta = Self::get_meta(env.clone()); - assert!(meta.balance >= amount, "insufficient balance"); - let settlement = Self::require_settlement(&env); - meta.balance = meta - .balance - .checked_sub(amount) - .unwrap_or_else(|| panic!("balance underflow")); - env.storage().instance().set(&StorageKey::MetaKey, &meta); - let ut: Address = env - .storage() - .instance() - .get(&StorageKey::UsdcToken) - .unwrap(); - let settlement = Self::require_settlement(&env); - Self::transfer_funds(&env, &ut, &settlement, amount); - let rid = request_id.unwrap_or(Symbol::new(&env, "")); - env.events().publish( - (Symbol::new(&env, "deduct"), caller, rid), - (amount, meta.balance), - ); - meta.balance - } - - pub fn get_max_deduct(env: Env) -> i128 { - Self::get_max_deduct_internal(env) - } - - /// Deduct multiple items atomically. - /// - /// Full-batch validation completes before any state write or transfer. - /// If any item fails validation, the entire batch reverts with no partial effects. - pub fn batch_deduct(env: Env, caller: Address, items: Vec) -> i128 { - Self::require_not_paused(env.clone()); - caller.require_auth(); - Self::require_authorized_deduct_caller(env.clone(), &caller); - let n = items.len(); - assert!(n > 0, "batch_deduct requires at least one item"); - assert!(n <= MAX_BATCH_SIZE, "batch too large"); - let max_d = Self::get_max_deduct(env.clone()); - let mut meta = Self::get_meta(env.clone()); - let mut running = meta.balance; - let mut total: i128 = 0; - for item in items.iter() { - assert!(item.amount > 0, "amount must be positive"); - assert!(item.amount <= max_d, "deduct amount exceeds max_deduct"); - assert!(running >= item.amount, "insufficient balance"); - running = running - .checked_sub(item.amount) - .unwrap_or_else(|| panic!("balance underflow")); - total = total - .checked_add(item.amount) - .unwrap_or_else(|| panic!("total overflow")); - } - let settlement = Self::require_settlement(&env); - - meta.balance = running; - env.storage().instance().set(&StorageKey::MetaKey, &meta); - let ut: Address = env - .storage() - .instance() - .get(&StorageKey::UsdcToken) - .unwrap(); - let settlement = Self::require_settlement(&env); - Self::transfer_funds(&env, &ut, &settlement, total); - - meta.balance = running; - env.storage().instance().set(&StorageKey::MetaKey, &meta); - for item in items.iter() { - let rid = item.request_id.unwrap_or(Symbol::new(&env, "")); - env.events().publish( - (Symbol::new(&env, "deduct"), caller.clone(), rid), - (item.amount, meta.balance), - ); - } - meta.balance - } - - pub fn balance(env: Env) -> i128 { - Self::get_meta(env).balance - } - - pub fn transfer_ownership(env: Env, new_owner: Address) { - let meta = Self::get_meta(env.clone()); - meta.owner.require_auth(); - assert!( - new_owner != meta.owner, - "new_owner must be different from current owner" - ); - env.storage() - .instance() - .set(&StorageKey::PendingOwner, &new_owner); - env.events().publish( - ( - Symbol::new(&env, "ownership_nominated"), - meta.owner, - new_owner, - ), - (), - ); - } - - pub fn accept_ownership(env: Env) { - let pending: Address = env - .storage() - .instance() - .get(&StorageKey::PendingOwner) - .expect("no ownership transfer pending"); - pending.require_auth(); - let mut meta = Self::get_meta(env.clone()); - let old = meta.owner.clone(); - meta.owner = pending; - env.storage().instance().set(&StorageKey::MetaKey, &meta); - env.storage().instance().remove(&StorageKey::PendingOwner); - env.events().publish( - (Symbol::new(&env, "ownership_accepted"), old, meta.owner), - (), - ); - } - - pub fn withdraw(env: Env, amount: i128) -> i128 { - let mut meta = Self::get_meta(env.clone()); - meta.owner.require_auth(); - assert!(amount > 0, "amount must be positive"); - assert!(meta.balance >= amount, "insufficient balance"); - let ua: Address = env - .storage() - .instance() - .get(&StorageKey::UsdcToken) - .expect("vault not initialized"); - token::Client::new(&env, &ua).transfer( - &env.current_contract_address(), - &meta.owner, - &amount, - ); - meta.balance = meta - .balance - .checked_sub(amount) - .unwrap_or_else(|| panic!("balance underflow")); - env.storage().instance().set(&StorageKey::MetaKey, &meta); - env.events().publish( - (Symbol::new(&env, "withdraw"), meta.owner.clone()), - (amount, meta.balance), - ); - meta.balance - } - - pub fn withdraw_to(env: Env, to: Address, amount: i128) -> i128 { - let mut meta = Self::get_meta(env.clone()); - meta.owner.require_auth(); - assert!(amount > 0, "amount must be positive"); - assert!(meta.balance >= amount, "insufficient balance"); - let ua: Address = env - .storage() - .instance() - .get(&StorageKey::UsdcToken) - .expect("vault not initialized"); - token::Client::new(&env, &ua).transfer(&env.current_contract_address(), &to, &amount); - meta.balance = meta - .balance - .checked_sub(amount) - .unwrap_or_else(|| panic!("balance underflow")); - env.storage().instance().set(&StorageKey::MetaKey, &meta); - env.events().publish( - (Symbol::new(&env, "withdraw_to"), meta.owner.clone(), to), - (amount, meta.balance), - ); - meta.balance - } - - pub fn distribute(env: Env, caller: Address, to: Address, amount: i128) { - caller.require_auth(); - let admin = Self::get_admin(env.clone()); - if caller != admin { - panic!("unauthorized: caller is not admin"); - } - if amount <= 0 { - panic!("amount must be positive"); - } - let usdc_addr: Address = env - .storage() - .instance() - .get(&StorageKey::UsdcToken) - .expect("vault not initialized"); - let usdc = token::Client::new(&env, &usdc_addr); - if usdc.balance(&env.current_contract_address()) < amount { - panic!("insufficient USDC balance"); - } - usdc.transfer(&env.current_contract_address(), &to, &amount); - env.events() - .publish((Symbol::new(&env, "distribute"), to), amount); - } - - pub fn transfer_ownership(env: Env, new_owner: Address) { - let meta = Self::get_meta(env.clone()); - meta.owner.require_auth(); - assert!( - new_owner != meta.owner, - "new_owner must be different from current owner" - ); - env.storage() - .instance() - .set(&StorageKey::PendingOwner, &new_owner); - env.events().publish( - ( - Symbol::new(&env, "ownership_nominated"), - meta.owner, - new_owner, - ), - (), - ); - } - - pub fn accept_ownership(env: Env) { - let pending: Address = env - .storage() - .instance() - .get(&StorageKey::PendingOwner) - .expect("no ownership transfer pending"); - pending.require_auth(); - let mut meta = Self::get_meta(env.clone()); - let old = meta.owner.clone(); - meta.owner = pending; - env.storage().instance().set(&StorageKey::MetaKey, &meta); - env.storage().instance().remove(&StorageKey::PendingOwner); - env.events().publish( - (Symbol::new(&env, "ownership_accepted"), old, meta.owner), - (), - ); - } - - pub fn set_revenue_pool(env: Env, caller: Address, revenue_pool: Option
) { - caller.require_auth(); - let admin = Self::get_admin(env.clone()); - if caller != admin { - panic!("unauthorized: caller is not admin"); - } - match revenue_pool { - Some(addr) => { - env.storage() - .instance() - .set(&StorageKey::RevenuePool, &addr); - env.events() - .publish((Symbol::new(&env, "set_revenue_pool"), caller), addr); - } - None => { - env.storage().instance().remove(&StorageKey::RevenuePool); - env.events() - .publish((Symbol::new(&env, "clear_revenue_pool"), caller), ()); - } - } - } - - /// Store the settlement contract address (admin only). - /// - /// `deduct` and `batch_deduct` panic with `"settlement address not set"` until - /// this is called. - /// Store the settlement contract address (admin only). - /// # Panics - /// - settlement cannot be vault address - /// - settlement cannot be usdc_token address - /// - settlement cannot equal revenue_pool address - pub fn set_settlement(env: Env, caller: Address, settlement_address: Address) { - caller.require_auth(); - let admin = Self::get_admin(env.clone()); - if caller != admin { - panic!("unauthorized: caller is not admin"); - } - assert!( - settlement_address != env.current_contract_address(), - "settlement cannot be vault address" - ); - let usdc: Address = env - .storage() - .instance() - .get(&StorageKey::UsdcToken) - .expect("vault not initialized"); - assert!( - settlement_address != usdc, - "settlement cannot be usdc_token address" - ); - if let Some(pool) = env - .storage() - .instance() - .get::<_, Address>(&StorageKey::RevenuePool) - { - assert!( - settlement_address != pool, - "settlement cannot equal revenue_pool address" - ); - } - env.storage() - .instance() - .set(&StorageKey::Settlement, &settlement_address); - env.events().publish( - (Symbol::new(&env, "set_settlement"), caller), - settlement_address, - ); - } - - /// Return the settlement address, panicking if not set. - pub fn get_settlement(env: Env) -> Address { - env.storage() - .instance() - .get(&StorageKey::Settlement) - .unwrap_or_else(|| panic!("settlement address not set")) - } - - /// Return `(usdc_token, settlement, revenue_pool)` in one call. - pub fn get_contract_addresses(env: Env) -> (Option
, Option
, Option
) { - let inst = env.storage().instance(); - let usdc: Option
= inst.get(&StorageKey::UsdcToken); - let settlement: Option
= inst.get(&StorageKey::Settlement); - let revenue_pool: Option
= inst.get(&StorageKey::RevenuePool); - (usdc, settlement, revenue_pool) - } - - pub fn set_metadata( - env: Env, - caller: Address, - offering_id: String, - metadata: String, - ) -> String { - caller.require_auth(); - Self::require_owner(env.clone(), caller.clone()); - assert!( - offering_id.len() <= MAX_OFFERING_ID_LEN, - "offering_id exceeds max length" - ); - assert!( - metadata.len() <= MAX_METADATA_LEN, - "metadata exceeds max length" - ); - env.storage() - .instance() - .set(&StorageKey::Metadata(offering_id.clone()), &metadata); - env.events().publish( - (Symbol::new(&env, "metadata_set"), offering_id, caller), - metadata.clone(), - ); - metadata - } - - pub fn update_metadata( - env: Env, - caller: Address, - offering_id: String, - metadata: String, - ) -> String { - caller.require_auth(); - Self::require_owner(env.clone(), caller.clone()); - assert!( - offering_id.len() <= MAX_OFFERING_ID_LEN, - "offering_id exceeds max length" - ); - assert!( - metadata.len() <= MAX_METADATA_LEN, - "metadata exceeds max length" - ); - let old: String = env - .storage() - .instance() - .get(&StorageKey::Metadata(offering_id.clone())) - .unwrap_or(String::from_str(&env, "")); - env.storage() - .instance() - .set(&StorageKey::Metadata(offering_id.clone()), &metadata); - env.events().publish( - (Symbol::new(&env, "metadata_updated"), offering_id, caller), - (old, metadata.clone()), - ); - metadata - } - - // ----------------------------------------------------------------------- - // Private helpers - // ----------------------------------------------------------------------- - - fn require_authorized_deduct_caller(env: Env, caller: &Address) { - let meta = Self::get_meta(env.clone()); - let auth = match &meta.authorized_caller { - Some(ac) => caller == ac || *caller == meta.owner, - None => *caller == meta.owner, - }; - assert!(auth, "unauthorized caller"); - } - - fn transfer_funds(env: &Env, usdc_token: &Address, to: &Address, amount: i128) { - token::Client::new(env, usdc_token).transfer(&env.current_contract_address(), to, &amount); - } - - fn require_settlement(env: &Env) -> Address { - env.storage() - .instance() - .get(&StorageKey::Settlement) - .unwrap_or_else(|| panic!("settlement address not set")) - } - - fn require_not_paused(env: Env) { - assert!(!Self::is_paused(env), "vault is paused"); - } - - fn require_admin_or_owner(env: Env, caller: &Address) { - let admin: Address = env - .storage() - .instance() - .get(&StorageKey::Admin) - .expect("vault not initialized"); - let meta = Self::get_meta(env); - assert!( - *caller == admin || *caller == meta.owner, - "unauthorized: caller is not admin or owner" - ); - } - - pub fn add_address(env: Env, caller: Address, depositor: Address) { - Self::set_allowed_depositor(env.clone(), caller.clone(), Some(depositor.clone())); - env.events() - .publish((Symbol::new(&env, "allowlist_add"), caller, depositor), ()); - } - - pub fn get_allowlist(env: Env) -> Vec
{ - Self::get_allowed_depositors(env) - } - - pub fn clear_all(env: Env, caller: Address) { - Self::clear_allowed_depositors(env.clone(), caller.clone()); - env.events() - .publish((Symbol::new(&env, "allowlist_clear"), caller), ()); - } -} - -// Allowlist aliases used by tests -#[contractimpl] -impl CalloraVault { - pub fn add_address(env: Env, caller: Address, depositor: Address) { - caller.require_auth(); - Self::require_owner(env.clone(), caller.clone()); - let mut list: Vec
= env - .storage() - .instance() - .get(&StorageKey::DepositorList) - .unwrap_or(Vec::new(&env)); - if !list.contains(&depositor) { - list.push_back(depositor.clone()); - } - env.storage() - .instance() - .set(&StorageKey::DepositorList, &list); - env.events() - .publish((Symbol::new(&env, "allowlist_add"), caller, depositor), ()); - } - - pub fn clear_all(env: Env, caller: Address) { - caller.require_auth(); - Self::require_owner(env.clone(), caller.clone()); - env.storage() - .instance() - .set(&StorageKey::DepositorList, &Vec::
::new(&env)); - env.events() - .publish((Symbol::new(&env, "allowlist_clear"), caller), ()); - } - - pub fn get_allowlist(env: Env) -> Vec
{ - env.storage() - .instance() - .get(&StorageKey::DepositorList) - .unwrap_or(Vec::new(&env)) - } } - -#[cfg(test)] -mod test; - -#[cfg(test)] -mod test_init_hardening; - -#[cfg(test)] -mod test_setter_validation; - -#[cfg(test)] -mod test_views;