From 627026579fbd93f9a30e53db0e8b2b589a203de7 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:19:29 +0200 Subject: [PATCH 01/15] contructor in factory --- contracts/factory/src/contract.rs | 113 ++++++++++++-------------- contracts/factory/src/tests.rs | 63 ++++++++------ contracts/factory/src/tests/config.rs | 27 +++--- contracts/factory/src/tests/setup.rs | 29 ++++--- 4 files changed, 123 insertions(+), 109 deletions(-) diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 33e3ac23..fa849dd3 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -30,19 +30,6 @@ pub struct Factory; #[allow(dead_code)] pub trait FactoryTrait { - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - admin: Address, - multihop_wasm_hash: BytesN<32>, - lp_wasm_hash: BytesN<32>, - stable_wasm_hash: BytesN<32>, - stake_wasm_hash: BytesN<32>, - token_wasm_hash: BytesN<32>, - whitelisted_accounts: Vec
, - lp_token_decimals: u32, - ); - #[allow(clippy::too_many_arguments)] fn create_liquidity_pool( env: Env, @@ -89,56 +76,6 @@ pub trait FactoryTrait { #[contractimpl] impl FactoryTrait for Factory { - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - admin: Address, - multihop_wasm_hash: BytesN<32>, - lp_wasm_hash: BytesN<32>, - stable_wasm_hash: BytesN<32>, - stake_wasm_hash: BytesN<32>, - token_wasm_hash: BytesN<32>, - whitelisted_accounts: Vec
, - lp_token_decimals: u32, - ) { - if is_initialized(&env) { - log!( - &env, - "Factory: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - if whitelisted_accounts.is_empty() { - log!(&env, "Factory: Initialize: there must be at least one whitelisted account able to create liquidity pools."); - panic_with_error!(&env, ContractError::WhiteListeEmpty); - } - - set_initialized(&env); - - let multihop_address = - deploy_and_initialize_multihop_contract(env.clone(), admin.clone(), multihop_wasm_hash); - - save_config( - &env, - Config { - admin: admin.clone(), - multihop_address, - lp_wasm_hash, - stake_wasm_hash, - token_wasm_hash, - whitelisted_accounts, - lp_token_decimals, - }, - ); - save_stable_wasm_hash(&env, stable_wasm_hash); - - save_lp_vec(&env, Vec::new(&env)); - - env.events() - .publish(("initialize", "LP factory contract"), admin); - } - #[allow(clippy::too_many_arguments)] fn create_liquidity_pool( env: Env, @@ -501,6 +438,56 @@ impl FactoryTrait for Factory { #[contractimpl] impl Factory { + #[allow(clippy::too_many_arguments)] + pub fn __constructor( + env: Env, + admin: Address, + multihop_wasm_hash: BytesN<32>, + lp_wasm_hash: BytesN<32>, + stable_wasm_hash: BytesN<32>, + stake_wasm_hash: BytesN<32>, + token_wasm_hash: BytesN<32>, + whitelisted_accounts: Vec
, + lp_token_decimals: u32, + ) { + if is_initialized(&env) { + log!( + &env, + "Factory: Initialize: initializing contract twice is not allowed" + ); + panic_with_error!(&env, ContractError::AlreadyInitialized); + } + + if whitelisted_accounts.is_empty() { + log!(&env, "Factory: Initialize: there must be at least one whitelisted account able to create liquidity pools."); + panic_with_error!(&env, ContractError::WhiteListeEmpty); + } + + set_initialized(&env); + + let multihop_address = + deploy_and_initialize_multihop_contract(env.clone(), admin.clone(), multihop_wasm_hash); + + save_config( + &env, + Config { + admin: admin.clone(), + multihop_address, + lp_wasm_hash, + stake_wasm_hash, + token_wasm_hash, + whitelisted_accounts, + lp_token_decimals, + }, + ); + save_stable_wasm_hash(&env, stable_wasm_hash); + + save_lp_vec(&env, Vec::new(&env)); + + env.events() + .publish(("initialize", "LP factory contract"), admin); + } + #[allow(dead_code)] pub fn update(env: Env, new_wasm_hash: BytesN<32>, new_stable_pool_hash: BytesN<32>) { let admin = get_config(&env).admin; diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index 48f5751a..cea4db58 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -1,8 +1,10 @@ -use soroban_sdk::{testutils::Address as _, vec, Address, Env}; +use soroban_sdk::{testutils::Address as _, vec, Address, Env, Vec}; + +use crate::contract::{Factory, FactoryClient}; use self::setup::{ - deploy_factory_contract, install_lp_contract, install_multihop_wasm, install_stable_lp, - install_stake_wasm, install_token_wasm, + install_lp_contract, install_multihop_wasm, install_stable_lp, install_stake_wasm, + install_token_wasm, }; mod config; @@ -24,27 +26,42 @@ fn test_deploy_factory_twice_should_fail() { let stable_wasm_hash = install_stable_lp(&env); let stake_wasm_hash = install_stake_wasm(&env); let token_wasm_hash = install_token_wasm(&env); + let whitelisted_accounts = vec![&env, auth_user]; + let contract_addr = Address::generate(&env); - let factory = deploy_factory_contract(&env, admin.clone()); - - factory.initialize( - &admin, - &multihop_wasm_hash, - &lp_wasm_hash, - &stable_wasm_hash, - &stake_wasm_hash, - &token_wasm_hash, - &vec![&env, auth_user.clone()], - &10u32, + let _ = FactoryClient::new( + &env, + &env.register_at( + &contract_addr.clone(), + Factory {}, + ( + &admin, + &multihop_wasm_hash, + &lp_wasm_hash, + &stable_wasm_hash, + &stake_wasm_hash, + &token_wasm_hash, + whitelisted_accounts.clone(), + &10u32, + ), + ), ); - factory.initialize( - &admin, - &multihop_wasm_hash, - &lp_wasm_hash, - &stable_wasm_hash, - &stake_wasm_hash, - &token_wasm_hash, - &vec![&env, auth_user.clone()], - &10u32, + + let _ = FactoryClient::new( + &env, + &env.register_at( + &contract_addr, + Factory {}, + ( + &admin, + &multihop_wasm_hash, + &lp_wasm_hash, + &stable_wasm_hash, + &stake_wasm_hash, + &token_wasm_hash, + whitelisted_accounts, + &10u32, + ), + ), ); } diff --git a/contracts/factory/src/tests/config.rs b/contracts/factory/src/tests/config.rs index 06089bf7..75e0241c 100644 --- a/contracts/factory/src/tests/config.rs +++ b/contracts/factory/src/tests/config.rs @@ -245,24 +245,29 @@ fn factory_fails_to_init_lp_when_no_whitelisted_accounts() { env.mock_all_auths(); env.cost_estimate().budget().reset_unlimited(); - let factory = FactoryClient::new(&env, &env.register(Factory, ())); let multihop_wasm_hash = install_multihop_wasm(&env); - let whitelisted_accounts = vec![&env]; + let whitelisted_accounts: soroban_sdk::Vec
= vec![&env]; let lp_wasm_hash = install_lp_contract(&env); let stable_wasm_hash = install_stable_lp(&env); let stake_wasm_hash = install_stake_wasm(&env); let token_wasm_hash = install_token_wasm(&env); - factory.initialize( - &admin, - &multihop_wasm_hash, - &lp_wasm_hash, - &stable_wasm_hash, - &stake_wasm_hash, - &token_wasm_hash, - &whitelisted_accounts, - &10u32, + let _ = FactoryClient::new( + &env, + &env.register( + Factory, + ( + &admin, + &multihop_wasm_hash, + &lp_wasm_hash, + &stable_wasm_hash, + &stake_wasm_hash, + &token_wasm_hash, + whitelisted_accounts, + &10u32, + ), + ), ); } diff --git a/contracts/factory/src/tests/setup.rs b/contracts/factory/src/tests/setup.rs index 9b8f6f9c..ba0d9641 100644 --- a/contracts/factory/src/tests/setup.rs +++ b/contracts/factory/src/tests/setup.rs @@ -3,7 +3,7 @@ use crate::{ token_contract, }; use phoenix::utils::{LiquidityPoolInitInfo, StakeInitInfo, TokenInitInfo}; -use soroban_sdk::{testutils::Address as _, vec, Address, BytesN, Env, String}; +use soroban_sdk::{testutils::Address as _, vec, Address, BytesN, Env, String, Vec}; pub const ONE_DAY: u64 = 86400; const TOKEN_WASM: &[u8] = include_bytes!("../../../../target/wasm32-unknown-unknown/release/soroban_token_contract.wasm"); @@ -62,24 +62,29 @@ pub fn deploy_factory_contract<'a>( admin: impl Into>, ) -> FactoryClient<'a> { let admin = admin.into().unwrap_or(Address::generate(env)); - let factory = FactoryClient::new(env, &env.register(Factory, ())); let multihop_wasm_hash = install_multihop_wasm(env); - let whitelisted_accounts = vec![env, admin.clone()]; + let whitelisted_accounts: Vec
= vec![env, admin.clone()]; let lp_wasm_hash = install_lp_contract(env); let stable_wasm_hash = install_stable_lp(env); let stake_wasm_hash = install_stake_wasm(env); let token_wasm_hash = install_token_wasm(env); - factory.initialize( - &admin, - &multihop_wasm_hash, - &lp_wasm_hash, - &stable_wasm_hash, - &stake_wasm_hash, - &token_wasm_hash, - &whitelisted_accounts, - &10u32, + let factory = FactoryClient::new( + env, + &env.register( + Factory, + ( + &admin, + &multihop_wasm_hash, + &lp_wasm_hash, + &stable_wasm_hash, + &stake_wasm_hash, + &token_wasm_hash, + whitelisted_accounts, + &10u32, + ), + ), ); factory From b13c867f8d4030e1354ddac4d77773126bae35c2 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Mon, 6 Jan 2025 23:27:25 +0200 Subject: [PATCH 02/15] [no ci] wip --- contracts/multihop/src/contract.rs | 40 +++++++++--------- contracts/multihop/src/lib.rs | 7 ++++ contracts/multihop/src/tests.rs | 15 ++++--- contracts/multihop/src/tests/query.rs | 2 + contracts/multihop/src/tests/setup.rs | 59 ++++++++++++--------------- 5 files changed, 65 insertions(+), 58 deletions(-) diff --git a/contracts/multihop/src/contract.rs b/contracts/multihop/src/contract.rs index 8de901cb..9334b0a9 100644 --- a/contracts/multihop/src/contract.rs +++ b/contracts/multihop/src/contract.rs @@ -25,8 +25,6 @@ pub struct Multihop; #[allow(dead_code)] pub trait MultihopTrait { - fn initialize(env: Env, admin: Address, factory: Address); - #[allow(clippy::too_many_arguments)] fn swap( env: Env, @@ -60,25 +58,6 @@ pub trait MultihopTrait { #[contractimpl] impl MultihopTrait for Multihop { - fn initialize(env: Env, admin: Address, factory: Address) { - if is_initialized(&env) { - log!( - &env, - "Multihop: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - set_initialized(&env); - - save_admin_old(&env, &admin); - - save_factory(&env, factory); - - env.events() - .publish(("initialize", "Multihop factory with admin: "), admin); - } - #[allow(clippy::too_many_arguments)] fn swap( env: Env, @@ -298,6 +277,25 @@ impl MultihopTrait for Multihop { #[contractimpl] impl Multihop { + pub fn __constructor(env: Env, admin: Address, factory: Address) { + if is_initialized(&env) { + log!( + &env, + "Multihop: Initialize: initializing contract twice is not allowed" + ); + panic_with_error!(&env, ContractError::AlreadyInitialized); + } + + set_initialized(&env); + + save_admin_old(&env, &admin); + + save_factory(&env, factory); + + env.events() + .publish(("initialize", "Multihop factory with admin: "), admin); + } + #[allow(dead_code)] pub fn update(env: Env, new_wasm_hash: BytesN<32>) { let admin = get_admin_old(&env); diff --git a/contracts/multihop/src/lib.rs b/contracts/multihop/src/lib.rs index af8906b0..9d7fc24e 100644 --- a/contracts/multihop/src/lib.rs +++ b/contracts/multihop/src/lib.rs @@ -21,6 +21,13 @@ pub mod stable_pool { ); } +#[allow(clippy::too_many_arguments)] +pub mod stake { + soroban_sdk::contractimport!( + file = "../../target/wasm32-unknown-unknown/release/phoenix_stake.wasm" + ); +} + #[allow(clippy::too_many_arguments)] pub mod factory_contract { soroban_sdk::contractimport!( diff --git a/contracts/multihop/src/tests.rs b/contracts/multihop/src/tests.rs index 51ca22e5..2b1605de 100644 --- a/contracts/multihop/src/tests.rs +++ b/contracts/multihop/src/tests.rs @@ -1,5 +1,4 @@ use crate::contract::{Multihop, MultihopClient}; -use crate::tests::setup::deploy_factory_contract; use soroban_sdk::{testutils::Address as _, Address, Env}; mod query; @@ -14,9 +13,15 @@ fn test_deploy_multihop_twice_should_fail() { env.cost_estimate().budget().reset_unlimited(); let admin = Address::generate(&env); + let multihop_addr = Address::generate(&env); + let factory = Address::generate(&env); - let multihop = MultihopClient::new(&env, &env.register(Multihop, ())); - let factory = deploy_factory_contract(&env, admin.clone()); - multihop.initialize(&admin, &factory); - multihop.initialize(&admin, &factory); + let _ = MultihopClient::new( + &env, + &env.register_at(&multihop_addr, Multihop, (&admin, factory.clone())), + ); + let _ = MultihopClient::new( + &env, + &env.register_at(&multihop_addr, Multihop, (admin, factory)), + ); } diff --git a/contracts/multihop/src/tests/query.rs b/contracts/multihop/src/tests/query.rs index 62d6729f..1966a45b 100644 --- a/contracts/multihop/src/tests/query.rs +++ b/contracts/multihop/src/tests/query.rs @@ -65,7 +65,9 @@ fn simulate_swap_single_pool_no_fees() { ]; // Offering 1k token1 should result in 2k token2 + soroban_sdk::testutils::arbitrary::std::dbg!("BEFORE"); let result = multihop.simulate_swap(&operation, &1_000, &PoolType::Xyk); + soroban_sdk::testutils::arbitrary::std::dbg!("AFTER"); assert_eq!(result.ask_amount, 2_000i128); assert_eq!( diff --git a/contracts/multihop/src/tests/setup.rs b/contracts/multihop/src/tests/setup.rs index 02225e9b..060877bf 100644 --- a/contracts/multihop/src/tests/setup.rs +++ b/contracts/multihop/src/tests/setup.rs @@ -1,12 +1,16 @@ use crate::contract::{Multihop, MultihopClient}; use crate::factory_contract::{LiquidityPoolInitInfo, PoolType, StakeInitInfo, TokenInitInfo}; -use crate::{factory_contract, stable_pool, token_contract, xyk_pool}; +use crate::{factory_contract, stable_pool, stake, token_contract, xyk_pool}; use soroban_sdk::{ testutils::{arbitrary::std, Address as _}, - Address, Bytes, BytesN, Env, + Address, BytesN, Env, }; use soroban_sdk::{vec, String}; + +const FACTORY_WASM: &[u8] = + include_bytes!("../../../../target/wasm32-unknown-unknown/release/phoenix_factory.wasm"); + pub fn create_token_contract_with_metadata<'a>( env: &Env, admin: &Address, @@ -45,10 +49,7 @@ pub fn deploy_token_contract<'a>(env: &Env, admin: &Address) -> token_contract:: #[allow(clippy::too_many_arguments)] pub fn install_stake_wasm(env: &Env) -> BytesN<32> { - soroban_sdk::contractimport!( - file = "../../target/wasm32-unknown-unknown/release/phoenix_stake.wasm" - ); - env.deployer().upload_contract_wasm(WASM) + env.deployer().upload_contract_wasm(stake::WASM) } #[allow(clippy::too_many_arguments)] @@ -59,16 +60,6 @@ pub fn install_multihop_wasm(env: &Env) -> BytesN<32> { env.deployer().upload_contract_wasm(WASM) } -pub fn deploy_factory_contract(e: &Env, admin: Address) -> Address { - let factory_wasm = e.deployer().upload_contract_wasm(factory_contract::WASM); - let salt = Bytes::new(e); - let salt = e.crypto().sha256(&salt); - - e.deployer() - .with_address(admin, salt) - .deploy_v2(factory_wasm, ()) -} - pub fn deploy_multihop_contract<'a>( env: &Env, admin: impl Into>, @@ -76,9 +67,8 @@ pub fn deploy_multihop_contract<'a>( ) -> MultihopClient<'a> { let admin = admin.into().unwrap_or(Address::generate(env)); - let multihop = MultihopClient::new(env, &env.register(Multihop, ())); + let multihop = MultihopClient::new(env, &env.register(Multihop, (&admin, factory))); - multihop.initialize(&admin, factory); multihop } @@ -93,27 +83,32 @@ pub fn deploy_and_mint_tokens<'a>( } pub fn deploy_and_initialize_factory(env: &Env, admin: Address) -> factory_contract::Client { - let factory_addr = deploy_factory_contract(env, admin.clone()); - let factory_client = factory_contract::Client::new(env, &factory_addr); let multihop_wasm_hash = install_multihop_wasm(env); - let whitelisted_accounts = vec![env, admin.clone()]; - let lp_wasm_hash = install_lp_contract(env); let stable_wasm_hash = install_stable_lp_contract(env); let stake_wasm_hash = install_stake_wasm(env); let token_wasm_hash = install_token_wasm(env); - factory_client.initialize( - &admin.clone(), - &multihop_wasm_hash, - &lp_wasm_hash, - &stable_wasm_hash, - &stake_wasm_hash, - &token_wasm_hash, - &whitelisted_accounts, - &10u32, + let whitelisted_accounts = vec![env, admin.clone()]; + + let factory = factory_contract::Client::new( + env, + &env.register( + FACTORY_WASM, + ( + &admin, + &multihop_wasm_hash, + &lp_wasm_hash, + &stable_wasm_hash, + &stake_wasm_hash, + &token_wasm_hash, + whitelisted_accounts, + &10u32, + ), + ), ); - factory_client + + factory } #[allow(clippy::too_many_arguments)] From bbd254933fa61440e6d1fd8692abec7aed00d3e4 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:02:51 +0200 Subject: [PATCH 03/15] multihop to use constructors --- contracts/factory/src/tests.rs | 2 +- contracts/factory/src/utils.rs | 13 +++---------- contracts/multihop/src/tests/query.rs | 2 -- contracts/multihop/src/tests/setup.rs | 6 +++--- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index cea4db58..db2f4a30 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{testutils::Address as _, vec, Address, Env, Vec}; +use soroban_sdk::{testutils::Address as _, vec, Address, Env}; use crate::contract::{Factory, FactoryClient}; diff --git a/contracts/factory/src/utils.rs b/contracts/factory/src/utils.rs index a9fa48d6..6e9e41e1 100644 --- a/contracts/factory/src/utils.rs +++ b/contracts/factory/src/utils.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{xdr::ToXdr, Address, Bytes, BytesN, Env, IntoVal, Symbol, Val, Vec}; +use soroban_sdk::{xdr::ToXdr, Address, Bytes, BytesN, Env}; pub fn deploy_lp_contract( env: &Env, @@ -25,14 +25,7 @@ pub fn deploy_and_initialize_multihop_contract( salt.append(&admin.clone().to_xdr(&env)); let salt = env.crypto().sha256(&salt); - let multihop_address = env - .deployer() + env.deployer() .with_current_contract(salt) - .deploy_v2(multihop_wasm_hash, ()); - - let init_fn = Symbol::new(&env, "initialize"); - let init_args: Vec = (admin, env.current_contract_address()).into_val(&env); - env.invoke_contract::(&multihop_address, &init_fn, init_args); - - multihop_address + .deploy_v2(multihop_wasm_hash, (admin, env.current_contract_address())) } diff --git a/contracts/multihop/src/tests/query.rs b/contracts/multihop/src/tests/query.rs index 1966a45b..62d6729f 100644 --- a/contracts/multihop/src/tests/query.rs +++ b/contracts/multihop/src/tests/query.rs @@ -65,9 +65,7 @@ fn simulate_swap_single_pool_no_fees() { ]; // Offering 1k token1 should result in 2k token2 - soroban_sdk::testutils::arbitrary::std::dbg!("BEFORE"); let result = multihop.simulate_swap(&operation, &1_000, &PoolType::Xyk); - soroban_sdk::testutils::arbitrary::std::dbg!("AFTER"); assert_eq!(result.ask_amount, 2_000i128); assert_eq!( diff --git a/contracts/multihop/src/tests/setup.rs b/contracts/multihop/src/tests/setup.rs index 060877bf..6a34ac7e 100644 --- a/contracts/multihop/src/tests/setup.rs +++ b/contracts/multihop/src/tests/setup.rs @@ -6,7 +6,7 @@ use soroban_sdk::{ testutils::{arbitrary::std, Address as _}, Address, BytesN, Env, }; -use soroban_sdk::{vec, String}; +use soroban_sdk::{vec, String, Vec}; const FACTORY_WASM: &[u8] = include_bytes!("../../../../target/wasm32-unknown-unknown/release/phoenix_factory.wasm"); @@ -89,7 +89,7 @@ pub fn deploy_and_initialize_factory(env: &Env, admin: Address) -> factory_contr let stake_wasm_hash = install_stake_wasm(env); let token_wasm_hash = install_token_wasm(env); - let whitelisted_accounts = vec![env, admin.clone()]; + let whitelisted_accounts: Vec
= vec![env, admin.clone()]; let factory = factory_contract::Client::new( env, @@ -103,7 +103,7 @@ pub fn deploy_and_initialize_factory(env: &Env, admin: Address) -> factory_contr &stake_wasm_hash, &token_wasm_hash, whitelisted_accounts, - &10u32, + 10u32, ), ), ); From c6f1a6c90d5592717f424ab8ed32939ee79e1fe9 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:23:39 +0200 Subject: [PATCH 04/15] pool to use constructor --- contracts/pool/src/contract.rs | 262 +++++++++---------- contracts/pool/src/tests/config.rs | 50 ++-- contracts/pool/src/tests/setup.rs | 26 +- contracts/pool/src/tests/stake_deployment.rs | 78 +----- 4 files changed, 170 insertions(+), 246 deletions(-) diff --git a/contracts/pool/src/contract.rs b/contracts/pool/src/contract.rs index 1f54580c..0430d089 100644 --- a/contracts/pool/src/contract.rs +++ b/contracts/pool/src/contract.rs @@ -36,21 +36,6 @@ pub struct LiquidityPool; #[allow(dead_code)] pub trait LiquidityPoolTrait { - // Sets the token contract addresses for this pool - // token_wasm_hash is the WASM hash of the deployed token contract for the pool share token - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - stake_wasm_hash: BytesN<32>, - token_wasm_hash: BytesN<32>, - lp_init_info: LiquidityPoolInitInfo, - factory_addr: Address, - share_token_name: String, - share_token_symbol: String, - default_slippage_bps: i64, - max_allowed_fee_bps: i64, - ); - // Deposits token_a and token_b. Also mints pool shares for the "to" Identifier. The amount minted // is determined based on the difference between the reserves stored by this contract, and // the actual balance of token_a and token_b for this contract. @@ -148,130 +133,6 @@ pub trait LiquidityPoolTrait { #[contractimpl] impl LiquidityPoolTrait for LiquidityPool { - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - stake_wasm_hash: BytesN<32>, - token_wasm_hash: BytesN<32>, - lp_init_info: LiquidityPoolInitInfo, - factory_addr: Address, - share_token_name: String, - share_token_symbol: String, - default_slippage_bps: i64, - max_allowed_fee_bps: i64, - ) { - if is_initialized(&env) { - log!( - &env, - "Pool: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - let admin = lp_init_info.admin; - let swap_fee_bps = lp_init_info.swap_fee_bps; - let fee_recipient = lp_init_info.fee_recipient; - let max_allowed_slippage_bps = lp_init_info.max_allowed_slippage_bps; - let max_allowed_spread_bps = lp_init_info.max_allowed_spread_bps; - let max_referral_bps = lp_init_info.max_referral_bps; - let token_init_info = lp_init_info.token_init_info; - let stake_init_info = lp_init_info.stake_init_info; - - validate_bps!( - swap_fee_bps, - max_allowed_slippage_bps, - max_allowed_spread_bps, - max_referral_bps, - default_slippage_bps, - max_allowed_fee_bps - ); - - // if the swap_fee_bps is above the threshold, we throw an error - if swap_fee_bps > max_allowed_fee_bps { - log!( - &env, - "Pool: Initialize: swap fee is higher than the maximum allowed!" - ); - panic_with_error!(&env, ContractError::SwapFeeBpsOverLimit); - } - - set_initialized(&env); - - // Token info - let token_a = token_init_info.token_a; - let token_b = token_init_info.token_b; - // Stake info - let min_bond = stake_init_info.min_bond; - let min_reward = stake_init_info.min_reward; - let manager = stake_init_info.manager; - - // Token order validation to make sure only one instance of a pool can exist - if token_a >= token_b { - log!( - &env, - "Pool: Initialize: First token must be alphabetically smaller than second token" - ); - panic_with_error!(&env, ContractError::TokenABiggerThanTokenB); - } - - let precision1 = token_contract::Client::new(&env, &token_a).decimals(); - let precision2 = token_contract::Client::new(&env, &token_b).decimals(); - let max_precision_decimals: u32 = if precision1 > precision2 { - precision1 - } else { - precision2 - }; - - // deploy and initialize token contract - let share_token_address = utils::deploy_token_contract( - &env, - token_wasm_hash.clone(), - &token_a, - &token_b, - env.current_contract_address(), - max_precision_decimals, - share_token_name, - share_token_symbol, - ); - - let stake_contract_address = utils::deploy_stake_contract(&env, stake_wasm_hash); - stake_contract::Client::new(&env, &stake_contract_address).initialize( - &admin, - &share_token_address, - &min_bond, - &min_reward, - &manager, - &factory_addr, - &stake_init_info.max_complexity, - ); - - let config = Config { - token_a: token_a.clone(), - token_b: token_b.clone(), - share_token: share_token_address, - stake_contract: stake_contract_address, - pool_type: PairType::Xyk, - total_fee_bps: swap_fee_bps, - fee_recipient, - max_allowed_slippage_bps, - max_allowed_spread_bps, - max_referral_bps, - }; - - save_config(&env, config); - save_default_slippage_bps(&env, default_slippage_bps); - - utils::save_admin_old(&env, admin); - utils::save_total_shares(&env, 0); - utils::save_pool_balance_a(&env, 0); - utils::save_pool_balance_b(&env, 0); - - env.events() - .publish(("initialize", "XYK LP token_a"), token_a); - env.events() - .publish(("initialize", "XYK LP token_b"), token_b); - } - #[allow(clippy::too_many_arguments)] fn provide_liquidity( env: Env, @@ -790,6 +651,129 @@ impl LiquidityPoolTrait for LiquidityPool { #[contractimpl] impl LiquidityPool { + #[allow(clippy::too_many_arguments)] + pub fn __constructor( + env: Env, + stake_wasm_hash: BytesN<32>, + token_wasm_hash: BytesN<32>, + lp_init_info: LiquidityPoolInitInfo, + factory_addr: Address, + share_token_name: String, + share_token_symbol: String, + default_slippage_bps: i64, + max_allowed_fee_bps: i64, + ) { + if is_initialized(&env) { + log!( + &env, + "Pool: Initialize: initializing contract twice is not allowed" + ); + panic_with_error!(&env, ContractError::AlreadyInitialized); + } + + let admin = lp_init_info.admin; + let swap_fee_bps = lp_init_info.swap_fee_bps; + let fee_recipient = lp_init_info.fee_recipient; + let max_allowed_slippage_bps = lp_init_info.max_allowed_slippage_bps; + let max_allowed_spread_bps = lp_init_info.max_allowed_spread_bps; + let max_referral_bps = lp_init_info.max_referral_bps; + let token_init_info = lp_init_info.token_init_info; + let stake_init_info = lp_init_info.stake_init_info; + + validate_bps!( + swap_fee_bps, + max_allowed_slippage_bps, + max_allowed_spread_bps, + max_referral_bps, + default_slippage_bps, + max_allowed_fee_bps + ); + + // if the swap_fee_bps is above the threshold, we throw an error + if swap_fee_bps > max_allowed_fee_bps { + log!( + &env, + "Pool: Initialize: swap fee is higher than the maximum allowed!" + ); + panic_with_error!(&env, ContractError::SwapFeeBpsOverLimit); + } + + set_initialized(&env); + + // Token info + let token_a = token_init_info.token_a; + let token_b = token_init_info.token_b; + // Stake info + let min_bond = stake_init_info.min_bond; + let min_reward = stake_init_info.min_reward; + let manager = stake_init_info.manager; + + // Token order validation to make sure only one instance of a pool can exist + if token_a >= token_b { + log!( + &env, + "Pool: Initialize: First token must be alphabetically smaller than second token" + ); + panic_with_error!(&env, ContractError::TokenABiggerThanTokenB); + } + + let precision1 = token_contract::Client::new(&env, &token_a).decimals(); + let precision2 = token_contract::Client::new(&env, &token_b).decimals(); + let max_precision_decimals: u32 = if precision1 > precision2 { + precision1 + } else { + precision2 + }; + + // deploy and initialize token contract + let share_token_address = utils::deploy_token_contract( + &env, + token_wasm_hash.clone(), + &token_a, + &token_b, + env.current_contract_address(), + max_precision_decimals, + share_token_name, + share_token_symbol, + ); + + let stake_contract_address = utils::deploy_stake_contract(&env, stake_wasm_hash); + stake_contract::Client::new(&env, &stake_contract_address).initialize( + &admin, + &share_token_address, + &min_bond, + &min_reward, + &manager, + &factory_addr, + &stake_init_info.max_complexity, + ); + + let config = Config { + token_a: token_a.clone(), + token_b: token_b.clone(), + share_token: share_token_address, + stake_contract: stake_contract_address, + pool_type: PairType::Xyk, + total_fee_bps: swap_fee_bps, + fee_recipient, + max_allowed_slippage_bps, + max_allowed_spread_bps, + max_referral_bps, + }; + + save_config(&env, config); + save_default_slippage_bps(&env, default_slippage_bps); + + utils::save_admin_old(&env, admin); + utils::save_total_shares(&env, 0); + utils::save_pool_balance_a(&env, 0); + utils::save_pool_balance_b(&env, 0); + + env.events() + .publish(("initialize", "XYK LP token_a"), token_a); + env.events() + .publish(("initialize", "XYK LP token_b"), token_b); + } #[allow(dead_code)] pub fn update(env: Env, new_wasm_hash: BytesN<32>) { let admin = get_admin_old(&env); diff --git a/contracts/pool/src/tests/config.rs b/contracts/pool/src/tests/config.rs index cfdb3bf4..a9b03292 100644 --- a/contracts/pool/src/tests/config.rs +++ b/contracts/pool/src/tests/config.rs @@ -27,7 +27,6 @@ fn test_initialize_with_bigger_first_token_should_fail() { std::mem::swap(&mut token1, &mut token2); } - let pool = LiquidityPoolClient::new(&env, &env.register(LiquidityPool, ())); let fee_recipient = Address::generate(&env); let token_init_info = TokenInitInfo { @@ -55,15 +54,21 @@ fn test_initialize_with_bigger_first_token_should_fail() { stake_init_info, }; - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &Address::generate(&env), - &String::from_str(&env, "Pool"), - &String::from_str(&env, "PHOBTC"), - &100i64, - &1_000, + let _ = LiquidityPoolClient::new( + &env, + &env.register( + LiquidityPool, + ( + &stake_wasm_hash, + &token_wasm_hash, + lp_init_info, + &Address::generate(&env), + String::from_str(&env, "Pool"), + String::from_str(&env, "PHOBTC"), + &100i64, + &1_000i64, + ), + ), ); } @@ -453,7 +458,6 @@ fn test_initialize_with_maximum_allowed_swap_fee_bps_over_the_cap_should_fail() std::mem::swap(&mut token1, &mut token2); } - let pool = LiquidityPoolClient::new(&env, &env.register(LiquidityPool, ())); let fee_recipient = Address::generate(&env); let token_init_info = TokenInitInfo { @@ -481,14 +485,20 @@ fn test_initialize_with_maximum_allowed_swap_fee_bps_over_the_cap_should_fail() stake_init_info, }; - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &Address::generate(&env), - &String::from_str(&env, "Pool"), - &String::from_str(&env, "PHOBTC"), - &100i64, - &1_000, + let _ = LiquidityPoolClient::new( + &env, + &env.register( + LiquidityPool, + ( + &stake_wasm_hash, + &token_wasm_hash, + lp_init_info, + &Address::generate(&env), + String::from_str(&env, "Pool"), + String::from_str(&env, "PHOBTC"), + &100i64, + &1_000i64, + ), + ), ); } diff --git a/contracts/pool/src/tests/setup.rs b/contracts/pool/src/tests/setup.rs index 2e5faac0..de41efc0 100644 --- a/contracts/pool/src/tests/setup.rs +++ b/contracts/pool/src/tests/setup.rs @@ -51,7 +51,6 @@ pub fn deploy_liquidity_pool_contract<'a>( stake_owner: Address, ) -> LiquidityPoolClient<'a> { let admin = admin.into().unwrap_or(Address::generate(env)); - let pool = LiquidityPoolClient::new(env, &env.register(LiquidityPool, ())); let fee_recipient = fee_recipient .into() .unwrap_or_else(|| Address::generate(env)); @@ -81,15 +80,22 @@ pub fn deploy_liquidity_pool_contract<'a>( stake_init_info, }; - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &stake_owner, - &String::from_str(env, "Pool"), - &String::from_str(env, "PHOBTC"), - &100i64, - &1_000, + let pool = LiquidityPoolClient::new( + env, + &env.register( + LiquidityPool, + ( + &stake_wasm_hash, + &token_wasm_hash, + lp_init_info, + &stake_owner, + String::from_str(env, "Pool"), + String::from_str(env, "PHOBTC"), + &100i64, + &1_000i64, + ), + ), ); + pool } diff --git a/contracts/pool/src/tests/stake_deployment.rs b/contracts/pool/src/tests/stake_deployment.rs index ba0d302b..8dae9cf5 100644 --- a/contracts/pool/src/tests/stake_deployment.rs +++ b/contracts/pool/src/tests/stake_deployment.rs @@ -1,6 +1,5 @@ extern crate std; -use phoenix::utils::{LiquidityPoolInitInfo, StakeInitInfo, TokenInitInfo}; -use soroban_sdk::{testutils::Address as _, Address, Env, String}; +use soroban_sdk::{testutils::Address as _, Address, Env}; use super::setup::{deploy_liquidity_pool_contract, deploy_token_contract}; use crate::{ @@ -8,9 +7,6 @@ use crate::{ storage::{Config, PairType}, }; -use crate::contract::{LiquidityPool, LiquidityPoolClient}; -use crate::tests::setup::{install_stake_wasm, install_token_wasm}; - #[test] fn confirm_stake_contract_deployment() { let env = Env::default(); @@ -77,75 +73,3 @@ fn confirm_stake_contract_deployment() { } ); } - -#[test] -#[should_panic(expected = "Pool: Initialize: initializing contract twice is not allowed")] -fn second_pool_deployment_should_fail() { - let env = Env::default(); - env.mock_all_auths(); - env.cost_estimate().budget().reset_unlimited(); - - let mut admin1 = Address::generate(&env); - let mut admin2 = Address::generate(&env); - let user = Address::generate(&env); - - let mut token1 = deploy_token_contract(&env, &admin1); - let mut token2 = deploy_token_contract(&env, &admin2); - if token2.address < token1.address { - std::mem::swap(&mut token1, &mut token2); - std::mem::swap(&mut admin1, &mut admin2); - } - - let pool = LiquidityPoolClient::new(&env, &env.register(LiquidityPool, ())); - - let token_wasm_hash = install_token_wasm(&env); - let stake_wasm_hash = install_stake_wasm(&env); - let fee_recipient = user; - let max_allowed_slippage = 5_000i64; // 50% if not specified - let max_allowed_spread = 500i64; // 5% if not specified - - let token_init_info = TokenInitInfo { - token_a: token1.address.clone(), - token_b: token2.address.clone(), - }; - let stake_init_info = StakeInitInfo { - min_bond: 10i128, - min_reward: 5i128, - manager: Address::generate(&env), - max_complexity: 10u32, - }; - - let lp_init_info = LiquidityPoolInitInfo { - admin: admin1, - swap_fee_bps: 0i64, - fee_recipient, - max_allowed_slippage_bps: max_allowed_slippage, - default_slippage_bps: 2_500, - max_allowed_spread_bps: max_allowed_spread, - max_referral_bps: 500, - token_init_info, - stake_init_info, - }; - - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &Address::generate(&env), - &String::from_str(&env, "Pool"), - &String::from_str(&env, "PHOBTC"), - &100i64, - &1_000, - ); - - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &Address::generate(&env), - &String::from_str(&env, "Pool"), - &String::from_str(&env, "PHOBTC"), - &100i64, - &1_000, - ); -} From a30633c9e9e455d4a74e693bbd87ec80f447d807 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:35:30 +0200 Subject: [PATCH 05/15] stable pool to use constrcutor --- contracts/pool_stable/src/contract.rs | 262 ++++++++---------- contracts/pool_stable/src/error.rs | 35 ++- contracts/pool_stable/src/storage.rs | 23 +- contracts/pool_stable/src/tests/setup.rs | 26 +- .../pool_stable/src/tests/stake_deployment.rs | 102 +------ 5 files changed, 169 insertions(+), 279 deletions(-) diff --git a/contracts/pool_stable/src/contract.rs b/contracts/pool_stable/src/contract.rs index ce80cee7..6d50f1c2 100644 --- a/contracts/pool_stable/src/contract.rs +++ b/contracts/pool_stable/src/contract.rs @@ -13,7 +13,7 @@ use crate::{ storage::{ get_amp, get_config, get_greatest_precision, get_precisions, save_amp, save_config, save_greatest_precision, - utils::{self, get_admin_old, is_initialized, set_initialized}, + utils::{self, get_admin_old}, AmplifierParameters, Asset, Config, PairType, PoolResponse, SimulateReverseSwapResponse, SimulateSwapResponse, StableLiquidityPoolInfo, ADMIN, }, @@ -37,21 +37,6 @@ pub struct StableLiquidityPool; #[allow(dead_code)] pub trait StableLiquidityPoolTrait { - // Sets the token contract addresses for this pool - // token_wasm_hash is the WASM hash of the deployed token contract for the pool share token - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - stake_wasm_hash: BytesN<32>, - token_wasm_hash: BytesN<32>, - lp_init_info: LiquidityPoolInitInfo, - factory_addr: Address, - share_token_name: String, - share_token_symbol: String, - amp: u64, - max_allowed_fee_bps: i64, - ); - // Deposits token_a and token_b. Also mints pool shares for the "to" Identifier. The amount minted // is determined based on the difference between the reserves stored by this contract, and // the actual balance of token_a and token_b for this contract. @@ -143,134 +128,6 @@ pub trait StableLiquidityPoolTrait { #[contractimpl] impl StableLiquidityPoolTrait for StableLiquidityPool { - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - stake_wasm_hash: BytesN<32>, - token_wasm_hash: BytesN<32>, - lp_init_info: LiquidityPoolInitInfo, - factory_addr: Address, - share_token_name: String, - share_token_symbol: String, - amp: u64, - max_allowed_fee_bps: i64, - ) { - if is_initialized(&env) { - log!( - &env, - "Pool stable: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - let admin = lp_init_info.admin; - let swap_fee_bps = lp_init_info.swap_fee_bps; - let fee_recipient = lp_init_info.fee_recipient; - let max_allowed_slippage_bps = lp_init_info.max_allowed_slippage_bps; - let default_slippage_bps = lp_init_info.default_slippage_bps; - let max_allowed_spread_bps = lp_init_info.max_allowed_spread_bps; - let token_init_info = lp_init_info.token_init_info; - let stake_init_info = lp_init_info.stake_init_info; - - validate_bps!( - swap_fee_bps, - max_allowed_slippage_bps, - max_allowed_spread_bps, - default_slippage_bps, - max_allowed_fee_bps - ); - - // if the swap_fee_bps is above the threshold, we throw an error - if swap_fee_bps > max_allowed_fee_bps { - log!( - &env, - "Pool: Initialize: swap fee is higher than the maximum allowed!" - ); - panic_with_error!(&env, ContractError::SwapFeeBpsOverLimit); - } - - set_initialized(&env); - - // Token info - let token_a = token_init_info.token_a; - let token_b = token_init_info.token_b; - // Contract info - let min_bond = stake_init_info.min_bond; - let min_reward = stake_init_info.min_reward; - let manager = stake_init_info.manager; - - // Token order validation to make sure only one instance of a pool can exist - if token_a >= token_b { - log!( - &env, - "Pool Stable: Initialize: First token must be alphabetically smaller than second token" - ); - panic_with_error!(&env, ContractError::TokenABiggerThanTokenB); - } - - let decimals = save_greatest_precision(&env, &token_a, &token_b); - - // deploy and initialize token contract - let share_token_address = utils::deploy_token_contract( - &env, - token_wasm_hash, - &token_a, - &token_b, - env.current_contract_address(), - decimals, - share_token_name, - share_token_symbol, - ); - - let stake_contract_address = utils::deploy_stake_contract(&env, stake_wasm_hash); - stake_contract::Client::new(&env, &stake_contract_address).initialize( - &admin, - &share_token_address, - &min_bond, - &min_reward, - &manager, - &factory_addr, - &stake_init_info.max_complexity, - ); - - let config = Config { - token_a: token_a.clone(), - token_b: token_b.clone(), - share_token: share_token_address, - stake_contract: stake_contract_address, - pool_type: PairType::Stable, - total_fee_bps: swap_fee_bps, - fee_recipient, - max_allowed_slippage_bps, - default_slippage_bps, - max_allowed_spread_bps, - }; - save_config(&env, config); - let current_time = env.ledger().timestamp(); - if amp == 0 || amp > MAX_AMP { - log!(&env, "Pool Stable: Initialize: AMP parameter is incorrect"); - panic_with_error!(&env, ContractError::InvalidAMP); - } - save_amp( - &env, - AmplifierParameters { - init_amp: amp * AMP_PRECISION, - init_amp_time: current_time, - next_amp: amp * AMP_PRECISION, - next_amp_time: current_time, - }, - ); - utils::save_admin_old(&env, admin); - utils::save_total_shares(&env, 0); - utils::save_pool_balance_a(&env, 0); - utils::save_pool_balance_b(&env, 0); - - env.events() - .publish(("initialize", "XYK LP token_a"), token_a); - env.events() - .publish(("initialize", "XYK LP token_b"), token_b); - } - fn provide_liquidity( env: Env, sender: Address, @@ -826,6 +683,123 @@ impl StableLiquidityPoolTrait for StableLiquidityPool { #[contractimpl] impl StableLiquidityPool { + #[allow(clippy::too_many_arguments)] + pub fn __constructor( + env: Env, + stake_wasm_hash: BytesN<32>, + token_wasm_hash: BytesN<32>, + lp_init_info: LiquidityPoolInitInfo, + factory_addr: Address, + share_token_name: String, + share_token_symbol: String, + amp: u64, + max_allowed_fee_bps: i64, + ) { + let admin = lp_init_info.admin; + let swap_fee_bps = lp_init_info.swap_fee_bps; + let fee_recipient = lp_init_info.fee_recipient; + let max_allowed_slippage_bps = lp_init_info.max_allowed_slippage_bps; + let default_slippage_bps = lp_init_info.default_slippage_bps; + let max_allowed_spread_bps = lp_init_info.max_allowed_spread_bps; + let token_init_info = lp_init_info.token_init_info; + let stake_init_info = lp_init_info.stake_init_info; + + validate_bps!( + swap_fee_bps, + max_allowed_slippage_bps, + max_allowed_spread_bps, + default_slippage_bps, + max_allowed_fee_bps + ); + + // if the swap_fee_bps is above the threshold, we throw an error + if swap_fee_bps > max_allowed_fee_bps { + log!( + &env, + "Pool: Initialize: swap fee is higher than the maximum allowed!" + ); + panic_with_error!(&env, ContractError::SwapFeeBpsOverLimit); + } + + // Token info + let token_a = token_init_info.token_a; + let token_b = token_init_info.token_b; + // Contract info + let min_bond = stake_init_info.min_bond; + let min_reward = stake_init_info.min_reward; + let manager = stake_init_info.manager; + + // Token order validation to make sure only one instance of a pool can exist + if token_a >= token_b { + log!( + &env, + "Pool Stable: Initialize: First token must be alphabetically smaller than second token" + ); + panic_with_error!(&env, ContractError::TokenABiggerThanTokenB); + } + + let decimals = save_greatest_precision(&env, &token_a, &token_b); + + // deploy and initialize token contract + let share_token_address = utils::deploy_token_contract( + &env, + token_wasm_hash, + &token_a, + &token_b, + env.current_contract_address(), + decimals, + share_token_name, + share_token_symbol, + ); + + let stake_contract_address = utils::deploy_stake_contract(&env, stake_wasm_hash); + stake_contract::Client::new(&env, &stake_contract_address).initialize( + &admin, + &share_token_address, + &min_bond, + &min_reward, + &manager, + &factory_addr, + &stake_init_info.max_complexity, + ); + + let config = Config { + token_a: token_a.clone(), + token_b: token_b.clone(), + share_token: share_token_address, + stake_contract: stake_contract_address, + pool_type: PairType::Stable, + total_fee_bps: swap_fee_bps, + fee_recipient, + max_allowed_slippage_bps, + default_slippage_bps, + max_allowed_spread_bps, + }; + save_config(&env, config); + let current_time = env.ledger().timestamp(); + if amp == 0 || amp > MAX_AMP { + log!(&env, "Pool Stable: Initialize: AMP parameter is incorrect"); + panic_with_error!(&env, ContractError::InvalidAMP); + } + save_amp( + &env, + AmplifierParameters { + init_amp: amp * AMP_PRECISION, + init_amp_time: current_time, + next_amp: amp * AMP_PRECISION, + next_amp_time: current_time, + }, + ); + utils::save_admin_old(&env, admin); + utils::save_total_shares(&env, 0); + utils::save_pool_balance_a(&env, 0); + utils::save_pool_balance_b(&env, 0); + + env.events() + .publish(("initialize", "XYK LP token_a"), token_a); + env.events() + .publish(("initialize", "XYK LP token_b"), token_b); + } #[allow(dead_code)] pub fn update(env: Env, new_wasm_hash: BytesN<32>) { let admin = get_admin_old(&env); diff --git a/contracts/pool_stable/src/error.rs b/contracts/pool_stable/src/error.rs index a8f8bfd4..5c8afb6b 100644 --- a/contracts/pool_stable/src/error.rs +++ b/contracts/pool_stable/src/error.rs @@ -10,22 +10,21 @@ pub enum ContractError { ValidateFeeBpsTotalFeesCantBeGreaterThan100 = 4, TotalSharesEqualZero = 5, AssetNotInPool = 6, - AlreadyInitialized = 7, - TokenABiggerThanTokenB = 8, - InvalidBps = 9, - LowLiquidity = 10, - Unauthorized = 11, - IncorrectAssetSwap = 12, - NewtonMethodFailed = 13, - CalcYErr = 14, - SwapMinReceivedBiggerThanReturn = 15, - ProvideLiquidityBothTokensMustBeMoreThanZero = 16, - DivisionByZero = 17, - InvalidAMP = 18, - TransactionAfterTimestampDeadline = 19, - SlippageToleranceExceeded = 20, - IssuedSharesLessThanUserRequested = 21, - SwapFeeBpsOverLimit = 22, - UserDeclinesPoolFee = 23, - AdminNotSet = 24, + TokenABiggerThanTokenB = 7, + InvalidBps = 8, + LowLiquidity = 9, + Unauthorized = 10, + IncorrectAssetSwap = 11, + NewtonMethodFailed = 12, + CalcYErr = 13, + SwapMinReceivedBiggerThanReturn = 14, + ProvideLiquidityBothTokensMustBeMoreThanZero = 15, + DivisionByZero = 16, + InvalidAMP = 17, + TransactionAfterTimestampDeadline = 18, + SlippageToleranceExceeded = 19, + IssuedSharesLessThanUserRequested = 20, + SwapFeeBpsOverLimit = 21, + UserDeclinesPoolFee = 22, + AdminNotSet = 23, } diff --git a/contracts/pool_stable/src/storage.rs b/contracts/pool_stable/src/storage.rs index 57b79f1f..533d68c8 100644 --- a/contracts/pool_stable/src/storage.rs +++ b/contracts/pool_stable/src/storage.rs @@ -16,10 +16,9 @@ pub enum DataKey { ReserveA = 1, ReserveB = 2, Admin = 3, - Initialized = 4, - Amp = 5, - MaxPrecision = 6, - TokenPrecision = 7, + Amp = 4, + MaxPrecision = 5, + TokenPrecision = 6, } impl TryFromVal for Val { @@ -356,22 +355,6 @@ pub mod utils { pub fn get_balance(e: &Env, contract: &Address) -> i128 { token_contract::Client::new(e, contract).balance(&e.current_contract_address()) } - - pub fn is_initialized(e: &Env) -> bool { - e.storage() - .persistent() - .get(&DataKey::Initialized) - .unwrap_or(false) - } - - pub fn set_initialized(e: &Env) { - e.storage().persistent().set(&DataKey::Initialized, &true); - e.storage().persistent().extend_ttl( - &DataKey::Initialized, - PERSISTENT_LIFETIME_THRESHOLD, - PERSISTENT_BUMP_AMOUNT, - ); - } } #[cfg(test)] diff --git a/contracts/pool_stable/src/tests/setup.rs b/contracts/pool_stable/src/tests/setup.rs index 3640e596..5f97a775 100644 --- a/contracts/pool_stable/src/tests/setup.rs +++ b/contracts/pool_stable/src/tests/setup.rs @@ -51,7 +51,6 @@ pub fn deploy_stable_liquidity_pool_contract<'a>( init_amp: impl Into>, ) -> StableLiquidityPoolClient<'a> { let admin = admin.into().unwrap_or(Address::generate(env)); - let pool = StableLiquidityPoolClient::new(env, &env.register(StableLiquidityPool, ())); let fee_recipient = fee_recipient .into() .unwrap_or_else(|| Address::generate(env)); @@ -83,15 +82,22 @@ pub fn deploy_stable_liquidity_pool_contract<'a>( stake_init_info, }; - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &factory, - &String::from_str(env, "LP_SHARE_TOKEN"), - &String::from_str(env, "PHOBTCLP"), - &init_amp.into().unwrap_or(6u64), - &1_000, + let pool = StableLiquidityPoolClient::new( + env, + &env.register( + StableLiquidityPool, + ( + &stake_wasm_hash, + &token_wasm_hash, + lp_init_info, + &factory, + String::from_str(env, "LP_SHARE_TOKEN"), + String::from_str(env, "PHOBTCLP"), + &init_amp.into().unwrap_or(6u64), + &1_000i64, + ), + ), ); + pool } diff --git a/contracts/pool_stable/src/tests/stake_deployment.rs b/contracts/pool_stable/src/tests/stake_deployment.rs index d68c9eaf..72705e5d 100644 --- a/contracts/pool_stable/src/tests/stake_deployment.rs +++ b/contracts/pool_stable/src/tests/stake_deployment.rs @@ -79,81 +79,6 @@ fn confirm_stake_contract_deployment() { ); } -#[test] -#[should_panic(expected = "Pool stable: Initialize: initializing contract twice is not allowed")] -fn second_pool_stable_deployment_should_fail() { - let env = Env::default(); - env.mock_all_auths(); - env.cost_estimate().budget().reset_unlimited(); - - let mut admin1 = Address::generate(&env); - let mut admin2 = Address::generate(&env); - let user = Address::generate(&env); - - let mut token1 = deploy_token_contract(&env, &admin1); - let mut token2 = deploy_token_contract(&env, &admin2); - if token2.address < token1.address { - std::mem::swap(&mut token1, &mut token2); - std::mem::swap(&mut admin1, &mut admin2); - } - - let pool = StableLiquidityPoolClient::new(&env, &env.register(StableLiquidityPool, ())); - - let token_wasm_hash = install_token_wasm(&env); - let stake_wasm_hash = install_stake_wasm(&env); - let _stake_reward_wasm_hash = install_stake_rewards_wasm(&env); - let fee_recipient = user; - let max_allowed_slippage = 5_000i64; // 50% if not specified - let max_allowed_spread = 500i64; // 5% if not specified - let amp = 6u64; - let stake_manager = Address::generate(&env); - let factory = Address::generate(&env); - - let token_init_info = TokenInitInfo { - token_a: token1.address.clone(), - token_b: token2.address.clone(), - }; - let stake_init_info = StakeInitInfo { - min_bond: 10i128, - min_reward: 5i128, - manager: stake_manager.clone(), - max_complexity: 10, - }; - - let lp_init_info = LiquidityPoolInitInfo { - admin: admin1, - swap_fee_bps: 0i64, - fee_recipient, - max_allowed_slippage_bps: max_allowed_slippage, - default_slippage_bps: 2_500, - max_allowed_spread_bps: max_allowed_spread, - max_referral_bps: 500, - token_init_info, - stake_init_info, - }; - - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &factory, - &String::from_str(&env, "LP_SHARE_TOKEN"), - &String::from_str(&env, "PHOBTCLP"), - &, - &150, - ); - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &factory, - &String::from_str(&env, "LP_SHARE_TOKEN"), - &String::from_str(&env, "PHOBTCLP"), - &, - &150, - ); -} - #[test] #[should_panic( expected = "Pool Stable: Initialize: First token must be alphabetically smaller than second token" @@ -174,8 +99,6 @@ fn pool_stable_initialization_should_fail_with_token_a_bigger_than_token_b() { std::mem::swap(&mut admin2, &mut admin1); } - let pool = StableLiquidityPoolClient::new(&env, &env.register(StableLiquidityPool, ())); - let token_wasm_hash = install_token_wasm(&env); let stake_wasm_hash = install_stake_wasm(&env); let _stake_reward_wasm_hash = install_stake_rewards_wasm(&env); @@ -208,15 +131,20 @@ fn pool_stable_initialization_should_fail_with_token_a_bigger_than_token_b() { token_init_info, stake_init_info, }; - - pool.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &factory, - &String::from_str(&env, "LP_SHARE_TOKEN"), - &String::from_str(&env, "PHOBTCLP"), - &, - &150, + let _ = StableLiquidityPoolClient::new( + &env, + &env.register( + StableLiquidityPool, + ( + &stake_wasm_hash, + &token_wasm_hash, + lp_init_info, + &factory, + String::from_str(&env, "LP_SHARE_TOKEN"), + String::from_str(&env, "PHOBTCLP"), + &, + &150i64, + ), + ), ); } From abd405a47ced44f10640f8f6e830826e6158bf00 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Thu, 9 Jan 2025 23:19:15 +0200 Subject: [PATCH 06/15] fixes the failing tests --- contracts/factory/src/contract.rs | 35 ++++++++++++++------------- contracts/factory/src/lib.rs | 14 +++++++++++ contracts/factory/src/tests/config.rs | 4 +-- contracts/factory/src/utils.rs | 16 ------------ 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index fa849dd3..a4b68cf4 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -6,7 +6,7 @@ use crate::{ save_lp_vec_with_tuple_as_key, save_stable_wasm_hash, set_initialized, Asset, Config, LiquidityPoolInfo, LpPortfolio, PairTupleKey, StakePortfolio, UserPortfolio, ADMIN, }, - utils::{deploy_and_initialize_multihop_contract, deploy_lp_contract}, + utils::deploy_and_initialize_multihop_contract, ConvertVec, }; use phoenix::{ @@ -18,8 +18,8 @@ use phoenix::{ utils::{LiquidityPoolInitInfo, PoolType, StakeInitInfo, TokenInitInfo}, }; use soroban_sdk::{ - contract, contractimpl, contractmeta, log, panic_with_error, vec, Address, BytesN, Env, - IntoVal, String, Symbol, Val, Vec, + contract, contractimpl, contractmeta, log, panic_with_error, vec, xdr::ToXdr, Address, Bytes, + BytesN, Env, IntoVal, String, Symbol, Val, Vec, }; // Metadata that is added on to the WASM custom section @@ -112,18 +112,6 @@ impl FactoryTrait for Factory { let stake_wasm_hash = config.stake_wasm_hash; let token_wasm_hash = config.token_wasm_hash; - let pool_hash = match pool_type { - PoolType::Xyk => config.lp_wasm_hash, - PoolType::Stable => get_stable_wasm_hash(&env), - }; - - let lp_contract_address = deploy_lp_contract( - &env, - pool_hash, - &lp_init_info.token_init_info.token_a, - &lp_init_info.token_init_info.token_b, - ); - validate_bps!( lp_init_info.swap_fee_bps, lp_init_info.max_allowed_slippage_bps, @@ -134,7 +122,6 @@ impl FactoryTrait for Factory { ); let factory_addr = env.current_contract_address(); - let init_fn: Symbol = Symbol::new(&env, "initialize"); let mut init_fn_args: Vec = ( stake_wasm_hash, token_wasm_hash, @@ -155,7 +142,21 @@ impl FactoryTrait for Factory { init_fn_args.push_back(max_allowed_fee_bps.into_val(&env)); - env.invoke_contract::(&lp_contract_address, &init_fn, init_fn_args); + let mut salt = Bytes::new(&env); + salt.append(&lp_init_info.token_init_info.token_a.clone().to_xdr(&env)); + salt.append(&lp_init_info.token_init_info.token_b.clone().to_xdr(&env)); + let salt = env.crypto().sha256(&salt); + + let lp_contract_address = match pool_type { + PoolType::Xyk => env + .deployer() + .with_current_contract(salt) + .deploy_v2(config.lp_wasm_hash, init_fn_args.clone()), + PoolType::Stable => env + .deployer() + .with_current_contract(salt) + .deploy_v2(get_stable_wasm_hash(&env), init_fn_args), + }; let mut lp_vec = get_lp_vec(&env); diff --git a/contracts/factory/src/lib.rs b/contracts/factory/src/lib.rs index 54e08c5f..eec45c75 100644 --- a/contracts/factory/src/lib.rs +++ b/contracts/factory/src/lib.rs @@ -23,6 +23,20 @@ pub mod stake_contract { ); } +//#[allow(clippy::too_many_arguments)] +//pub mod xyk_pool { +// soroban_sdk::contractimport!( +// file = "../../target/wasm32-unknown-unknown/release/phoenix_pool.wasm" +// ); +//} +// +//#[allow(clippy::too_many_arguments)] +//pub mod stable_pool { +// soroban_sdk::contractimport!( +// file = "../../target/wasm32-unknown-unknown/release/phoenix_pool_stable.wasm" +// ); +//} +// pub trait ConvertVec { fn convert_vec(&self) -> soroban_sdk::Vec; } diff --git a/contracts/factory/src/tests/config.rs b/contracts/factory/src/tests/config.rs index 75e0241c..57326979 100644 --- a/contracts/factory/src/tests/config.rs +++ b/contracts/factory/src/tests/config.rs @@ -483,9 +483,9 @@ fn factory_create_xyk_pool_with_amp_parameter_should_still_succeed() { &String::from_str(&env, "Pool Stable"), &String::from_str(&env, "EUROC/USDC"), &PoolType::Xyk, - &Some(10), + &Some(10u64), &100i64, - &1_000, + &1_000i64, ); let lp_contract_addr = factory.query_pools().get(0).unwrap(); diff --git a/contracts/factory/src/utils.rs b/contracts/factory/src/utils.rs index 6e9e41e1..94a6eb0d 100644 --- a/contracts/factory/src/utils.rs +++ b/contracts/factory/src/utils.rs @@ -1,21 +1,5 @@ use soroban_sdk::{xdr::ToXdr, Address, Bytes, BytesN, Env}; -pub fn deploy_lp_contract( - env: &Env, - wasm_hash: BytesN<32>, - token_a: &Address, - token_b: &Address, -) -> Address { - let mut salt = Bytes::new(env); - salt.append(&token_a.to_xdr(env)); - salt.append(&token_b.to_xdr(env)); - let salt = env.crypto().sha256(&salt); - - env.deployer() - .with_current_contract(salt) - .deploy_v2(wasm_hash, ()) -} - pub fn deploy_and_initialize_multihop_contract( env: Env, admin: Address, From cd953432d8919514db7c7fde738c3f45ec432213 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Thu, 9 Jan 2025 23:19:30 +0200 Subject: [PATCH 07/15] [no ci] removes comments --- contracts/factory/src/lib.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/contracts/factory/src/lib.rs b/contracts/factory/src/lib.rs index eec45c75..54e08c5f 100644 --- a/contracts/factory/src/lib.rs +++ b/contracts/factory/src/lib.rs @@ -23,20 +23,6 @@ pub mod stake_contract { ); } -//#[allow(clippy::too_many_arguments)] -//pub mod xyk_pool { -// soroban_sdk::contractimport!( -// file = "../../target/wasm32-unknown-unknown/release/phoenix_pool.wasm" -// ); -//} -// -//#[allow(clippy::too_many_arguments)] -//pub mod stable_pool { -// soroban_sdk::contractimport!( -// file = "../../target/wasm32-unknown-unknown/release/phoenix_pool_stable.wasm" -// ); -//} -// pub trait ConvertVec { fn convert_vec(&self) -> soroban_sdk::Vec; } From 5ac7e6ebe4aad40c75f366fe3c0710cab846b0fd Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Thu, 9 Jan 2025 23:31:16 +0200 Subject: [PATCH 08/15] removes redundant check if contract is initialized --- contracts/factory/src/contract.rs | 16 ++----- contracts/factory/src/error.rs | 15 +++---- contracts/factory/src/storage.rs | 18 -------- contracts/factory/src/tests.rs | 66 +--------------------------- contracts/multihop/src/contract.rs | 14 +----- contracts/multihop/src/error.rs | 7 ++- contracts/multihop/src/storage.rs | 17 ------- contracts/multihop/src/tests.rs | 24 ---------- contracts/multihop/src/tests/swap.rs | 2 +- contracts/pool/src/contract.rs | 12 +---- contracts/pool/src/error.rs | 24 +++++----- contracts/pool/src/storage.rs | 17 ------- 12 files changed, 29 insertions(+), 203 deletions(-) diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index a4b68cf4..394fd8f6 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -2,9 +2,9 @@ use crate::{ error::ContractError, stake_contract::StakedResponse, storage::{ - get_config, get_lp_vec, get_stable_wasm_hash, is_initialized, save_config, save_lp_vec, - save_lp_vec_with_tuple_as_key, save_stable_wasm_hash, set_initialized, Asset, Config, - LiquidityPoolInfo, LpPortfolio, PairTupleKey, StakePortfolio, UserPortfolio, ADMIN, + get_config, get_lp_vec, get_stable_wasm_hash, save_config, save_lp_vec, + save_lp_vec_with_tuple_as_key, save_stable_wasm_hash, Asset, Config, LiquidityPoolInfo, + LpPortfolio, PairTupleKey, StakePortfolio, UserPortfolio, ADMIN, }, utils::deploy_and_initialize_multihop_contract, ConvertVec, @@ -451,21 +451,11 @@ impl Factory { whitelisted_accounts: Vec
, lp_token_decimals: u32, ) { - if is_initialized(&env) { - log!( - &env, - "Factory: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - if whitelisted_accounts.is_empty() { log!(&env, "Factory: Initialize: there must be at least one whitelisted account able to create liquidity pools."); panic_with_error!(&env, ContractError::WhiteListeEmpty); } - set_initialized(&env); - let multihop_address = deploy_and_initialize_multihop_contract(env.clone(), admin.clone(), multihop_wasm_hash); diff --git a/contracts/factory/src/error.rs b/contracts/factory/src/error.rs index ced4476a..622f044b 100644 --- a/contracts/factory/src/error.rs +++ b/contracts/factory/src/error.rs @@ -4,12 +4,11 @@ use soroban_sdk::contracterror; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum ContractError { - AlreadyInitialized = 1, - WhiteListeEmpty = 2, - NotAuthorized = 3, - LiquidityPoolNotFound = 4, - TokenABiggerThanTokenB = 5, - MinStakeInvalid = 6, - MinRewardInvalid = 7, - AdminNotSet = 8, + WhiteListeEmpty = 1, + NotAuthorized = 2, + LiquidityPoolNotFound = 3, + TokenABiggerThanTokenB = 4, + MinStakeInvalid = 5, + MinRewardInvalid = 6, + AdminNotSet = 7, } diff --git a/contracts/factory/src/storage.rs b/contracts/factory/src/storage.rs index a82882a7..55044dd7 100644 --- a/contracts/factory/src/storage.rs +++ b/contracts/factory/src/storage.rs @@ -16,7 +16,6 @@ pub const ADMIN: Symbol = symbol_short!("ADMIN"); pub enum DataKey { Config = 1, LpVec = 2, - Initialized = 3, } #[derive(Clone)] @@ -233,20 +232,3 @@ pub fn save_lp_vec_with_tuple_as_key( PERSISTENT_BUMP_AMOUNT, ); } - -pub fn is_initialized(e: &Env) -> bool { - e.storage() - .persistent() - .get(&DataKey::Initialized) - .unwrap_or(false) -} - -pub fn set_initialized(e: &Env) { - e.storage().persistent().set(&DataKey::Initialized, &true); - - e.storage().persistent().extend_ttl( - &DataKey::Initialized, - PERSISTENT_LIFETIME_THRESHOLD, - PERSISTENT_BUMP_AMOUNT, - ); -} diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index db2f4a30..035cf4ae 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -1,67 +1,3 @@ -use soroban_sdk::{testutils::Address as _, vec, Address, Env}; - -use crate::contract::{Factory, FactoryClient}; - -use self::setup::{ - install_lp_contract, install_multihop_wasm, install_stable_lp, install_stake_wasm, - install_token_wasm, -}; - mod config; -mod setup; - mod queries; -#[test] -#[should_panic(expected = "Factory: Initialize: initializing contract twice is not allowed")] -fn test_deploy_factory_twice_should_fail() { - let env = Env::default(); - env.mock_all_auths(); - env.cost_estimate().budget().reset_unlimited(); - - let admin = Address::generate(&env); - - let auth_user = Address::generate(&env); - let multihop_wasm_hash = install_multihop_wasm(&env); - let lp_wasm_hash = install_lp_contract(&env); - let stable_wasm_hash = install_stable_lp(&env); - let stake_wasm_hash = install_stake_wasm(&env); - let token_wasm_hash = install_token_wasm(&env); - let whitelisted_accounts = vec![&env, auth_user]; - let contract_addr = Address::generate(&env); - - let _ = FactoryClient::new( - &env, - &env.register_at( - &contract_addr.clone(), - Factory {}, - ( - &admin, - &multihop_wasm_hash, - &lp_wasm_hash, - &stable_wasm_hash, - &stake_wasm_hash, - &token_wasm_hash, - whitelisted_accounts.clone(), - &10u32, - ), - ), - ); - - let _ = FactoryClient::new( - &env, - &env.register_at( - &contract_addr, - Factory {}, - ( - &admin, - &multihop_wasm_hash, - &lp_wasm_hash, - &stable_wasm_hash, - &stake_wasm_hash, - &token_wasm_hash, - whitelisted_accounts, - &10u32, - ), - ), - ); -} +mod setup; diff --git a/contracts/multihop/src/contract.rs b/contracts/multihop/src/contract.rs index 9334b0a9..8d4afd5b 100644 --- a/contracts/multihop/src/contract.rs +++ b/contracts/multihop/src/contract.rs @@ -8,8 +8,8 @@ use crate::factory_contract::PoolType; // FIXM: Disable Referral struct // use crate::lp_contract::Referral; use crate::storage::{ - get_admin_old, get_factory, is_initialized, save_admin_old, save_factory, set_initialized, - SimulateReverseSwapResponse, SimulateSwapResponse, Swap, ADMIN, + get_admin_old, get_factory, save_admin_old, save_factory, SimulateReverseSwapResponse, + SimulateSwapResponse, Swap, ADMIN, }; use crate::utils::{verify_reverse_swap, verify_swap}; use crate::{factory_contract, stable_pool, token_contract, xyk_pool}; @@ -278,16 +278,6 @@ impl MultihopTrait for Multihop { #[contractimpl] impl Multihop { pub fn __constructor(env: Env, admin: Address, factory: Address) { - if is_initialized(&env) { - log!( - &env, - "Multihop: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - set_initialized(&env); - save_admin_old(&env, &admin); save_factory(&env, factory); diff --git a/contracts/multihop/src/error.rs b/contracts/multihop/src/error.rs index c74c4b9b..2c4e0720 100644 --- a/contracts/multihop/src/error.rs +++ b/contracts/multihop/src/error.rs @@ -4,8 +4,7 @@ use soroban_sdk::contracterror; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum ContractError { - AlreadyInitialized = 1, - OperationsEmpty = 2, - IncorrectAssetSwap = 3, - AdminNotSet = 4, + OperationsEmpty = 1, + IncorrectAssetSwap = 2, + AdminNotSet = 3, } diff --git a/contracts/multihop/src/storage.rs b/contracts/multihop/src/storage.rs index bf889153..517aa2af 100644 --- a/contracts/multihop/src/storage.rs +++ b/contracts/multihop/src/storage.rs @@ -31,7 +31,6 @@ pub enum DataKey { PairKey(Pair), FactoryKey, Admin, - Initialized, } #[contracttype] @@ -137,19 +136,3 @@ pub fn _get_admin(env: &Env) -> Address { admin } - -pub fn is_initialized(e: &Env) -> bool { - e.storage() - .persistent() - .get(&DataKey::Initialized) - .unwrap_or(false) -} - -pub fn set_initialized(e: &Env) { - e.storage().persistent().set(&DataKey::Initialized, &true); - e.storage().persistent().extend_ttl( - &DataKey::Initialized, - PERSISTENT_LIFETIME_THRESHOLD, - PERSISTENT_BUMP_AMOUNT, - ); -} diff --git a/contracts/multihop/src/tests.rs b/contracts/multihop/src/tests.rs index 2b1605de..8119c4f6 100644 --- a/contracts/multihop/src/tests.rs +++ b/contracts/multihop/src/tests.rs @@ -1,27 +1,3 @@ -use crate::contract::{Multihop, MultihopClient}; -use soroban_sdk::{testutils::Address as _, Address, Env}; - mod query; mod setup; mod swap; - -#[test] -#[should_panic(expected = "Multihop: Initialize: initializing contract twice is not allowed")] -fn test_deploy_multihop_twice_should_fail() { - let env = Env::default(); - env.mock_all_auths(); - env.cost_estimate().budget().reset_unlimited(); - - let admin = Address::generate(&env); - let multihop_addr = Address::generate(&env); - let factory = Address::generate(&env); - - let _ = MultihopClient::new( - &env, - &env.register_at(&multihop_addr, Multihop, (&admin, factory.clone())), - ); - let _ = MultihopClient::new( - &env, - &env.register_at(&multihop_addr, Multihop, (admin, factory)), - ); -} diff --git a/contracts/multihop/src/tests/swap.rs b/contracts/multihop/src/tests/swap.rs index 3234b6a0..313f5071 100644 --- a/contracts/multihop/src/tests/swap.rs +++ b/contracts/multihop/src/tests/swap.rs @@ -726,7 +726,7 @@ fn test_v_phx_vul_013_add_belief_price_for_every_swap() { } #[test] -#[should_panic(expected = "Error(Contract, #21)")] +#[should_panic(expected = "Error(Contract, #20)")] fn test_swap_with_ask_asset_min_amount() { let env = Env::default(); let admin = Address::generate(&env); diff --git a/contracts/pool/src/contract.rs b/contracts/pool/src/contract.rs index 0430d089..8fd1fce3 100644 --- a/contracts/pool/src/contract.rs +++ b/contracts/pool/src/contract.rs @@ -9,7 +9,7 @@ use crate::{ stake_contract, storage::{ get_config, get_default_slippage_bps, save_config, save_default_slippage_bps, - utils::{self, get_admin_old, is_initialized, set_initialized}, + utils::{self, get_admin_old}, Asset, ComputeSwap, Config, LiquidityPoolInfo, PairType, PoolResponse, SimulateReverseSwapResponse, SimulateSwapResponse, ADMIN, }, @@ -663,14 +663,6 @@ impl LiquidityPool { default_slippage_bps: i64, max_allowed_fee_bps: i64, ) { - if is_initialized(&env) { - log!( - &env, - "Pool: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - let admin = lp_init_info.admin; let swap_fee_bps = lp_init_info.swap_fee_bps; let fee_recipient = lp_init_info.fee_recipient; @@ -698,8 +690,6 @@ impl LiquidityPool { panic_with_error!(&env, ContractError::SwapFeeBpsOverLimit); } - set_initialized(&env); - // Token info let token_a = token_init_info.token_a; let token_b = token_init_info.token_b; diff --git a/contracts/pool/src/error.rs b/contracts/pool/src/error.rs index e16cb476..e2c05d74 100644 --- a/contracts/pool/src/error.rs +++ b/contracts/pool/src/error.rs @@ -23,17 +23,15 @@ pub enum ContractError { DesiredAmountsBelowOrEqualZero = 14, MinAmountsBelowZero = 15, AssetNotInPool = 16, - AlreadyInitialized = 17, - TokenABiggerThanTokenB = 18, - InvalidBps = 19, - SlippageInvalid = 20, - - SwapMinReceivedBiggerThanReturn = 21, - TransactionAfterTimestampDeadline = 22, - CannotConvertU256ToI128 = 23, - UserDeclinesPoolFee = 24, - SwapFeeBpsOverLimit = 25, - NotEnoughSharesToBeMinted = 26, - NotEnoughLiquidityProvided = 27, - AdminNotSet = 28, + TokenABiggerThanTokenB = 17, + InvalidBps = 18, + SlippageInvalid = 19, + SwapMinReceivedBiggerThanReturn = 20, + TransactionAfterTimestampDeadline = 21, + CannotConvertU256ToI128 = 22, + UserDeclinesPoolFee = 23, + SwapFeeBpsOverLimit = 24, + NotEnoughSharesToBeMinted = 25, + NotEnoughLiquidityProvided = 26, + AdminNotSet = 27, } diff --git a/contracts/pool/src/storage.rs b/contracts/pool/src/storage.rs index a8062dc4..ecfb672b 100644 --- a/contracts/pool/src/storage.rs +++ b/contracts/pool/src/storage.rs @@ -16,7 +16,6 @@ pub enum DataKey { ReserveA = 1, ReserveB = 2, Admin = 3, - Initialized = 4, } impl TryFromVal for Val { @@ -456,22 +455,6 @@ pub mod utils { (amount_a, amount_b) } - - pub fn is_initialized(e: &Env) -> bool { - e.storage() - .persistent() - .get(&DataKey::Initialized) - .unwrap_or(false) - } - - pub fn set_initialized(e: &Env) { - e.storage().persistent().set(&DataKey::Initialized, &true); - e.storage().persistent().extend_ttl( - &DataKey::Initialized, - PERSISTENT_LIFETIME_THRESHOLD, - PERSISTENT_BUMP_AMOUNT, - ); - } } #[cfg(test)] From 8002d1aebe28259b2d37163c70643759583d1b3c Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Fri, 10 Jan 2025 10:39:02 +0200 Subject: [PATCH 09/15] stake to use constructors --- contracts/stake/src/contract.rs | 122 ++++++++++++----------------- contracts/stake/src/error.rs | 27 +++---- contracts/stake/src/storage.rs | 14 ---- contracts/stake/src/tests/bond.rs | 103 ++++++++++-------------- contracts/stake/src/tests/setup.rs | 25 +++--- 5 files changed, 119 insertions(+), 172 deletions(-) diff --git a/contracts/stake/src/contract.rs b/contracts/stake/src/contract.rs index de24bf62..f10b7e39 100644 --- a/contracts/stake/src/contract.rs +++ b/contracts/stake/src/contract.rs @@ -15,7 +15,6 @@ use crate::{ get_config, get_stakes, save_config, save_stakes, utils::{ self, add_distribution, get_admin_old, get_distributions, get_total_staked_counter, - is_initialized, set_initialized, }, Config, Stake, ADMIN, }, @@ -33,19 +32,6 @@ pub struct Staking; #[allow(dead_code)] pub trait StakingTrait { - // Sets the token contract addresses for this pool - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - admin: Address, - lp_token: Address, - min_bond: i128, - min_reward: i128, - manager: Address, - owner: Address, - max_complexity: u32, - ); - fn bond(env: Env, sender: Address, tokens: i128); fn unbond(env: Env, sender: Address, stake_amount: i128, stake_timestamp: u64); @@ -79,65 +65,6 @@ pub trait StakingTrait { #[contractimpl] impl StakingTrait for Staking { - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - admin: Address, - lp_token: Address, - min_bond: i128, - min_reward: i128, - manager: Address, - owner: Address, - max_complexity: u32, - ) { - if is_initialized(&env) { - log!( - &env, - "Stake: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - set_initialized(&env); - - if min_bond <= 0 { - log!( - &env, - "Stake: initialize: Minimum amount of lp share tokens to bond can not be smaller or equal to 0" - ); - panic_with_error!(&env, ContractError::InvalidMinBond); - } - if min_reward <= 0 { - log!(&env, "Stake: initialize: min_reward must be bigger than 0!"); - panic_with_error!(&env, ContractError::InvalidMinReward); - } - - if max_complexity == 0 { - log!( - &env, - "Stake: initialize: max_complexity must be bigger than 0!" - ); - panic_with_error!(&env, ContractError::InvalidMaxComplexity); - } - - env.events() - .publish(("initialize", "LP Share token staking contract"), &lp_token); - - let config = Config { - lp_token, - min_bond, - min_reward, - manager, - owner, - max_complexity, - }; - save_config(&env, config); - - utils::save_admin_old(&env, &admin); - utils::init_total_staked(&env); - save_total_staked_history(&env, map![&env]); - } - fn bond(env: Env, sender: Address, tokens: i128) { sender.require_auth(); env.storage() @@ -393,6 +320,55 @@ impl StakingTrait for Staking { #[contractimpl] impl Staking { + #[allow(clippy::too_many_arguments)] + pub fn __constructor( + env: Env, + admin: Address, + lp_token: Address, + min_bond: i128, + min_reward: i128, + manager: Address, + owner: Address, + max_complexity: u32, + ) { + if min_bond <= 0 { + log!( + &env, + "Stake: initialize: Minimum amount of lp share tokens to bond can not be smaller or equal to 0" + ); + panic_with_error!(&env, ContractError::InvalidMinBond); + } + if min_reward <= 0 { + log!(&env, "Stake: initialize: min_reward must be bigger than 0!"); + panic_with_error!(&env, ContractError::InvalidMinReward); + } + + if max_complexity == 0 { + log!( + &env, + "Stake: initialize: max_complexity must be bigger than 0!" + ); + panic_with_error!(&env, ContractError::InvalidMaxComplexity); + } + + env.events() + .publish(("initialize", "LP Share token staking contract"), &lp_token); + + let config = Config { + lp_token, + min_bond, + min_reward, + manager, + owner, + max_complexity, + }; + save_config(&env, config); + + utils::save_admin_old(&env, &admin); + utils::init_total_staked(&env); + save_total_staked_history(&env, map![&env]); + } + #[allow(dead_code)] pub fn update(env: Env, new_wasm_hash: BytesN<32>) { let admin = get_admin_old(&env); diff --git a/contracts/stake/src/error.rs b/contracts/stake/src/error.rs index f5670291..a45baec4 100644 --- a/contracts/stake/src/error.rs +++ b/contracts/stake/src/error.rs @@ -4,18 +4,17 @@ use soroban_sdk::contracterror; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum ContractError { - AlreadyInitialized = 1, - InvalidMinBond = 2, - InvalidMinReward = 3, - InvalidBond = 4, - Unauthorized = 5, - MinRewardNotEnough = 6, - RewardsInvalid = 7, - StakeNotFound = 8, - InvalidTime = 9, - DistributionExists = 10, - InvalidRewardAmount = 11, - InvalidMaxComplexity = 12, - DistributionNotFound = 13, - AdminNotSet = 14, + InvalidMinBond = 1, + InvalidMinReward = 2, + InvalidBond = 3, + Unauthorized = 4, + MinRewardNotEnough = 5, + RewardsInvalid = 6, + StakeNotFound = 7, + InvalidTime = 8, + DistributionExists = 9, + InvalidRewardAmount = 10, + InvalidMaxComplexity = 11, + DistributionNotFound = 12, + AdminNotSet = 13, } diff --git a/contracts/stake/src/storage.rs b/contracts/stake/src/storage.rs index e8864a0e..5f5e17f5 100644 --- a/contracts/stake/src/storage.rs +++ b/contracts/stake/src/storage.rs @@ -124,20 +124,6 @@ pub mod utils { } } - pub fn is_initialized(e: &Env) -> bool { - e.storage() - .instance() - .get(&DataKey::Initialized) - .unwrap_or(false) - } - - pub fn set_initialized(e: &Env) { - e.storage().instance().set(&DataKey::Initialized, &true); - e.storage() - .instance() - .extend_ttl(PERSISTENT_LIFETIME_THRESHOLD, PERSISTENT_BUMP_AMOUNT); - } - pub fn save_admin_old(e: &Env, address: &Address) { e.storage().persistent().set(&DataKey::Admin, address); e.storage().persistent().extend_ttl( diff --git a/contracts/stake/src/tests/bond.rs b/contracts/stake/src/tests/bond.rs index 74dba88b..6b64f793 100644 --- a/contracts/stake/src/tests/bond.rs +++ b/contracts/stake/src/tests/bond.rs @@ -56,37 +56,6 @@ fn initialize_staking_contract() { assert_eq!(response, admin); } -#[test] -#[should_panic(expected = "Stake: Initialize: initializing contract twice is not allowed")] -fn test_deploying_stake_twice_should_fail() { - let env = Env::default(); - env.mock_all_auths(); - - let admin = Address::generate(&env); - let lp_token = deploy_token_contract(&env, &admin); - let manager = Address::generate(&env); - let owner = Address::generate(&env); - - let first = deploy_staking_contract( - &env, - admin.clone(), - &lp_token.address, - &manager, - &owner, - &DEFAULT_COMPLEXITY, - ); - - first.initialize( - &admin, - &lp_token.address, - &100i128, - &50i128, - &manager, - &owner, - &DEFAULT_COMPLEXITY, - ); -} - #[test] #[should_panic = "Stake: Bond: Trying to stake less than minimum required"] fn bond_too_few() { @@ -409,16 +378,20 @@ fn initialize_staking_contract_should_panic_when_min_bond_invalid() { let env = Env::default(); env.mock_all_auths(); - let staking = StakingClient::new(&env, &env.register(Staking, ())); - - staking.initialize( - &Address::generate(&env), - &Address::generate(&env), - &0, - &1_000, - &Address::generate(&env), - &Address::generate(&env), - &DEFAULT_COMPLEXITY, + let _ = StakingClient::new( + &env, + &env.register( + Staking, + ( + &Address::generate(&env), + &Address::generate(&env), + &0i128, + &1_000i128, + &Address::generate(&env), + &Address::generate(&env), + &DEFAULT_COMPLEXITY, + ), + ), ); } @@ -428,16 +401,20 @@ fn initialize_staking_contract_should_panic_when_min_rewards_invalid() { let env = Env::default(); env.mock_all_auths(); - let staking = StakingClient::new(&env, &env.register(Staking, ())); - - staking.initialize( - &Address::generate(&env), - &Address::generate(&env), - &1_000, - &0, - &Address::generate(&env), - &Address::generate(&env), - &DEFAULT_COMPLEXITY, + let _ = StakingClient::new( + &env, + &env.register( + Staking, + ( + &Address::generate(&env), + &Address::generate(&env), + &1_000i128, + &0i128, + &Address::generate(&env), + &Address::generate(&env), + &DEFAULT_COMPLEXITY, + ), + ), ); } @@ -447,15 +424,19 @@ fn initialize_staking_contract_should_panic_when_max_complexity_invalid() { let env = Env::default(); env.mock_all_auths(); - let staking = StakingClient::new(&env, &env.register(Staking, ())); - - staking.initialize( - &Address::generate(&env), - &Address::generate(&env), - &1_000, - &1_000, - &Address::generate(&env), - &Address::generate(&env), - &0u32, + let _ = StakingClient::new( + &env, + &env.register( + Staking, + ( + &Address::generate(&env), + &Address::generate(&env), + &1_000i128, + &1_000i128, + &Address::generate(&env), + &Address::generate(&env), + &0u32, + ), + ), ); } diff --git a/contracts/stake/src/tests/setup.rs b/contracts/stake/src/tests/setup.rs index 9d393a5a..348ad4d2 100644 --- a/contracts/stake/src/tests/setup.rs +++ b/contracts/stake/src/tests/setup.rs @@ -40,17 +40,22 @@ pub fn deploy_staking_contract<'a>( max_complexity: &u32, ) -> StakingClient<'a> { let admin = admin.into().unwrap_or(Address::generate(env)); - let staking = StakingClient::new(env, &env.register(Staking, ())); - - staking.initialize( - &admin, - lp_token, - &MIN_BOND, - &MIN_REWARD, - manager, - owner, - max_complexity, + let staking = StakingClient::new( + env, + &env.register( + Staking, + ( + &admin, + lp_token, + &MIN_BOND, + &MIN_REWARD, + manager, + owner, + max_complexity, + ), + ), ); + staking } From 121b2c0a45f65c2c69d62713c1fbfb2d8ca6a99b Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Fri, 10 Jan 2025 11:12:39 +0200 Subject: [PATCH 10/15] fixes the failing build --- contracts/pool/src/contract.rs | 12 ++++++------ contracts/pool/src/storage.rs | 28 +++++++++++++++++++++++---- contracts/pool_stable/src/contract.rs | 12 ++++++------ contracts/pool_stable/src/storage.rs | 28 +++++++++++++++++++++++---- contracts/stake/src/storage.rs | 3 +-- 5 files changed, 61 insertions(+), 22 deletions(-) diff --git a/contracts/pool/src/contract.rs b/contracts/pool/src/contract.rs index 8fd1fce3..75cb5627 100644 --- a/contracts/pool/src/contract.rs +++ b/contracts/pool/src/contract.rs @@ -6,7 +6,6 @@ use num_integer::Roots; use crate::{ error::ContractError, - stake_contract, storage::{ get_config, get_default_slippage_bps, save_config, save_default_slippage_bps, utils::{self, get_admin_old}, @@ -727,15 +726,16 @@ impl LiquidityPool { share_token_symbol, ); - let stake_contract_address = utils::deploy_stake_contract(&env, stake_wasm_hash); - stake_contract::Client::new(&env, &stake_contract_address).initialize( + let stake_contract_address = utils::deploy_stake_contract( + &env, + stake_wasm_hash, &admin, &share_token_address, - &min_bond, - &min_reward, + min_bond, + min_reward, &manager, &factory_addr, - &stake_init_info.max_complexity, + stake_init_info.max_complexity, ); let config = Config { diff --git a/contracts/pool/src/storage.rs b/contracts/pool/src/storage.rs index ecfb672b..695c5a68 100644 --- a/contracts/pool/src/storage.rs +++ b/contracts/pool/src/storage.rs @@ -206,13 +206,33 @@ pub mod utils { .deploy_v2(token_wasm_hash, (admin, decimals, name, symbol)) } - pub fn deploy_stake_contract(e: &Env, stake_wasm_hash: BytesN<32>) -> Address { + #[allow(clippy::too_many_arguments)] + pub fn deploy_stake_contract( + e: &Env, + stake_wasm_hash: BytesN<32>, + admin: &Address, + share_token_address: &Address, + min_bond: i128, + min_reward: i128, + manager: &Address, + factory_addr: &Address, + max_complexity: u32, + ) -> Address { let salt = Bytes::new(e); let salt = e.crypto().sha256(&salt); - e.deployer() - .with_current_contract(salt) - .deploy_v2(stake_wasm_hash, ()) + e.deployer().with_current_contract(salt).deploy_v2( + stake_wasm_hash, + ( + admin, + share_token_address, + min_bond, + min_reward, + manager, + factory_addr, + max_complexity, + ), + ) } pub fn save_admin_old(e: &Env, address: Address) { diff --git a/contracts/pool_stable/src/contract.rs b/contracts/pool_stable/src/contract.rs index 6d50f1c2..2fee3e21 100644 --- a/contracts/pool_stable/src/contract.rs +++ b/contracts/pool_stable/src/contract.rs @@ -9,7 +9,6 @@ use soroban_sdk::{ use crate::{ error::ContractError, math::{calc_y, compute_current_amp, compute_d, scale_value, AMP_PRECISION}, - stake_contract, storage::{ get_amp, get_config, get_greatest_precision, get_precisions, save_amp, save_config, save_greatest_precision, @@ -752,15 +751,16 @@ impl StableLiquidityPool { share_token_symbol, ); - let stake_contract_address = utils::deploy_stake_contract(&env, stake_wasm_hash); - stake_contract::Client::new(&env, &stake_contract_address).initialize( + let stake_contract_address = utils::deploy_stake_contract( + &env, + stake_wasm_hash, &admin, &share_token_address, - &min_bond, - &min_reward, + min_bond, + min_reward, &manager, &factory_addr, - &stake_init_info.max_complexity, + stake_init_info.max_complexity, ); let config = Config { diff --git a/contracts/pool_stable/src/storage.rs b/contracts/pool_stable/src/storage.rs index 533d68c8..1df023e6 100644 --- a/contracts/pool_stable/src/storage.rs +++ b/contracts/pool_stable/src/storage.rs @@ -245,13 +245,33 @@ pub mod utils { .deploy_v2(token_wasm_hash, (admin, decimals, name, symbol)) } - pub fn deploy_stake_contract(e: &Env, stake_wasm_hash: BytesN<32>) -> Address { + #[allow(clippy::too_many_arguments)] + pub fn deploy_stake_contract( + e: &Env, + stake_wasm_hash: BytesN<32>, + admin: &Address, + share_token_address: &Address, + min_bond: i128, + min_reward: i128, + manager: &Address, + factory_addr: &Address, + max_complexity: u32, + ) -> Address { let salt = Bytes::new(e); let salt = e.crypto().sha256(&salt); - e.deployer() - .with_current_contract(salt) - .deploy_v2(stake_wasm_hash, ()) + e.deployer().with_current_contract(salt).deploy_v2( + stake_wasm_hash, + ( + admin, + share_token_address, + min_bond, + min_reward, + manager, + factory_addr, + max_complexity, + ), + ) } pub fn save_admin_old(e: &Env, address: Address) { diff --git a/contracts/stake/src/storage.rs b/contracts/stake/src/storage.rs index 5f5e17f5..b1f58a76 100644 --- a/contracts/stake/src/storage.rs +++ b/contracts/stake/src/storage.rs @@ -112,8 +112,7 @@ pub mod utils { Admin = 0, TotalStaked = 1, Distributions = 2, - Initialized = 3, - StakeRewards = 4, + StakeRewards = 3, } impl TryFromVal for Val { From a2d27ba2988fa95f98a81ac21844cc08cfec774c Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Fri, 10 Jan 2025 11:12:47 +0200 Subject: [PATCH 11/15] stake rewards now uses constructor --- contracts/stake_rewards/src/contract.rs | 110 +++++++++------------ contracts/stake_rewards/src/error.rs | 25 +++-- contracts/stake_rewards/src/storage.rs | 17 ---- contracts/stake_rewards/src/tests/setup.rs | 23 +++-- 4 files changed, 70 insertions(+), 105 deletions(-) diff --git a/contracts/stake_rewards/src/contract.rs b/contracts/stake_rewards/src/contract.rs index a320372c..0a2d9f93 100644 --- a/contracts/stake_rewards/src/contract.rs +++ b/contracts/stake_rewards/src/contract.rs @@ -18,7 +18,7 @@ use crate::{ msg::{AnnualizedRewardResponse, ConfigResponse, WithdrawableRewardResponse}, storage::{ get_config, save_config, - utils::{self, get_admin_old, is_initialized, set_initialized}, + utils::{self, get_admin_old}, BondingInfo, Config, }, token_contract, @@ -36,18 +36,6 @@ pub struct StakingRewards; #[allow(dead_code)] pub trait StakingRewardsTrait { - // Sets the token contract addresses for this pool - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - admin: Address, - staking_contract: Address, - reward_token: Address, - max_complexity: u32, - min_reward: i128, - min_bond: i128, - ); - fn add_user(env: Env, user: Address, stakes: BondingInfo); fn calculate_bond(env: Env, sender: Address, stakes: BondingInfo); @@ -83,59 +71,6 @@ pub trait StakingRewardsTrait { #[contractimpl] impl StakingRewardsTrait for StakingRewards { - #[allow(clippy::too_many_arguments)] - fn initialize( - env: Env, - admin: Address, - staking_contract: Address, - reward_token: Address, - max_complexity: u32, - min_reward: i128, - min_bond: i128, - ) { - if is_initialized(&env) { - log!( - &env, - "Stake rewards: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - set_initialized(&env); - - env.events().publish( - ("initialize", "StakingRewards rewards distribution contract"), - (), - ); - - let config = Config { - staking_contract, - reward_token: reward_token.clone(), - max_complexity, - min_reward, - min_bond, - }; - save_config(&env, config); - - let distribution = Distribution { - shares_per_point: 1u128, - shares_leftover: 0u64, - distributed_total: 0u128, - withdrawable_total: 0u128, - max_bonus_bps: 0u64, - bonus_per_day_bps: 0u64, - }; - - save_distribution(&env, &reward_token, &distribution); - // Create the default reward distribution curve which is just a flat 0 const - save_reward_curve(&env, reward_token.clone(), &Curve::Constant(0)); - - env.events() - .publish(("create_distribution_flow", "asset"), &reward_token); - - utils::save_admin_old(&env, &admin); - } - fn add_user(env: Env, user: Address, stakes: BondingInfo) { let config = get_config(&env); // only Staking contract which deployed this one can call this method @@ -546,6 +481,49 @@ impl StakingRewardsTrait for StakingRewards { #[contractimpl] impl StakingRewards { + #[allow(clippy::too_many_arguments)] + pub fn __constructor( + env: Env, + admin: Address, + staking_contract: Address, + reward_token: Address, + max_complexity: u32, + min_reward: i128, + min_bond: i128, + ) { + env.events().publish( + ("initialize", "StakingRewards rewards distribution contract"), + (), + ); + + let config = Config { + staking_contract, + reward_token: reward_token.clone(), + max_complexity, + min_reward, + min_bond, + }; + save_config(&env, config); + + let distribution = Distribution { + shares_per_point: 1u128, + shares_leftover: 0u64, + distributed_total: 0u128, + withdrawable_total: 0u128, + max_bonus_bps: 0u64, + bonus_per_day_bps: 0u64, + }; + + save_distribution(&env, &reward_token, &distribution); + // Create the default reward distribution curve which is just a flat 0 const + save_reward_curve(&env, reward_token.clone(), &Curve::Constant(0)); + + env.events() + .publish(("create_distribution_flow", "asset"), &reward_token); + + utils::save_admin_old(&env, &admin); + } + #[allow(dead_code)] pub fn update(env: Env, new_wasm_hash: BytesN<32>) { let admin = get_admin_old(&env); diff --git a/contracts/stake_rewards/src/error.rs b/contracts/stake_rewards/src/error.rs index 3587d74c..fcab1c6d 100644 --- a/contracts/stake_rewards/src/error.rs +++ b/contracts/stake_rewards/src/error.rs @@ -4,17 +4,16 @@ use soroban_sdk::contracterror; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum ContractError { - AlreadyInitialized = 1, - InvalidMinBond = 2, - InvalidMinReward = 3, - InvalidBond = 4, - Unauthorized = 5, - MinRewardNotEnough = 6, - RewardsInvalid = 7, - StakeNotFound = 8, - InvalidTime = 9, - DistributionExists = 10, - InvalidRewardAmount = 11, - InvalidMaxComplexity = 12, - AdminNotSet = 13, + InvalidMinBond = 1, + InvalidMinReward = 2, + InvalidBond = 3, + Unauthorized = 4, + MinRewardNotEnough = 5, + RewardsInvalid = 6, + StakeNotFound = 7, + InvalidTime = 8, + DistributionExists = 9, + InvalidRewardAmount = 10, + InvalidMaxComplexity = 11, + AdminNotSet = 12, } diff --git a/contracts/stake_rewards/src/storage.rs b/contracts/stake_rewards/src/storage.rs index 527bd10f..e0b9db4b 100644 --- a/contracts/stake_rewards/src/storage.rs +++ b/contracts/stake_rewards/src/storage.rs @@ -55,7 +55,6 @@ pub mod utils { #[derive(Clone, Copy)] #[repr(u32)] pub enum DataKey { - Initialized = 0, Admin = 1, } @@ -67,22 +66,6 @@ pub mod utils { } } - pub fn is_initialized(e: &Env) -> bool { - e.storage() - .persistent() - .get(&DataKey::Initialized) - .unwrap_or(false) - } - - pub fn set_initialized(e: &Env) { - e.storage().persistent().set(&DataKey::Initialized, &true); - e.storage().persistent().extend_ttl( - &DataKey::Initialized, - PERSISTENT_LIFETIME_THRESHOLD, - PERSISTENT_BUMP_AMOUNT, - ); - } - pub fn save_admin_old(e: &Env, address: &Address) { e.storage().persistent().set(&DataKey::Admin, address); e.storage().persistent().extend_ttl( diff --git a/contracts/stake_rewards/src/tests/setup.rs b/contracts/stake_rewards/src/tests/setup.rs index 341a5409..1785cf20 100644 --- a/contracts/stake_rewards/src/tests/setup.rs +++ b/contracts/stake_rewards/src/tests/setup.rs @@ -23,15 +23,20 @@ pub fn deploy_staking_rewards_contract<'a>( reward_token: &Address, staking_contract: &Address, ) -> StakingRewardsClient<'a> { - let staking_rewards = StakingRewardsClient::new(env, &env.register(StakingRewards, ())); - - staking_rewards.initialize( - admin, - staking_contract, - reward_token, - &MAX_COMPLEXITY, - &MIN_REWARD, - &MIN_BOND, + let staking_rewards = StakingRewardsClient::new( + env, + &env.register( + StakingRewards, + ( + admin, + staking_contract, + reward_token, + &MAX_COMPLEXITY, + &MIN_REWARD, + &MIN_BOND, + ), + ), ); + staking_rewards } From 626c194c3f035b0ef420015100add246c087c75e Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Fri, 10 Jan 2025 16:22:32 +0200 Subject: [PATCH 12/15] trader - constructor --- contracts/trader/src/contract.rs | 77 ++++++------- contracts/trader/src/error.rs | 3 +- contracts/trader/src/storage.rs | 18 --- contracts/trader/src/tests/msgs.rs | 170 +++++++++------------------- contracts/trader/src/tests/setup.rs | 58 +++++----- 5 files changed, 116 insertions(+), 210 deletions(-) diff --git a/contracts/trader/src/contract.rs b/contracts/trader/src/contract.rs index 4ad5d7fa..c1226d97 100644 --- a/contracts/trader/src/contract.rs +++ b/contracts/trader/src/contract.rs @@ -7,9 +7,8 @@ use crate::{ error::ContractError, lp_contract, storage::{ - get_admin_old, get_name, get_output_token, get_pair, is_initialized, save_admin_old, - save_name, save_output_token, save_pair, set_initialized, Asset, BalanceInfo, - OutputTokenInfo, ADMIN, + get_admin_old, get_name, get_output_token, get_pair, save_admin_old, save_name, + save_output_token, save_pair, Asset, BalanceInfo, OutputTokenInfo, ADMIN, }, token_contract, }; @@ -24,14 +23,6 @@ pub struct Trader; #[allow(dead_code)] pub trait TraderTrait { - fn initialize( - env: Env, - admin: Address, - contract_name: String, - pair_addresses: (Address, Address), - output_token: Address, - ); - #[allow(clippy::too_many_arguments)] fn trade_token( env: Env, @@ -68,40 +59,6 @@ pub trait TraderTrait { #[contractimpl] impl TraderTrait for Trader { - fn initialize( - env: Env, - admin: Address, - contract_name: String, - pair_addresses: (Address, Address), - output_token: Address, - ) { - admin.require_auth(); - - if is_initialized(&env) { - log!(&env, "Trader: Initialize: Cannot initialize trader twice!"); - panic_with_error!(env, ContractError::AlreadyInitialized) - } - - save_admin_old(&env, &admin); - - save_name(&env, &contract_name); - - save_pair(&env, &pair_addresses); - - save_output_token(&env, &output_token); - - set_initialized(&env); - - env.events() - .publish(("Trader: Initialize", "admin: "), &admin); - env.events() - .publish(("Trader: Initialize", "contract name: "), contract_name); - env.events() - .publish(("Trader: Initialize", "pairs: "), pair_addresses); - env.events() - .publish(("Trader: Initialize", "PHO token: "), output_token); - } - #[allow(clippy::too_many_arguments)] fn trade_token( env: Env, @@ -278,3 +235,33 @@ impl TraderTrait for Trader { Ok(()) } } + +#[contractimpl] +impl Trader { + pub fn __constructor( + env: Env, + admin: Address, + contract_name: String, + pair_addresses: (Address, Address), + output_token: Address, + ) { + admin.require_auth(); + + save_admin_old(&env, &admin); + + save_name(&env, &contract_name); + + save_pair(&env, &pair_addresses); + + save_output_token(&env, &output_token); + + env.events() + .publish(("Trader: Initialize", "admin: "), &admin); + env.events() + .publish(("Trader: Initialize", "contract name: "), contract_name); + env.events() + .publish(("Trader: Initialize", "pairs: "), pair_addresses); + env.events() + .publish(("Trader: Initialize", "PHO token: "), output_token); + } +} diff --git a/contracts/trader/src/error.rs b/contracts/trader/src/error.rs index ec32bb68..08efe730 100644 --- a/contracts/trader/src/error.rs +++ b/contracts/trader/src/error.rs @@ -13,6 +13,5 @@ pub enum ContractError { SwapTokenNotInPair = 7, InvalidMaxSpreadBps = 8, InitValueNotFound = 9, - AlreadyInitialized = 10, - AdminNotSet = 11, + AdminNotSet = 10, } diff --git a/contracts/trader/src/storage.rs b/contracts/trader/src/storage.rs index d4853e7c..8ccb6c7e 100644 --- a/contracts/trader/src/storage.rs +++ b/contracts/trader/src/storage.rs @@ -183,21 +183,3 @@ pub fn get_output_token(env: &Env) -> Address { token_addr } - -pub fn set_initialized(env: &Env) { - env.storage() - .persistent() - .set(&DataKey::IsInitialized, &true); - env.storage().persistent().extend_ttl( - &DataKey::IsInitialized, - PERSISTENT_LIFETIME_THRESHOLD, - PERSISTENT_BUMP_AMOUNT, - ); -} - -pub fn is_initialized(env: &Env) -> bool { - env.storage() - .persistent() - .get(&DataKey::IsInitialized) - .unwrap_or_default() -} diff --git a/contracts/trader/src/tests/msgs.rs b/contracts/trader/src/tests/msgs.rs index 572c9df0..3d1bd307 100644 --- a/contracts/trader/src/tests/msgs.rs +++ b/contracts/trader/src/tests/msgs.rs @@ -41,57 +41,10 @@ fn initialize() { &String::from_str(&env, "PHO"), ); - let trader_client = deploy_trader_client(&env); - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), usdc_token.address.clone()), - &pho_token.address, - ); - - assert_eq!(trader_client.query_admin_address(), admin); - assert_eq!(trader_client.query_contract_name(), contract_name); - assert_eq!( - trader_client.query_trading_pairs(), - (xlm_token.address, usdc_token.address) - ); -} - -#[test] -#[should_panic(expected = "Trader: Initialize: Cannot initialize trader twice!")] -fn initialize_twice_should_panic() { - let env = Env::default(); - env.mock_all_auths(); - env.cost_estimate().budget().reset_unlimited(); - - let admin = Address::generate(&env); - let contract_name = String::from_str(&env, "XLM/USDC"); - let xlm_token = deploy_token_contract( - &env, - &admin, - &6, - &String::from_str(&env, "Stellar"), - &String::from_str(&env, "XLM"), - ); - let usdc_token = deploy_token_contract( - &env, - &admin, - &6, - &String::from_str(&env, "USD Coin"), - &String::from_str(&env, "USDC"), - ); - let pho_token = deploy_token_contract( + let trader_client = deploy_trader_client( &env, &admin, - &6, - &String::from_str(&env, "Phoenix"), - &String::from_str(&env, "PHO"), - ); - - let trader_client = deploy_trader_client(&env); - trader_client.initialize( - &admin, - &contract_name, + contract_name.clone(), &(xlm_token.address.clone(), usdc_token.address.clone()), &pho_token.address, ); @@ -100,15 +53,7 @@ fn initialize_twice_should_panic() { assert_eq!(trader_client.query_contract_name(), contract_name); assert_eq!( trader_client.query_trading_pairs(), - (xlm_token.address.clone(), usdc_token.address.clone()) - ); - - // second time should fail - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), usdc_token.address.clone()), - &pho_token.address, + (xlm_token.address, usdc_token.address) ); } @@ -152,7 +97,13 @@ fn simple_trade_token_and_transfer_token() { xlm_token.mint(&admin, &1_000_000); output_token.mint(&admin, &2_000_000); - let trader_client = deploy_trader_client(&env); + let trader_client = deploy_trader_client( + &env, + &admin, + contract_name, + &(xlm_token.address.clone(), usdc_token.address.clone()), + &output_token.address, + ); let xlm_pho_client: crate::lp_contract::Client<'_> = deploy_and_init_lp_client( &env, @@ -164,13 +115,6 @@ fn simple_trade_token_and_transfer_token() { 0, ); - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), usdc_token.address.clone()), - &output_token.address, - ); - xlm_token.mint(&trader_client.address, &1_000); assert_eq!( @@ -270,7 +214,13 @@ fn extended_trade_and_transfer_token() { usdc_token.mint(&admin, &3_000_000); output_token.mint(&admin, &2_000_000); - let trader_client = deploy_trader_client(&env); + let trader_client = deploy_trader_client( + &env, + &admin, + contract_name, + &(xlm_token.address.clone(), usdc_token.address.clone()), + &output_token.address, + ); // 1:1 xlm/pho pool let xlm_pho_client: crate::lp_contract::Client<'_> = deploy_and_init_lp_client( @@ -294,13 +244,6 @@ fn extended_trade_and_transfer_token() { 1_000, // 10% swap fee ); - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), usdc_token.address.clone()), - &output_token.address, - ); - // collected fees from previous txs so we have something to trade against PHO token xlm_token.mint(&trader_client.address, &2_000); usdc_token.mint(&trader_client.address, &3_000); @@ -428,7 +371,7 @@ fn extended_trade_and_transfer_token() { &admin.clone(), &usdc_token.address.clone(), &usdc_pho_client.address, - &Some(1_500), + &Some(1_499), &None::, &None, &None, @@ -449,7 +392,7 @@ fn extended_trade_and_transfer_token() { }, token_b: Asset { symbol: usdc_token.symbol(), - amount: 0 + amount: 1 } } ); @@ -494,7 +437,13 @@ fn trade_token_should_fail_when_unauthorized() { xlm_token.mint(&admin, &1_000_000); pho_token.mint(&admin, &2_000_000); - let trader_client = deploy_trader_client(&env); + let trader_client = deploy_trader_client( + &env, + &admin, + contract_name, + &(xlm_token.address.clone(), Address::generate(&env)), + &pho_token.address, + ); xlm_token.mint(&trader_client.address, &1_000); @@ -508,13 +457,6 @@ fn trade_token_should_fail_when_unauthorized() { 0, ); - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), Address::generate(&env)), - &pho_token.address, - ); - trader_client.trade_token( &Address::generate(&env), &xlm_token.address.clone(), @@ -561,7 +503,13 @@ fn trade_token_should_fail_when_offered_token_not_in_pair() { xlm_token.mint(&admin, &1_000_000); pho_token.mint(&admin, &2_000_000); - let trader_client = deploy_trader_client(&env); + let trader_client = deploy_trader_client( + &env, + &admin, + contract_name, + &(xlm_token.address.clone(), Address::generate(&env)), + &pho_token.address, + ); xlm_token.mint(&trader_client.address, &1_000); @@ -575,13 +523,6 @@ fn trade_token_should_fail_when_offered_token_not_in_pair() { 0, ); - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), Address::generate(&env)), - &pho_token.address, - ); - trader_client.trade_token( &admin.clone(), &Address::generate(&env), @@ -629,7 +570,13 @@ fn transfer_should_fail_when_unauthorized() { xlm_token.mint(&admin, &1_000_000); pho_token.mint(&admin, &2_000_000); - let trader_client = deploy_trader_client(&env); + let trader_client = deploy_trader_client( + &env, + &admin, + contract_name, + &(xlm_token.address.clone(), Address::generate(&env)), + &pho_token.address, + ); xlm_token.mint(&trader_client.address, &1_000); @@ -643,13 +590,6 @@ fn transfer_should_fail_when_unauthorized() { 0, ); - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), Address::generate(&env)), - &pho_token.address, - ); - trader_client.trade_token( &admin.clone(), &xlm_token.address.clone(), @@ -699,7 +639,13 @@ fn transfer_should_fail_with_invalid_spread_bps(max_spread_bps: i64) { xlm_token.mint(&admin, &1_000_000); pho_token.mint(&admin, &2_000_000); - let trader_client = deploy_trader_client(&env); + let trader_client = deploy_trader_client( + &env, + &admin, + contract_name, + &(xlm_token.address.clone(), Address::generate(&env)), + &pho_token.address, + ); xlm_token.mint(&trader_client.address, &1_000); @@ -713,13 +659,6 @@ fn transfer_should_fail_with_invalid_spread_bps(max_spread_bps: i64) { 0, ); - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), Address::generate(&env)), - &pho_token.address, - ); - trader_client.trade_token( &admin.clone(), &xlm_token.address.clone(), @@ -772,7 +711,13 @@ fn simple_trade_token_and_transfer_token_with_some_ask_asset_min_amount() { xlm_token.mint(&admin, &1_000_000); output_token.mint(&admin, &2_000_000); - let trader_client = deploy_trader_client(&env); + let trader_client = deploy_trader_client( + &env, + &admin, + contract_name, + &(xlm_token.address.clone(), usdc_token.address.clone()), + &output_token.address, + ); let xlm_pho_client: crate::lp_contract::Client<'_> = deploy_and_init_lp_client( &env, @@ -784,13 +729,6 @@ fn simple_trade_token_and_transfer_token_with_some_ask_asset_min_amount() { 0, ); - trader_client.initialize( - &admin, - &contract_name, - &(xlm_token.address.clone(), usdc_token.address.clone()), - &output_token.address, - ); - xlm_token.mint(&trader_client.address, &1_000); // pretty much the same test as `simple_trade_token_and_transfer` but with `Some` value for diff --git a/contracts/trader/src/tests/setup.rs b/contracts/trader/src/tests/setup.rs index ce7e2e71..0e2104f4 100644 --- a/contracts/trader/src/tests/setup.rs +++ b/contracts/trader/src/tests/setup.rs @@ -1,7 +1,6 @@ use soroban_sdk::{ testutils::{arbitrary::std, Address as _}, - xdr::ToXdr, - Address, Bytes, BytesN, Env, String, + Address, BytesN, Env, String, }; use crate::{ @@ -25,18 +24,6 @@ pub fn install_stake_wasm(env: &Env) -> BytesN<32> { env.deployer().upload_contract_wasm(WASM) } -pub fn deploy_lp_wasm(env: &Env, admin: Address, token_a: Address, token_b: Address) -> Address { - let factory_wasm = env.deployer().upload_contract_wasm(lp_contract::WASM); - let mut salt = Bytes::new(env); - salt.append(&token_a.to_xdr(env)); - salt.append(&token_b.to_xdr(env)); - let salt = env.crypto().sha256(&salt); - - env.deployer() - .with_address(admin, salt) - .deploy_v2(factory_wasm, ()) -} - pub fn deploy_token_contract<'a>( env: &Env, admin: &Address, @@ -59,10 +46,6 @@ pub fn deploy_and_init_lp_client( token_b_amount: i128, swap_fee_bps: i64, ) -> lp_contract::Client { - let lp_addr = deploy_lp_wasm(env, admin.clone(), token_a.clone(), token_b.clone()); - - let lp_client = lp_contract::Client::new(env, &lp_addr); - let stake_wasm_hash = install_stake_wasm(env); let token_wasm_hash = install_token_wasm(env); @@ -89,15 +72,21 @@ pub fn deploy_and_init_lp_client( stake_init_info, }; - lp_client.initialize( - &stake_wasm_hash, - &token_wasm_hash, - &lp_init_info, - &Address::generate(env), - &String::from_str(env, "staked Phoenix"), - &String::from_str(env, "sPHO"), - &100i64, - &1_000, + let lp_client = lp_contract::Client::new( + env, + &env.register( + lp_contract::WASM, + ( + &stake_wasm_hash, + &token_wasm_hash, + lp_init_info, + &Address::generate(env), + String::from_str(env, "staked Phoenix"), + String::from_str(env, "sPHO"), + &100i64, + &1_000i64, + ), + ), ); lp_client.provide_liquidity( @@ -112,6 +101,17 @@ pub fn deploy_and_init_lp_client( lp_client } -pub fn deploy_trader_client(env: &Env) -> TraderClient { - TraderClient::new(env, &env.register(Trader, ())) +pub fn deploy_trader_client<'a>( + env: &Env, + admin: &Address, + contract_name: String, + token_tuple: &(Address, Address), + pho_token: &Address, +) -> TraderClient<'a> { + let trader_client = TraderClient::new( + env, + &env.register(Trader, (admin, contract_name, token_tuple, pho_token)), + ); + + trader_client } From 4b02f727203d8b9978b548c66eac9bb7e76a0f5a Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Fri, 10 Jan 2025 16:31:26 +0200 Subject: [PATCH 13/15] brings back the DataKey for initialized check as precaution --- contracts/factory/src/storage.rs | 1 + contracts/multihop/src/storage.rs | 1 + contracts/pool/src/storage.rs | 1 + contracts/pool_stable/src/storage.rs | 7 ++++--- contracts/stake/src/storage.rs | 3 ++- contracts/stake_rewards/src/storage.rs | 1 + contracts/trader/src/storage.rs | 2 +- 7 files changed, 11 insertions(+), 5 deletions(-) diff --git a/contracts/factory/src/storage.rs b/contracts/factory/src/storage.rs index 55044dd7..3d1eea69 100644 --- a/contracts/factory/src/storage.rs +++ b/contracts/factory/src/storage.rs @@ -16,6 +16,7 @@ pub const ADMIN: Symbol = symbol_short!("ADMIN"); pub enum DataKey { Config = 1, LpVec = 2, + Initialized = 3, // deprecated, do not remove for now } #[derive(Clone)] diff --git a/contracts/multihop/src/storage.rs b/contracts/multihop/src/storage.rs index 517aa2af..11f48233 100644 --- a/contracts/multihop/src/storage.rs +++ b/contracts/multihop/src/storage.rs @@ -31,6 +31,7 @@ pub enum DataKey { PairKey(Pair), FactoryKey, Admin, + Initialized, // deprecated, do not remove for now } #[contracttype] diff --git a/contracts/pool/src/storage.rs b/contracts/pool/src/storage.rs index 695c5a68..06e33198 100644 --- a/contracts/pool/src/storage.rs +++ b/contracts/pool/src/storage.rs @@ -16,6 +16,7 @@ pub enum DataKey { ReserveA = 1, ReserveB = 2, Admin = 3, + Initialized = 4, // deprecated, do not remove for now } impl TryFromVal for Val { diff --git a/contracts/pool_stable/src/storage.rs b/contracts/pool_stable/src/storage.rs index 1df023e6..8dd54bd6 100644 --- a/contracts/pool_stable/src/storage.rs +++ b/contracts/pool_stable/src/storage.rs @@ -16,9 +16,10 @@ pub enum DataKey { ReserveA = 1, ReserveB = 2, Admin = 3, - Amp = 4, - MaxPrecision = 5, - TokenPrecision = 6, + Initialized = 4, // deprecated, do not remove for now + Amp = 5, + MaxPrecision = 6, + TokenPrecision = 7, } impl TryFromVal for Val { diff --git a/contracts/stake/src/storage.rs b/contracts/stake/src/storage.rs index b1f58a76..da5cd301 100644 --- a/contracts/stake/src/storage.rs +++ b/contracts/stake/src/storage.rs @@ -112,7 +112,8 @@ pub mod utils { Admin = 0, TotalStaked = 1, Distributions = 2, - StakeRewards = 3, + Initialized = 3, // deprecated, do not remove for now + StakeRewards = 4, } impl TryFromVal for Val { diff --git a/contracts/stake_rewards/src/storage.rs b/contracts/stake_rewards/src/storage.rs index e0b9db4b..a59dd93c 100644 --- a/contracts/stake_rewards/src/storage.rs +++ b/contracts/stake_rewards/src/storage.rs @@ -55,6 +55,7 @@ pub mod utils { #[derive(Clone, Copy)] #[repr(u32)] pub enum DataKey { + Initialized = 0, // deprecated, do not remove for now Admin = 1, } diff --git a/contracts/trader/src/storage.rs b/contracts/trader/src/storage.rs index 8ccb6c7e..107c7b46 100644 --- a/contracts/trader/src/storage.rs +++ b/contracts/trader/src/storage.rs @@ -19,7 +19,7 @@ pub enum DataKey { Pair, Token, MaxSpread, - IsInitialized, + IsInitialized, // deprecated, do not remove for now } #[contracttype] From 5f704911ad460eb92ed4fc5e394dfcfe147cabc6 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:30:32 +0200 Subject: [PATCH 14/15] vesting constructor --- contracts/vesting/src/contract.rs | 135 ++++++++------------- contracts/vesting/src/storage.rs | 39 ++++-- contracts/vesting/src/tests/claim.rs | 43 ++++--- contracts/vesting/src/tests/instantiate.rs | 54 ++++----- contracts/vesting/src/tests/minter.rs | 124 ++++++++++++++----- contracts/vesting/src/tests/setup.rs | 22 +++- 6 files changed, 240 insertions(+), 177 deletions(-) diff --git a/contracts/vesting/src/contract.rs b/contracts/vesting/src/contract.rs index 6e8082e1..dcd535a8 100644 --- a/contracts/vesting/src/contract.rs +++ b/contracts/vesting/src/contract.rs @@ -11,9 +11,10 @@ use crate::storage::{get_minter, save_minter, MinterInfo}; use crate::{ error::ContractError, storage::{ - get_admin_old, get_all_vestings, get_max_vesting_complexity, get_token_info, get_vesting, - is_initialized, save_admin_old, save_max_vesting_complexity, save_token_info, save_vesting, - set_initialized, update_vesting, VestingInfo, VestingSchedule, VestingTokenInfo, ADMIN, + get_admin_old, get_all_vestings, get_config, get_max_vesting_complexity, get_token_info, + get_vesting, save_admin_old, save_config, save_max_vesting_complexity, save_token_info, + save_vesting, update_vesting, Config, VestingInfo, VestingSchedule, VestingTokenInfo, + ADMIN, }, token_contract, utils::{check_duplications, validate_vesting_schedule}, @@ -29,13 +30,6 @@ pub struct Vesting; #[allow(dead_code)] pub trait VestingTrait { - fn initialize( - env: Env, - admin: Address, - vesting_token: VestingTokenInfo, - max_vesting_complexity: u32, - ); - fn create_vesting_schedules(env: Env, vesting_accounts: Vec); fn claim(env: Env, sender: Address, index: u64); @@ -54,14 +48,7 @@ pub trait VestingTrait { fn query_available_to_claim(env: Env, address: Address, index: u64) -> i128; - #[cfg(feature = "minter")] - fn initialize_with_minter( - env: Env, - admin: Address, - vesting_token: VestingTokenInfo, - max_vesting_complexity: u32, - minter_info: MinterInfo, - ); + fn query_config(env: Env) -> Config; #[cfg(feature = "minter")] fn burn(env: Env, sender: Address, amount: u128); @@ -83,73 +70,6 @@ pub trait VestingTrait { #[contractimpl] impl VestingTrait for Vesting { - fn initialize( - env: Env, - admin: Address, - vesting_token: VestingTokenInfo, - max_vesting_complexity: u32, - ) { - if is_initialized(&env) { - log!( - &env, - "Stake: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - set_initialized(&env); - - save_admin_old(&env, &admin); - - let token_info = VestingTokenInfo { - name: vesting_token.name, - symbol: vesting_token.symbol, - decimals: vesting_token.decimals, - address: vesting_token.address, - }; - - save_token_info(&env, &token_info); - save_max_vesting_complexity(&env, &max_vesting_complexity); - - env.events() - .publish(("Initialize", "Vesting contract with admin: "), admin); - } - - #[cfg(feature = "minter")] - fn initialize_with_minter( - env: Env, - admin: Address, - vesting_token: VestingTokenInfo, - max_vesting_complexity: u32, - minter_info: MinterInfo, - ) { - if is_initialized(&env) { - log!( - &env, - "Stake: Initialize: initializing contract twice is not allowed" - ); - panic_with_error!(&env, ContractError::AlreadyInitialized); - } - - set_initialized(&env); - save_admin_old(&env, &admin); - - save_minter(&env, &minter_info); - - let token_info = VestingTokenInfo { - name: vesting_token.name, - symbol: vesting_token.symbol, - decimals: vesting_token.decimals, - address: vesting_token.address, - }; - - save_token_info(&env, &token_info); - save_max_vesting_complexity(&env, &max_vesting_complexity); - - env.events() - .publish(("Initialize", "Vesting contract with admin: "), admin); - } - fn create_vesting_schedules(env: Env, vesting_schedules: Vec) { let admin = get_admin_old(&env); admin.require_auth(); @@ -266,6 +186,14 @@ impl VestingTrait for Vesting { .publish(("Claim", "Claimed tokens: "), available_to_claim); } + fn query_config(env: Env) -> Config { + env.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + get_config(&env) + } + #[cfg(feature = "minter")] fn burn(env: Env, sender: Address, amount: u128) { sender.require_auth(); @@ -485,3 +413,40 @@ impl VestingTrait for Vesting { Ok(()) } } + +#[contractimpl] +impl Vesting { + pub fn __constructor( + env: Env, + admin: Address, + vesting_token: VestingTokenInfo, + max_vesting_complexity: u32, + minter_info: Option, + ) { + save_admin_old(&env, &admin); + + let token_info = VestingTokenInfo { + name: vesting_token.name, + symbol: vesting_token.symbol, + decimals: vesting_token.decimals, + address: vesting_token.address, + }; + + let mut config = Config { + is_with_minter: false, + }; + + save_token_info(&env, &token_info); + save_max_vesting_complexity(&env, &max_vesting_complexity); + + if let Some(minter_info) = minter_info { + save_minter(&env, &minter_info); + config.is_with_minter = true; + } + + save_config(&env, config); + + env.events() + .publish(("Initialize", "Vesting contract with admin: "), admin); + } +} diff --git a/contracts/vesting/src/storage.rs b/contracts/vesting/src/storage.rs index 130c7e81..dac71219 100644 --- a/contracts/vesting/src/storage.rs +++ b/contracts/vesting/src/storage.rs @@ -41,6 +41,12 @@ pub struct VestingTokenInfo { pub address: Address, } +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Config { + pub is_with_minter: bool, +} + // This structure is used as an argument during the vesting account creation #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] @@ -277,16 +283,29 @@ pub fn get_max_vesting_complexity(env: &Env) -> u32 { vesting_complexity } -pub fn is_initialized(e: &Env) -> bool { - e.storage() - .instance() - .get(&DataKey::IsInitialized) - .unwrap_or(false) +pub fn save_config(env: &Env, config: Config) { + env.storage().persistent().set(&DataKey::Config, &config); + + env.storage().persistent().extend_ttl( + &DataKey::Config, + PERSISTENT_LIFETIME_THRESHOLD, + PERSISTENT_BUMP_AMOUNT, + ) } -pub fn set_initialized(e: &Env) { - e.storage().instance().set(&DataKey::IsInitialized, &true); - e.storage() - .instance() - .extend_ttl(PERSISTENT_LIFETIME_THRESHOLD, PERSISTENT_BUMP_AMOUNT); +pub fn get_config(env: &Env) -> Config { + let config = env + .storage() + .persistent() + .get(&DataKey::Config) + .unwrap_or_else(|| { + log!(&env, "Config not found"); + panic_with_error!(&env, ContractError::NoConfigFound) + }); + env.storage().persistent().extend_ttl( + &DataKey::Config, + PERSISTENT_LIFETIME_THRESHOLD, + PERSISTENT_BUMP_AMOUNT, + ); + config } diff --git a/contracts/vesting/src/tests/claim.rs b/contracts/vesting/src/tests/claim.rs index df823796..7ea757d9 100644 --- a/contracts/vesting/src/tests/claim.rs +++ b/contracts/vesting/src/tests/claim.rs @@ -1,5 +1,5 @@ use crate::{ - storage::{VestingInfo, VestingSchedule, VestingTokenInfo}, + storage::{MinterInfo, VestingInfo, VestingSchedule, VestingTokenInfo}, tests::setup::instantiate_vesting_client, }; use curve::{Curve, PiecewiseLinear, SaturatingLinear, Step}; @@ -52,12 +52,12 @@ fn claim_tokens_when_fully_vested() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); // admin has 320 vesting tokens prior to initializing the contract assert_eq!(token_client.balance(&admin), 320); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); // after initialization the admin has 0 vesting tokens @@ -113,12 +113,12 @@ fn transfer_tokens_when_half_vested() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); // admin has 120 vesting tokens prior to initializing the contract assert_eq!(token_client.balance(&admin), 120); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); // after initialization the admin has 0 vesting tokens @@ -174,9 +174,9 @@ fn claim_tokens_once_then_claim_again() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); // after initialization the admin has 0 vesting tokens @@ -244,12 +244,12 @@ fn user_can_claim_tokens_way_after_the_testing_period() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); // admin has 120 vesting tokens prior to initializing the contract assert_eq!(token_client.balance(&admin), 120); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); // after initialization the admin has 0 vesting tokens @@ -307,9 +307,9 @@ fn transfer_vesting_token_before_vesting_period_starts_should_fail() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); // we set the timestamp at a time earlier than the vesting period start @@ -353,9 +353,9 @@ fn claim_after_all_tokens_have_been_claimed() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); env.ledger().with_mut(|li| li.timestamp = 61); @@ -428,9 +428,9 @@ fn transfer_works_with_multiple_users_and_distributions() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); // vesting period for our 4 vesters is between 0 and 1_500 @@ -530,12 +530,12 @@ fn claim_works() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); // admin has 120 vesting tokens prior to initializing the contract assert_eq!(token_client.balance(&admin), 120); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); // after initialization the admin has 0 vesting tokens @@ -596,8 +596,8 @@ fn claim_tokens_from_two_distributions() { address: token_client.address.clone(), }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize(&admin, &vesting_token, &10u32); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); let vesting_schedules = vec![ &env, @@ -738,9 +738,8 @@ fn first_mainnet_simulation() { }, ]; - let vesting_client = instantiate_vesting_client(&env); - - vesting_client.initialize(&admin, &vesting_token, &10u32); + let vesting_client = + instantiate_vesting_client(&env, &admin, vesting_token, 10u32, None::); // we move time to the beginning of the vesting schedule (100s before) env.ledger().with_mut(|li| li.timestamp = 1716817100); diff --git a/contracts/vesting/src/tests/instantiate.rs b/contracts/vesting/src/tests/instantiate.rs index b93fb6ab..4bcffa10 100644 --- a/contracts/vesting/src/tests/instantiate.rs +++ b/contracts/vesting/src/tests/instantiate.rs @@ -1,7 +1,7 @@ use soroban_sdk::{testutils::Address as _, vec, Address, Env, String}; use crate::{ - storage::{VestingInfo, VestingSchedule, VestingTokenInfo}, + storage::{MinterInfo, VestingInfo, VestingSchedule, VestingTokenInfo}, tests::setup::{deploy_token_contract, instantiate_vesting_client}, }; use curve::{Curve, SaturatingLinear}; @@ -45,9 +45,15 @@ fn instantiate_contract_successfully() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + None::, + ); + token_client.mint(&admin, &480); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); assert_eq!(vesting_client.query_token_info(), vesting_token); @@ -88,10 +94,15 @@ fn instantiate_contract_without_any_vesting_balances_should_fail() { }; let vesting_schedules = vec![&env]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + None::, + ); token_client.mint(&admin, &100); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); } @@ -127,32 +138,13 @@ fn create_schedule_panics_when_admin_has_no_tokens_to_fund() { }, ]; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + None::, + ); - vesting_client.initialize(&admin, &vesting_token, &10u32); vesting_client.create_vesting_schedules(&vesting_schedules); } - -#[test] -#[should_panic(expected = "Stake: Initialize: initializing contract twice is not allowed")] -fn instantiate_contract_twice_should_fail() { - let env = Env::default(); - env.mock_all_auths(); - - let admin = Address::generate(&env); - - let token_client = deploy_token_contract(&env, &admin); - - let vesting_token = VestingTokenInfo { - name: String::from_str(&env, "Phoenix"), - symbol: String::from_str(&env, "PHO"), - decimals: 6, - address: token_client.address.clone(), - }; - - let vesting_client = instantiate_vesting_client(&env); - token_client.mint(&admin, &480); - vesting_client.initialize(&admin, &vesting_token, &10u32); - // initialize again - vesting_client.initialize(&admin, &vesting_token, &10u32); -} diff --git a/contracts/vesting/src/tests/minter.rs b/contracts/vesting/src/tests/minter.rs index b4a443f5..c137c7f9 100644 --- a/contracts/vesting/src/tests/minter.rs +++ b/contracts/vesting/src/tests/minter.rs @@ -28,12 +28,16 @@ fn instantiate_contract_successfully_with_constant_curve_minter_info() { mint_capacity: 511223344, }; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); token_client.mint(&admin, &240); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info); - assert_eq!(vesting_client.query_token_info(), vesting_token); } @@ -60,9 +64,14 @@ fn mint_panics_when_over_the_cap() { mint_capacity: 100, }; - let vesting_client = instantiate_vesting_client(&env); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info); vesting_client.mint(&minter, &110i128); } @@ -97,12 +106,19 @@ fn burn_works() { }, ]; - let vesting_client = instantiate_vesting_client(&env); let minter_info = MinterInfo { address: Address::generate(&env), mint_capacity: 10_000, }; - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info); + + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); + vesting_client.create_vesting_schedules(&vesting_schedules); env.ledger().with_mut(|li| li.timestamp = 100); @@ -135,12 +151,19 @@ fn burn_should_panic_when_invalid_amount() { address: token.address.clone(), }; - let vesting_client = instantiate_vesting_client(&env); let minter_info = MinterInfo { address: Address::generate(&env), mint_capacity: 10_000, }; - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info); + + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); + vesting_client.burn(&Address::generate(&env), &0); } @@ -181,8 +204,14 @@ fn mint_works() { mint_capacity: 500, }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info.clone()); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); + vesting_client.create_vesting_schedules(&vesting_schedules); // we start with 120 tokens minted to the contract @@ -234,8 +263,13 @@ fn mint_should_panic_when_invalid_amount() { mint_capacity: 500, }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); vesting_client.mint(&Address::generate(&env), &0); } @@ -265,8 +299,13 @@ fn mint_should_panic_when_not_authorized_to_mint() { mint_capacity: 500, }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); vesting_client.mint(&vester1, &100); } @@ -296,8 +335,13 @@ fn mint_should_panic_when_mintet_does_not_have_enough_capacity() { mint_capacity: 500, }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); vesting_client.mint(&minter, &1_500); } @@ -326,8 +370,13 @@ fn update_minter_works_correctly() { mint_capacity: 500, }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info.clone()); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info.clone()), + ); assert_eq!(vesting_client.query_minter(), minter_info); @@ -369,8 +418,13 @@ fn update_minter_fails_when_not_authorized() { mint_capacity: 500, }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info.clone()); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); let new_minter_info = MinterInfo { address: new_minter.clone(), @@ -404,8 +458,13 @@ fn update_minter_capacity_when_replacing_old_capacity() { mint_capacity: 50_000, }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info.clone()); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); let new_minter_capacity = 1_000; vesting_client.update_minter_capacity(&admin, &new_minter_capacity); @@ -443,8 +502,13 @@ fn updating_minter_capacity_without_auth() { mint_capacity: 50_000, }; - let vesting_client = instantiate_vesting_client(&env); - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info.clone()); + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); vesting_client.update_minter_capacity(&Address::generate(&env), &1_000); } @@ -468,12 +532,18 @@ fn burning_more_than_balance() { address: token.address.clone(), }; - let vesting_client = instantiate_vesting_client(&env); let minter_info = MinterInfo { address: Address::generate(&env), mint_capacity: 1_000, }; - vesting_client.initialize_with_minter(&admin, &vesting_token, &10u32, &minter_info); + + let vesting_client = instantiate_vesting_client( + &env, + &admin, + vesting_token.clone(), + 10u32, + Some(minter_info), + ); // vester1 tries to burn 121 tokens vesting_client.burn(&Address::generate(&env), &121); diff --git a/contracts/vesting/src/tests/setup.rs b/contracts/vesting/src/tests/setup.rs index a1811984..2cde90da 100644 --- a/contracts/vesting/src/tests/setup.rs +++ b/contracts/vesting/src/tests/setup.rs @@ -2,11 +2,29 @@ use soroban_sdk::{Address, Env}; use crate::{ contract::{Vesting, VestingClient}, + storage::{MinterInfo, VestingTokenInfo}, token_contract, }; -pub fn instantiate_vesting_client(env: &Env) -> VestingClient { - VestingClient::new(env, &env.register(Vesting, ())) +pub fn instantiate_vesting_client<'a>( + env: &Env, + admin: &Address, + vesting_token: VestingTokenInfo, + max_vesting_complexity: u32, + minter_info: Option, +) -> VestingClient<'a> { + VestingClient::new( + env, + &env.register( + Vesting, + ( + admin.clone(), + vesting_token, + max_vesting_complexity, + minter_info, + ), + ), + ) } pub fn deploy_token_contract<'a>(env: &Env, admin: &Address) -> token_contract::Client<'a> { From 8316d92f0f4820cfe8b3ddbf89fc8e5b7dd8b7df Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Mon, 13 Jan 2025 13:00:41 +0200 Subject: [PATCH 15/15] deploy script to use constructors --- scripts/deploy.sh | 221 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 185 insertions(+), 36 deletions(-) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index d7e24c70..5a28d843 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -1,3 +1,4 @@ +#!/bin/bash # Ensure the script exits on any errors set -e @@ -25,6 +26,7 @@ soroban contract optimize --wasm phoenix_pool_stable.wasm soroban contract optimize --wasm phoenix_stake.wasm soroban contract optimize --wasm phoenix_stake_rewards.wasm soroban contract optimize --wasm phoenix_multihop.wasm +soroban contract optimize --wasm phoenix_stake_rewards.wasm echo "Contracts optimized." @@ -40,28 +42,16 @@ TOKEN_ADDR1=$XLM TOKEN_ADDR2=$(soroban contract deploy \ --wasm soroban_token_contract.optimized.wasm \ --source $IDENTITY_STRING \ - --network $NETWORK) - -soroban contract invoke \ - --id $TOKEN_ADDR2 \ - --source $IDENTITY_STRING \ --network $NETWORK \ -- \ - initialize \ --admin $ADMIN_ADDRESS \ --decimal 7 \ --name PHOENIX \ --symbol PHO +) echo "PHO Token initialized." -FACTORY_ADDR=$(soroban contract deploy \ - --wasm phoenix_factory.optimized.wasm \ - --source $IDENTITY_STRING \ - --network $NETWORK) - -echo "Tokens and factory deployed." - # Sort the token addresses alphabetically if [[ "$TOKEN_ADDR1" < "$TOKEN_ADDR2" ]]; then TOKEN_ID1=$TOKEN_ADDR1 @@ -71,7 +61,7 @@ else TOKEN_ID2=$TOKEN_ADDR1 fi -echo "Install the soroban_token, phoenix_pool and phoenix_stake contracts..." +echo "Install the soroban_token, multihop, phoenix_pool and phoenix_stake contracts..." TOKEN_WASM_HASH=$(soroban contract install \ --wasm soroban_token_contract.optimized.wasm \ @@ -99,33 +89,45 @@ STAKE_REWARDS_WASM_HASH=$(soroban contract install \ --source $IDENTITY_STRING \ --network $NETWORK) -echo "Token, pair and stake contracts deployed." - -echo "Initialize factory..." - -MULTIHOP=$(soroban contract install \ +MULTIHOP_WASM_HASH=$(soroban contract install \ --wasm phoenix_multihop.optimized.wasm \ --source $IDENTITY_STRING \ --network $NETWORK) -soroban contract invoke \ - --id $FACTORY_ADDR \ +echo "Token, pair and stake contracts deployed." + +echo "Initialize factory..." + +FACTORY_ADDR=$(soroban contract deploy \ + --wasm phoenix_factory.optimized.wasm \ --source $IDENTITY_STRING \ --network $NETWORK \ -- \ - initialize \ --admin $ADMIN_ADDRESS \ - --multihop_wasm_hash $MULTIHOP \ + --multihop_wasm_hash $MULTIHOP_WASM_HASH \ --lp_wasm_hash $PAIR_WASM_HASH \ --stable_wasm_hash $STABLE_PAIR_WASM_HASH \ --stake_wasm_hash $STAKE_WASM_HASH \ - --stake_rewards_wasm_hash $STAKE_REWARDS_WASM_HASH \ --token_wasm_hash $TOKEN_WASM_HASH \ --whitelisted_accounts "[ \"${ADMIN_ADDRESS}\" ]" \ --lp_token_decimals 7 +) echo "Factory initialized: " $FACTORY_ADDR +echo "Initialize Multihop..." +MULTIHOP_ADDR=$(soroban contract deploy \ + --wasm phoenix_multihop.optimized.wasm \ + --source $IDENTITY_STRING \ + --network $NETWORK \ + -- \ + --admin $ADMIN_ADDRESS \ + --factory $FACTORY_ADDR +) + +echo "Multihop initialized: " $MULTIHOP_ADDR + + echo "Initialize pair using the previously fetched hashes through factory..." soroban contract invoke \ @@ -136,11 +138,11 @@ soroban contract invoke \ create_liquidity_pool \ --sender $ADMIN_ADDRESS \ --lp_init_info "{ \"admin\": \"${ADMIN_ADDRESS}\", \"swap_fee_bps\": 1000, \"fee_recipient\": \"${ADMIN_ADDRESS}\", \"max_allowed_slippage_bps\": 10000, \"default_slippage_bps\": 3000, \"max_allowed_spread_bps\": 10000, \"max_referral_bps\": 5000, \"token_init_info\": { \"token_a\": \"${TOKEN_ID1}\", \"token_b\": \"${TOKEN_ID2}\" }, \"stake_init_info\": { \"min_bond\": \"100\", \"min_reward\": \"100\", \"max_distributions\": 3, \"manager\": \"${ADMIN_ADDRESS}\", \"max_complexity\": 7 } }" \ - --default_slippage_bps 3000 \ - --max_allowed_fee_bps 10000 \ --share_token_name "XLMPHOST" \ --share_token_symbol "XPST" \ - --pool_type 0 + --pool_type 0 \ + --default_slippage_bps 3000 \ + --max_allowed_fee_bps 10000 echo "Query XLM/PHO pair address..." @@ -198,18 +200,14 @@ echo "#############################" TOKEN_ADDR1=$(soroban contract deploy \ --wasm soroban_token_contract.optimized.wasm \ --source $IDENTITY_STRING \ - --network $NETWORK) - -soroban contract invoke \ - --id $TOKEN_ADDR1 \ - --source $IDENTITY_STRING \ --network $NETWORK \ -- \ - initialize \ --admin $ADMIN_ADDRESS \ --decimal 7 \ --name USDC \ --symbol USDC +) + echo "USDC Token initialized." @@ -278,7 +276,7 @@ echo "Liquidity provided." echo "Query stake contract address..." STAKE_ADDR2=$(soroban contract invoke \ - --id $PAIR_ADDR \ + --id $PAIR_ADDR2 \ --source $IDENTITY_STRING \ --network $NETWORK --fee 10000000 \ -- \ @@ -295,6 +293,155 @@ soroban contract invoke \ echo "Tokens bonded." +echo "Starting the deployment of stable pool..." + +echo "Deploying GBPx and EURc ..." + +STABLE_TOKEN_A=$( +soroban contract deploy \ + --wasm soroban_token_contract.optimized.wasm \ + --source $IDENTITY_STRING \ + --network $NETWORK \ + -- \ + --admin $ADMIN_ADDRESS \ + --decimal 7 \ + --name GBPCoin \ + --symbol GBPx +) + +STABLE_TOKEN_B=$( +soroban contract deploy \ + --wasm soroban_token_contract.optimized.wasm \ + --source $IDENTITY_STRING \ + --network $NETWORK \ + -- \ + --admin $ADMIN_ADDRESS \ + --decimal 7 \ + --name EuroCoin \ + --symbol EURc +) + +if [[ "$STABLE_TOKEN_A" < "$STABLE_TOKEN_B" ]]; then + STABLE_TOKEN_ID1=$STABLE_TOKEN_A + STABLE_TOKEN_ID2=$STABLE_TOKEN_B +else + STABLE_TOKEN_ID1=$STABLE_TOKEN_B + STABLE_TOKEN_ID2=$STABLE_TOKEN_A +fi + +echo "Minting GBPx and EURc..." + +soroban contract invoke \ + --id $STABLE_TOKEN_ID1 \ + --source $IDENTITY_STRING \ + --network $NETWORK \ + -- \ + mint --to $ADMIN_ADDRESS --amount 100000000000 + +soroban contract invoke \ + --id $STABLE_TOKEN_ID2 \ + --source $IDENTITY_STRING \ + --network $NETWORK \ + -- \ + mint --to $ADMIN_ADDRESS --amount 100000000000 + +echo "Deploy GBPx/EURc stable pool ..." + +soroban contract invoke \ + --id $FACTORY_ADDR \ + --source $IDENTITY_STRING \ + --network $NETWORK \ + -- \ + create_liquidity_pool \ + --sender $ADMIN_ADDRESS \ + --lp_init_info "{ \ + \"admin\": \"${ADMIN_ADDRESS}\", \ + \"swap_fee_bps\": 1000, \ + \"fee_recipient\": \"${ADMIN_ADDRESS}\", \ + \"max_allowed_slippage_bps\": 10000, \ + \"default_slippage_bps\": 3000, \ + \"max_allowed_spread_bps\": 10000, \ + \"max_referral_bps\": 5000, \ + \"token_init_info\": { \ + \"token_a\": \"${STABLE_TOKEN_ID1}\", \ + \"token_b\": \"${STABLE_TOKEN_ID2}\" \ + }, \ + \"stake_init_info\": { \ + \"min_bond\": \"100\", \ + \"min_reward\": \"100\", \ + \"max_distributions\": \"3\", \ + \"manager\": \"${ADMIN_ADDRESS}\", \ + \"max_complexity\": 7 \ + } \ + }" \ + --default_slippage_bps 3000 \ + --max_allowed_fee_bps 10000 \ + --share_token_name "GBPEURCST" \ + --share_token_symbol "GEST" \ + --pool_type 1 \ + --amp 50 + +echo "Query GBPx/EURc pair address..." + +STABLE_PAIR_ADDR=$(soroban contract invoke \ + --id $FACTORY_ADDR \ + --source $IDENTITY_STRING \ + --network $NETWORK --fee 100 \ + -- \ + query_pools | jq -r '.[2]') + +echo "Providing liquidity to stable pool: " $STABLE_PAIR_ADDR + +# temporary using 2 decimals zeros less, when the liquidity pool is fixed we can use regular numbers again +soroban contract invoke \ + --id $STABLE_PAIR_ADDR \ + --source $IDENTITY_STRING \ + --network $NETWORK --fee 10000000 \ + -- \ + provide_liquidity --sender $ADMIN_ADDRESS --desired_a 20000000 --desired_b 20000000 + +echo "Liquidity provided." + +echo "#############################" + +echo "Deploy and initialize stake_rewards contracts..." + +MAX_COMPLEXITY=7 +MIN_REWARD=100 +MIN_BOND=100 + +echo "Deploying stake_rewards for the XLM/PHO Stake Contract ($STAKE_ADDR)..." +STAKING_REWARDS_XLM_PHO_ADDR=$(soroban contract deploy \ + --wasm phoenix_stake_rewards.optimized.wasm \ + --source $IDENTITY_STRING \ + --network $NETWORK \ + -- \ + --admin "$ADMIN_ADDRESS" \ + --staking_contract "$STAKE_ADDR" \ + --reward_token "$TOKEN_ADDR2" \ + --max_complexity "$MAX_COMPLEXITY" \ + --min_reward "$MIN_REWARD" \ + --min_bond "$MIN_BOND" +) + +echo "Staking Rewards Contract for XLM/PHO deployed at address: $STAKING_REWARDS_XLM_PHO_ADDR" + +echo "Deploying staking_rewards for the PHO/USDC Stake Contract ($STAKE_ADDR2)..." +STAKING_REWARDS_PHO_USDC_ADDR=$(soroban contract deploy \ + --wasm phoenix_stake_rewards.optimized.wasm \ + --source $IDENTITY_STRING \ + --network $NETWORK \ + -- \ + --admin "$ADMIN_ADDRESS" \ + --staking_contract "$STAKE_ADDR2" \ + --reward_token "$TOKEN_ADDR2" \ + --max_complexity "$MAX_COMPLEXITY" \ + --min_reward "$MIN_REWARD" \ + --min_bond "$MIN_BOND" +) + +echo "Staking Rewards Contract for PHO/USDC deployed at address: $STAKING_REWARDS_PHO_USDC_ADDR" + echo "#############################" echo "Initialization complete!" @@ -305,6 +452,8 @@ echo "XLM/PHO Pair Contract address: $PAIR_ADDR" echo "XLM/PHO Stake Contract address: $STAKE_ADDR" echo "PHO/USDC Pair Contract address: $PAIR_ADDR2" echo "PHO/USDC Stake Contract address: $STAKE_ADDR2" +echo "GBPx/EURc Pair Contract address: $STABLE_PAIR_ADDR" echo "Factory Contract address: $FACTORY_ADDR" -echo "Multihop Contract address: $MULTIHOP" - +echo "Multihop Contract address: $MULTIHOP_ADDR" +echo "Staking Rewards Contract for XLM/PHO address: $STAKING_REWARDS_XLM_PHO_ADDR" +echo "Staking Rewards Contract for PHO/USDC address: $STAKING_REWARDS_PHO_USDC_ADDR"