diff --git a/backstop/src/contract.rs b/backstop/src/contract.rs index 39434b90..3dcba7b2 100644 --- a/backstop/src/contract.rs +++ b/backstop/src/contract.rs @@ -207,7 +207,7 @@ impl Backstop for BackstopContract { drop_list: Map, ) { storage::extend_instance(&e); - if storage::has_backstop_token(&e) { + if storage::get_is_init(&e) { panic_with_error!(e, BackstopError::AlreadyInitialized); } @@ -224,6 +224,8 @@ impl Backstop for BackstopContract { let last_distribution_time = EmitterClient::new(&e, &emitter).get_last_distro(&e.current_contract_address()); storage::set_last_distribution_time(&e, &last_distribution_time); + + storage::set_is_init(&e); } /********** Core **********/ diff --git a/backstop/src/storage.rs b/backstop/src/storage.rs index 4179eb9a..dea989c5 100644 --- a/backstop/src/storage.rs +++ b/backstop/src/storage.rs @@ -39,6 +39,7 @@ pub struct UserEmissionData { /********** Storage Key Types **********/ +const IS_INIT_KEY: &str = "IsInit"; const EMITTER_KEY: &str = "Emitter"; const BACKSTOP_TOKEN_KEY: &str = "BToken"; const POOL_FACTORY_KEY: &str = "PoolFact"; @@ -97,7 +98,19 @@ fn get_persistent_default, V: TryFromVal>( } } -/********** External Contracts **********/ +/********** Instance Storage **********/ + +/// Check if the contract has been initialized +pub fn get_is_init(e: &Env) -> bool { + e.storage().instance().has(&Symbol::new(e, IS_INIT_KEY)) +} + +/// Set the contract as initialized +pub fn set_is_init(e: &Env) { + e.storage() + .instance() + .set::(&Symbol::new(e, IS_INIT_KEY), &true); +} /// Fetch the pool factory id pub fn get_emitter(e: &Env) -> Address { @@ -179,13 +192,6 @@ pub fn get_backstop_token(e: &Env) -> Address { .unwrap_optimized() } -/// Checks if a backstop token is set for the backstop -pub fn has_backstop_token(e: &Env) -> bool { - e.storage() - .instance() - .has(&Symbol::new(e, BACKSTOP_TOKEN_KEY)) -} - /// Set the backstop token id /// /// ### Arguments diff --git a/emitter/src/contract.rs b/emitter/src/contract.rs index 4dddc740..c8f65983 100644 --- a/emitter/src/contract.rs +++ b/emitter/src/contract.rs @@ -76,7 +76,7 @@ pub trait Emitter { impl Emitter for EmitterContract { fn initialize(e: Env, blnd_token: Address, backstop: Address, backstop_token: Address) { storage::extend_instance(&e); - if storage::has_blnd_token(&e) { + if storage::get_is_init(&e) { panic_with_error!(&e, EmitterError::AlreadyInitialized) } @@ -84,6 +84,8 @@ impl Emitter for EmitterContract { storage::set_backstop(&e, &backstop); storage::set_backstop_token(&e, &backstop_token); storage::set_last_distro_time(&e, &backstop, e.ledger().timestamp()); + + storage::set_is_init(&e); } fn distribute(e: Env) -> i128 { diff --git a/emitter/src/storage.rs b/emitter/src/storage.rs index 1f68bfa6..3111b2a2 100644 --- a/emitter/src/storage.rs +++ b/emitter/src/storage.rs @@ -7,6 +7,7 @@ pub(crate) const LEDGER_BUMP_SHARED: u32 = 241920; // ~ 14 days /********** Storage **********/ +const IS_INIT_KEY: &str = "IsInit"; const BACKSTOP_KEY: &str = "Backstop"; const BACKSTOP_TOKEN_KEY: &str = "BToken"; const BLND_TOKEN_KEY: &str = "BLNDTkn"; @@ -30,6 +31,20 @@ pub fn extend_instance(e: &Env) { .extend_ttl(LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); } +/********** Init **********/ + +/// Check if the contract has been initialized +pub fn get_is_init(e: &Env) -> bool { + e.storage().instance().has(&Symbol::new(e, IS_INIT_KEY)) +} + +/// Set the contract as initialized +pub fn set_is_init(e: &Env) { + e.storage() + .instance() + .set::(&Symbol::new(e, IS_INIT_KEY), &true); +} + /********** Backstop **********/ /// Fetch the current backstop address @@ -128,13 +143,6 @@ pub fn set_blnd_token(e: &Env, blnd_token: &Address) { .set::(&Symbol::new(e, BLND_TOKEN_KEY), blnd_token); } -/// Check if the BLND token has been set -/// -/// Returns true if a BLND token has been set -pub fn has_blnd_token(e: &Env) -> bool { - e.storage().instance().has(&Symbol::new(e, BLND_TOKEN_KEY)) -} - /********** Blend Distributions **********/ /// Fetch the last timestamp distribution was ran on diff --git a/pool-factory/src/pool_factory.rs b/pool-factory/src/pool_factory.rs index 9ec846f5..b359aaaa 100644 --- a/pool-factory/src/pool_factory.rs +++ b/pool-factory/src/pool_factory.rs @@ -51,10 +51,13 @@ pub trait PoolFactory { impl PoolFactory for PoolFactoryContract { fn initialize(e: Env, pool_init_meta: PoolInitMeta) { storage::extend_instance(&e); - if storage::has_pool_init_meta(&e) { + if storage::get_is_init(&e) { panic_with_error!(&e, PoolFactoryError::AlreadyInitialized); } + storage::set_pool_init_meta(&e, &pool_init_meta); + + storage::set_is_init(&e); } fn deploy( diff --git a/pool-factory/src/storage.rs b/pool-factory/src/storage.rs index ad726e96..8f7d2392 100644 --- a/pool-factory/src/storage.rs +++ b/pool-factory/src/storage.rs @@ -4,6 +4,8 @@ use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Address, BytesN, Env, S pub(crate) const LEDGER_THRESHOLD: u32 = 518400; // TODO: Check on phase 1 max ledger entry bump pub(crate) const LEDGER_BUMP: u32 = 535670; // TODO: Check on phase 1 max ledger entry bump +const IS_INIT_KEY: &str = "IsInit"; + #[derive(Clone)] #[contracttype] pub enum PoolFactoryDataKey { @@ -26,6 +28,18 @@ pub fn extend_instance(e: &Env) { .extend_ttl(LEDGER_THRESHOLD, LEDGER_BUMP); } +/// Check if the contract has been initialized +pub fn get_is_init(e: &Env) -> bool { + e.storage().instance().has(&Symbol::new(e, IS_INIT_KEY)) +} + +/// Set the contract as initialized +pub fn set_is_init(e: &Env) { + e.storage() + .instance() + .set::(&Symbol::new(e, IS_INIT_KEY), &true); +} + /// Fetch the pool initialization metadata pub fn get_pool_init_meta(e: &Env) -> PoolInitMeta { e.storage() @@ -44,11 +58,6 @@ pub fn set_pool_init_meta(e: &Env, pool_init_meta: &PoolInitMeta) { .set::(&Symbol::new(e, "PoolMeta"), pool_init_meta) } -/// Check if the factory has a WASM hash set -pub fn has_pool_init_meta(e: &Env) -> bool { - e.storage().instance().has(&Symbol::new(e, "PoolMeta")) -} - /// Check if a given contract_id was deployed by the factory /// /// ### Arguments diff --git a/pool/src/pool/config.rs b/pool/src/pool/config.rs index c4efdc00..19a7f813 100644 --- a/pool/src/pool/config.rs +++ b/pool/src/pool/config.rs @@ -22,7 +22,7 @@ pub fn execute_initialize( blnd_id: &Address, usdc_id: &Address, ) { - if storage::has_admin(e) { + if storage::get_is_init(e) { panic_with_error!(e, PoolError::AlreadyInitialized); } @@ -45,6 +45,8 @@ pub fn execute_initialize( ); storage::set_blnd_token(e, blnd_id); storage::set_usdc_token(e, usdc_id); + + storage::set_is_init(e); } /// Update the pool @@ -184,7 +186,7 @@ mod tests { let name = Symbol::new(&e, "pool_name"); let oracle = Address::generate(&e); let bstop_rate = 0_100_000_000u64; - let max_postions = 2; + let max_positions = 2; let backstop_address = Address::generate(&e); let blnd_id = Address::generate(&e); let usdc_id = Address::generate(&e); @@ -196,7 +198,7 @@ mod tests { &name, &oracle, &bstop_rate, - &max_postions, + &max_positions, &backstop_address, &blnd_id, &usdc_id, @@ -213,6 +215,90 @@ mod tests { }); } + #[test] + #[should_panic(expected = "Error(Contract, #3)")] + fn test_execute_initialize_already_initialized() { + let e = Env::default(); + let pool = testutils::create_pool(&e); + + let admin = Address::generate(&e); + let name = Symbol::new(&e, "pool_name"); + let oracle = Address::generate(&e); + let bstop_rate = 0_100_000_000u64; + let max_positions = 3; + let backstop_address = Address::generate(&e); + let blnd_id = Address::generate(&e); + let usdc_id = Address::generate(&e); + + e.as_contract(&pool, || { + execute_initialize( + &e, + &admin, + &name, + &oracle, + &bstop_rate, + &max_positions, + &backstop_address, + &blnd_id, + &usdc_id, + ); + + execute_initialize( + &e, + &Address::generate(&e), + &name, + &oracle, + &bstop_rate, + &max_positions, + &backstop_address, + &blnd_id, + &usdc_id, + ); + }); + } + + #[test] + #[should_panic(expected = "Error(Contract, #5)")] + fn test_execute_initialize_bad_take_rate() { + let e = Env::default(); + let pool = testutils::create_pool(&e); + + let admin = Address::generate(&e); + let name = Symbol::new(&e, "pool_name"); + let oracle = Address::generate(&e); + let bstop_rate = 1_000_000_000u64; + let max_positions = 3; + let backstop_address = Address::generate(&e); + let blnd_id = Address::generate(&e); + let usdc_id = Address::generate(&e); + + e.as_contract(&pool, || { + execute_initialize( + &e, + &admin, + &name, + &oracle, + &bstop_rate, + &max_positions, + &backstop_address, + &blnd_id, + &usdc_id, + ); + + execute_initialize( + &e, + &Address::generate(&e), + &name, + &oracle, + &bstop_rate, + &max_positions, + &backstop_address, + &blnd_id, + &usdc_id, + ); + }); + } + #[test] fn test_execute_update_pool() { let e = Env::default(); diff --git a/pool/src/storage.rs b/pool/src/storage.rs index 44be2a5a..e8d7fd2f 100644 --- a/pool/src/storage.rs +++ b/pool/src/storage.rs @@ -95,6 +95,7 @@ pub struct UserEmissionData { /********** Storage Key Types **********/ +const IS_INIT_KEY: &str = "IsInit"; const ADMIN_KEY: &str = "Admin"; const NAME_KEY: &str = "Name"; const BACKSTOP_KEY: &str = "Backstop"; @@ -169,6 +170,20 @@ fn get_persistent_default, V: TryFromVal>( } } +/********** Init **********/ + +/// Check if the contract has been initialized +pub fn get_is_init(e: &Env) -> bool { + e.storage().instance().has(&Symbol::new(e, IS_INIT_KEY)) +} + +/// Set the contract as initialized +pub fn set_is_init(e: &Env) { + e.storage() + .instance() + .set::(&Symbol::new(e, IS_INIT_KEY), &true); +} + /********** User **********/ /// Fetch the user's positions or return an empty Positions struct @@ -224,11 +239,6 @@ pub fn set_admin(e: &Env, new_admin: &Address) { .set::(&Symbol::new(e, ADMIN_KEY), new_admin); } -/// Checks if an admin is set -pub fn has_admin(e: &Env) -> bool { - e.storage().instance().has(&Symbol::new(e, ADMIN_KEY)) -} - /********** Metadata **********/ /// Set a pool name