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 6a90e49d..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 @@ -161,7 +163,7 @@ fn require_valid_reserve_metadata(e: &Env, metadata: &ReserveConfig) { || metadata.util > 0_9500000 || (metadata.max_util > SCALAR_7_U32 || metadata.max_util <= metadata.util) || (metadata.r_one > metadata.r_two || metadata.r_two > metadata.r_three) - || (metadata.reactivity > 0_0005000) + || (metadata.reactivity > 0_0001000) { panic_with_error!(e, PoolError::InvalidReserveMetadata); } @@ -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(); @@ -887,7 +973,7 @@ mod tests { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 5001, + reactivity: 0_0001001, }; require_valid_reserve_metadata(&e, &metadata); } diff --git a/pool/src/pool/interest.rs b/pool/src/pool/interest.rs index 33a52a4a..e770c30b 100644 --- a/pool/src/pool/interest.rs +++ b/pool/src/pool/interest.rs @@ -78,7 +78,7 @@ pub fn calc_accrual( .fixed_mul_floor(util_dif_scaled, SCALAR_9) .unwrap_optimized(); let rate_dif = util_error - .fixed_mul_floor(i128(config.reactivity), SCALAR_9) + .fixed_mul_floor(i128(config.reactivity), SCALAR_7) .unwrap_optimized(); let next_ir_mod = ir_mod + rate_dif; let ir_mod_max = 10 * SCALAR_9; @@ -93,7 +93,7 @@ pub fn calc_accrual( .fixed_mul_ceil(util_dif_scaled, SCALAR_9) .unwrap_optimized(); let rate_dif = util_error - .fixed_mul_ceil(i128(config.reactivity), SCALAR_9) + .fixed_mul_ceil(i128(config.reactivity), SCALAR_7) .unwrap_optimized(); let next_ir_mod = ir_mod + rate_dif; let ir_mod_min = SCALAR_9 / 10; @@ -133,7 +133,7 @@ mod tests { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 0_000_002_000, + reactivity: 0_0000020, index: 0, }; let ir_mod: i128 = 1_000_000_000; @@ -168,7 +168,7 @@ mod tests { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 0_000_002_000, + reactivity: 0_0000020, index: 0, }; let ir_mod: i128 = 1_000_000_000; @@ -203,7 +203,7 @@ mod tests { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 0_000_002_000, + reactivity: 0_0000020, index: 0, }; let ir_mod: i128 = 1_000_000_000; @@ -238,7 +238,7 @@ mod tests { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 0_000_002_000, + reactivity: 0_0000020, index: 0, }; let ir_mod: i128 = 9_997_000_000; @@ -272,7 +272,7 @@ mod tests { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 0_000_002_000, + reactivity: 0_0000020, index: 0, }; let ir_mod: i128 = 0_150_000_000; @@ -306,7 +306,7 @@ mod tests { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 0_000_002_000, + reactivity: 0_0000020, index: 0, }; let ir_mod: i128 = 0_100_000_000; diff --git a/pool/src/pool/reserve.rs b/pool/src/pool/reserve.rs index 01553293..0887b2ac 100644 --- a/pool/src/pool/reserve.rs +++ b/pool/src/pool/reserve.rs @@ -20,10 +20,10 @@ pub struct Reserve { pub c_factor: u32, // the collateral factor for the reserve pub max_util: u32, // the maximum utilization rate for the reserve pub last_time: u64, // the last block the data was updated - pub scalar: i128, // scalar used for balances + pub scalar: i128, // scalar used for positions, b/d token supply, and credit pub d_rate: i128, // the conversion rate from dToken to underlying (9 decimals) pub b_rate: i128, // the conversion rate from bToken to underlying (9 decimals) - pub ir_mod: i128, // the interest rate curve modifier + pub ir_mod: i128, // the interest rate curve modifier (9 decimals) pub b_supply: i128, // the total supply of b tokens pub d_supply: i128, // the total supply of d tokens pub backstop_credit: i128, // the total amount of underlying tokens owed to the backstop diff --git a/pool/src/storage.rs b/pool/src/storage.rs index b3bceb4f..e8d7fd2f 100644 --- a/pool/src/storage.rs +++ b/pool/src/storage.rs @@ -44,8 +44,9 @@ pub struct ReserveConfig { pub r_one: u32, // the R1 value in the interest rate formula scaled expressed in 7 decimals pub r_two: u32, // the R2 value in the interest rate formula scaled expressed in 7 decimals pub r_three: u32, // the R3 value in the interest rate formula scaled expressed in 7 decimals - pub reactivity: u32, // the reactivity constant for the reserve scaled expressed in 9 decimals + pub reactivity: u32, // the reactivity constant for the reserve scaled expressed in 7 decimals } + #[derive(Clone)] #[contracttype] pub struct QueuedReserveInit { @@ -94,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"; @@ -168,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 @@ -223,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 diff --git a/pool/src/testutils.rs b/pool/src/testutils.rs index a5007ba5..48240298 100644 --- a/pool/src/testutils.rs +++ b/pool/src/testutils.rs @@ -210,7 +210,7 @@ pub(crate) fn default_reserve_meta() -> (ReserveConfig, ReserveData) { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 0_000_002_000, // 10e-5 + reactivity: 0_0000020, // 2e-6 index: 0, }, ReserveData { diff --git a/test-suites/src/pool.rs b/test-suites/src/pool.rs index ed029dde..98e46096 100644 --- a/test-suites/src/pool.rs +++ b/test-suites/src/pool.rs @@ -15,7 +15,7 @@ pub fn default_reserve_metadata() -> ReserveConfig { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, - reactivity: 0_000_002_000, // 10e-5 + reactivity: 0_0000020, // 2e-6 index: 0, } }