From a608c54a0b927ccfe51ed652cb0f52eb8a825d14 Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 17 Jun 2024 14:03:24 +0200 Subject: [PATCH 1/9] WIP --- contracts/factory/src/contract.rs | 4 ++-- contracts/factory/src/testing.rs | 6 +++--- contracts/factory/tests/factory_helper.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 1a99e0d..214e5c8 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -1,7 +1,7 @@ use coreum_wasm_sdk::core::{CoreumMsg, CoreumQueries}; use cosmwasm_std::{ attr, entry_point, from_json, to_json_binary, Addr, Binary, CosmosMsg, Decimal, Deps, DepsMut, - Env, MessageInfo, Order, Reply, ReplyOn, StdError, StdResult, WasmMsg, + Env, MessageInfo, Order, Reply, ReplyOn, StdError, StdResult, WasmMsg, coin }; use cw2::{ensure_from_older_version, set_contract_version}; use cw20::Cw20ReceiveMsg; @@ -531,7 +531,7 @@ pub fn execute_create_pair( verified, circuit_breaker: None, })?, - funds: vec![], + funds: vec![coin(10000000, "ucore")], label: "Dex pair".to_string(), } .into(), diff --git a/contracts/factory/src/testing.rs b/contracts/factory/src/testing.rs index 395295d..3de2609 100644 --- a/contracts/factory/src/testing.rs +++ b/contracts/factory/src/testing.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - attr, from_json, + attr, from_json, coin, testing::{mock_env, mock_info, MOCK_CONTRACT_ADDR}, to_json_binary, Addr, Coin, Decimal, ReplyOn, SubMsg, Uint128, WasmMsg, }; @@ -557,7 +557,7 @@ fn create_pair() { }) .unwrap(), code_id: pair_config.code_id, - funds: vec![], + funds: vec![coin(10000000, "ucore")], admin: Some(config.unwrap().owner.to_string()), label: String::from("Dex pair"), } @@ -654,7 +654,7 @@ fn create_permissionless_pair() { }) .unwrap(), code_id: pair_config.code_id, - funds: vec![], + funds: vec![coin(10000000, "ucore")], admin: Some(config.unwrap().owner.to_string()), label: String::from("Dex pair"), } diff --git a/contracts/factory/tests/factory_helper.rs b/contracts/factory/tests/factory_helper.rs index c1e03f9..7e5cf8a 100644 --- a/contracts/factory/tests/factory_helper.rs +++ b/contracts/factory/tests/factory_helper.rs @@ -192,7 +192,7 @@ impl FactoryHelper { sender.clone(), self.factory.clone(), &msg, - &[Coin::new(3_000, "coreum")], + &[Coin::new(4_100, "coreum")], ) } From 3d9627b46405bf601f015cb2b189861b484814ac Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 17 Jun 2024 14:21:13 +0200 Subject: [PATCH 2/9] Factory: Send tokens to the pool contract during initialization in order to work around Coreum's architecture --- contracts/factory/src/contract.rs | 4 +- contracts/factory/src/testing.rs | 60 +++++++++++------------ contracts/factory/tests/factory_helper.rs | 10 ++-- contracts/factory/tests/integration.rs | 50 +++++++++---------- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 214e5c8..739de8f 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -1,7 +1,7 @@ use coreum_wasm_sdk::core::{CoreumMsg, CoreumQueries}; use cosmwasm_std::{ - attr, entry_point, from_json, to_json_binary, Addr, Binary, CosmosMsg, Decimal, Deps, DepsMut, - Env, MessageInfo, Order, Reply, ReplyOn, StdError, StdResult, WasmMsg, coin + attr, coin, entry_point, from_json, to_json_binary, Addr, Binary, CosmosMsg, Decimal, Deps, + DepsMut, Env, MessageInfo, Order, Reply, ReplyOn, StdError, StdResult, WasmMsg, }; use cw2::{ensure_from_older_version, set_contract_version}; use cw20::Cw20ReceiveMsg; diff --git a/contracts/factory/src/testing.rs b/contracts/factory/src/testing.rs index 3de2609..c10589b 100644 --- a/contracts/factory/src/testing.rs +++ b/contracts/factory/src/testing.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - attr, from_json, coin, + attr, coin, from_json, testing::{mock_env, mock_info, MOCK_CONTRACT_ADDR}, to_json_binary, Addr, Coin, Decimal, ReplyOn, SubMsg, Uint128, WasmMsg, }; @@ -71,8 +71,8 @@ fn proper_initialization() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -98,8 +98,8 @@ fn proper_initialization() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -138,8 +138,8 @@ fn proper_initialization() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -170,8 +170,8 @@ fn trading_starts_validation() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -218,8 +218,8 @@ fn update_config() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -276,8 +276,8 @@ fn update_owner() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -367,8 +367,8 @@ fn update_pair_config() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -484,8 +484,8 @@ fn create_pair() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -502,7 +502,7 @@ fn create_pair() { let config = CONFIG.load(&deps.storage); let env = mock_env(); - let info = mock_info("owner0000", &[Coin::new(3_000, "coreum")]); + let info = mock_info("owner0000", &[Coin::new(320_000_000, "ucore")]); // Check pair creation using a non-whitelisted pair ID let res = execute( @@ -591,8 +591,8 @@ fn create_permissionless_pair() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000u128), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000u128), }, }; @@ -612,8 +612,8 @@ fn create_permissionless_pair() { let info = mock_info( "user0000", &[Coin { - denom: "coreum".to_string(), - amount: Uint128::new(3_000), + denom: "ucore".to_string(), + amount: Uint128::new(320_000_000), }], ); @@ -688,8 +688,8 @@ fn create_permissionless_pair_too_small_deposit() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000u128), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000u128), }, }; @@ -708,7 +708,7 @@ fn create_permissionless_pair_too_small_deposit() { let info = mock_info( "user0000", &[Coin { - denom: "coreum".to_string(), + denom: "ucore".to_string(), // 1_000 tokens less then required amount: Uint128::new(2_000), }], @@ -750,13 +750,13 @@ fn register() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; let env = mock_env(); - let info = mock_info("addr0000", &[Coin::new(3_000u128, "coreum")]); + let info = mock_info("addr0000", &[Coin::new(320_000_000u128, "ucore")]); let _res = instantiate(deps.as_mut(), env, info, msg).unwrap(); let asset_infos = vec![ @@ -773,7 +773,7 @@ fn register() { }; let env = mock_env(); - let info = mock_info(owner, &[Coin::new(3_000, "coreum")]); + let info = mock_info(owner, &[Coin::new(320_000_000, "ucore")]); let _res = execute(deps.as_mut(), env.clone(), info, msg).unwrap(); let pair0_addr = "pair0000".to_string(); @@ -857,7 +857,7 @@ fn register() { }; let env = mock_env(); - let info = mock_info(owner, &[Coin::new(3_000, "coreum")]); + let info = mock_info(owner, &[Coin::new(320_000_000, "ucore")]); let _res = execute(deps.as_mut(), env.clone(), info, msg).unwrap(); let pair1_addr = "pair0001".to_string(); diff --git a/contracts/factory/tests/factory_helper.rs b/contracts/factory/tests/factory_helper.rs index 7e5cf8a..ae5b049 100644 --- a/contracts/factory/tests/factory_helper.rs +++ b/contracts/factory/tests/factory_helper.rs @@ -64,8 +64,8 @@ impl FactoryHelper { .sudo(SudoMsg::Bank(BankSudo::Mint { to_address: astro_token.to_string(), amount: vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(3_000), + denom: "ucore".to_string(), + amount: Uint128::new(320_000_000), }], })) .unwrap(); @@ -125,8 +125,8 @@ impl FactoryHelper { }, trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -192,7 +192,7 @@ impl FactoryHelper { sender.clone(), self.factory.clone(), &msg, - &[Coin::new(4_100, "coreum")], + &[Coin::new(320_000_000, "ucore")], ) } diff --git a/contracts/factory/tests/integration.rs b/contracts/factory/tests/integration.rs index 27e9137..f79f24a 100644 --- a/contracts/factory/tests/integration.rs +++ b/contracts/factory/tests/integration.rs @@ -69,8 +69,8 @@ fn proper_initialization() { default_stake_config: default_stake_config(), trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), - amount: Uint128::new(3_000), + info: AssetInfo::Cw20Token("ucore".to_string()), + amount: Uint128::new(320_000_000), }, }; @@ -174,8 +174,8 @@ fn test_create_then_deregister_pair() { storage, &owner, vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(3_000), + denom: "ucore".to_string(), + amount: Uint128::new(320_000_000), }], ) }) @@ -286,8 +286,8 @@ fn test_valid_staking() { storage, &owner, vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(3_000), + denom: "ucore".to_string(), + amount: Uint128::new(320_000_000), }], ) }) @@ -373,8 +373,8 @@ fn test_create_pair() { storage, &owner, vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(6_000), + denom: "ucore".to_string(), + amount: Uint128::new(6_000_000_000), }], ) }) @@ -526,17 +526,17 @@ fn test_create_pair_permissions() { Some(18), ); - app.init_modules(|router, _, storage| { - router.bank.init_balance( - storage, - &user, - vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(6_000), - }], - ) - }) - .unwrap(); + // app.init_modules(|router, _, storage| { + // router.bank.init_balance( + // storage, + // &user, + // vec![Coin { + // denom: "ucore".to_string(), + // amount: Uint128::new(320_000_000), + // }], + // ) + // }) + // .unwrap(); let err = helper .create_pair( @@ -599,8 +599,8 @@ fn test_update_pair_fee() { storage, &owner, vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(3_000), + denom: "ucore".to_string(), + amount: Uint128::new(320_000_000), }], ) }) @@ -684,8 +684,8 @@ fn test_pair_migration() { storage, &owner, vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(6_000), + denom: "ucore".to_string(), + amount: Uint128::new(640_000_000), }], ) }) @@ -739,8 +739,8 @@ fn test_pair_migration() { storage, &new_owner, vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(3_000), + denom: "ucore".to_string(), + amount: Uint128::new(320_000_000), }], ) }) From 99cc9d1e1c137cca70a89e62acfc341d0e7ad445 Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 17 Jun 2024 14:24:10 +0200 Subject: [PATCH 3/9] Pool: Send tokens during stake contract's instantiation --- contracts/factory/src/contract.rs | 2 +- contracts/pool/src/contract.rs | 2 +- contracts/pool/src/testing.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 739de8f..c2318dc 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -531,7 +531,7 @@ pub fn execute_create_pair( verified, circuit_breaker: None, })?, - funds: vec![coin(10000000, "ucore")], + funds: vec![coin(20000000, "ucore")], label: "Dex pair".to_string(), } .into(), diff --git a/contracts/pool/src/contract.rs b/contracts/pool/src/contract.rs index f24b3bc..26ed65d 100644 --- a/contracts/pool/src/contract.rs +++ b/contracts/pool/src/contract.rs @@ -111,7 +111,7 @@ pub fn instantiate( admin: Some(info.sender.to_string()), unbonder: None, // TODO: allow specifying unbonder })?, - funds: vec![], + funds: vec![coin(10000000, "ucore")], admin: Some(info.sender.to_string()), label: String::from("Dex-Stake"), }, diff --git a/contracts/pool/src/testing.rs b/contracts/pool/src/testing.rs index 9cfdcf6..4e44767 100644 --- a/contracts/pool/src/testing.rs +++ b/contracts/pool/src/testing.rs @@ -95,7 +95,7 @@ fn proper_initialization() { msg: CosmosMsg::Wasm(WasmMsg::Instantiate { admin: Some("addr0000".to_owned()), code_id: 11, - funds: vec![], + funds: vec![coin(10000000, "ucore")], label: "Dex-Stake".to_owned(), msg: to_json_binary(&dex::stake::InstantiateMsg { lp_share_denom: "uuusdmapplp-cosmos2contract".to_owned(), From ef4ee8d400fe126bc48b66bebf68a0f13b4b0910 Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 17 Jun 2024 14:45:58 +0200 Subject: [PATCH 4/9] Factory: Prepare upgrade implementation allowing to update the new factory's code --- contracts/factory/src/contract.rs | 17 +++++++++++++++++ contracts/factory/src/testing.rs | 4 ++-- packages/dex/src/factory.rs | 4 ++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index c2318dc..7471312 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -865,6 +865,23 @@ pub fn migrate( MigrateMsg::Update() => { ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; } + MigrateMsg::UpdatePoolId { + pool_type, + new_pool_id, + } => { + PAIR_CONFIGS.update( + deps.storage, + pool_type.to_string(), + |old_config| -> StdResult<_> { + let new_config: PoolConfig = PoolConfig { + code_id: new_pool_id, + // if this config doesn't exist, we might as well panic and abort the migration + ..old_config.unwrap() + }; + Ok(new_config) + }, + )?; + } MigrateMsg::AddPermissionlessPoolDeposit(asset) => { CONFIG.update(deps.storage, |old_config| -> StdResult<_> { let new_config = Config { diff --git a/contracts/factory/src/testing.rs b/contracts/factory/src/testing.rs index c10589b..3da3d68 100644 --- a/contracts/factory/src/testing.rs +++ b/contracts/factory/src/testing.rs @@ -557,7 +557,7 @@ fn create_pair() { }) .unwrap(), code_id: pair_config.code_id, - funds: vec![coin(10000000, "ucore")], + funds: vec![coin(20000000, "ucore")], admin: Some(config.unwrap().owner.to_string()), label: String::from("Dex pair"), } @@ -654,7 +654,7 @@ fn create_permissionless_pair() { }) .unwrap(), code_id: pair_config.code_id, - funds: vec![coin(10000000, "ucore")], + funds: vec![coin(20000000, "ucore")], admin: Some(config.unwrap().owner.to_string()), label: String::from("Dex pair"), } diff --git a/packages/dex/src/factory.rs b/packages/dex/src/factory.rs index e37c256..c39030f 100644 --- a/packages/dex/src/factory.rs +++ b/packages/dex/src/factory.rs @@ -390,6 +390,10 @@ pub enum UpdateAddr { #[allow(clippy::large_enum_variant)] pub enum MigrateMsg { Update(), + UpdatePoolId{ + pool_type: PoolType, + new_pool_id: u64 + }, /// Required with <=2.1.0 migration AddPermissionlessPoolDeposit(Asset), } From da60e2314ebe56e4c661bb43b32f459058e287ff Mon Sep 17 00:00:00 2001 From: Jakub Date: Tue, 18 Jun 2024 14:14:05 +0200 Subject: [PATCH 5/9] Factory: Implement native denom parameter in order to allow proper fee transfer on mainnet and testnet --- Cargo.lock | 94 +++++++++++------------ Cargo.toml | 2 +- contracts/factory/src/contract.rs | 11 ++- contracts/factory/src/state.rs | 3 + contracts/factory/src/testing.rs | 13 ++++ contracts/factory/tests/factory_helper.rs | 1 + contracts/factory/tests/integration.rs | 1 + contracts/pool/src/contract.rs | 8 +- contracts/pool/src/state.rs | 2 + packages/dex/src/factory.rs | 3 + packages/dex/src/pool.rs | 4 + 11 files changed, 89 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 094958f..593c417 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "autocfg" @@ -51,7 +51,7 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bindings-test" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "coreum-wasm-sdk", @@ -392,7 +392,7 @@ dependencies = [ [[package]] name = "dex" -version = "1.1.0" +version = "1.1.1" dependencies = [ "coreum-wasm-sdk", "cosmwasm-schema", @@ -407,7 +407,7 @@ dependencies = [ [[package]] name = "dex-factory" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bindings-test", @@ -429,7 +429,7 @@ dependencies = [ [[package]] name = "dex-multi-hop" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bindings-test", @@ -451,7 +451,7 @@ dependencies = [ [[package]] name = "dex-pool" -version = "1.1.0" +version = "1.1.1" dependencies = [ "coreum-wasm-sdk", "cosmwasm-schema", @@ -466,7 +466,7 @@ dependencies = [ [[package]] name = "dex-pool-stable" -version = "1.1.0" +version = "1.1.1" dependencies = [ "coreum-wasm-sdk", "cosmwasm-schema", @@ -482,7 +482,7 @@ dependencies = [ [[package]] name = "dex-stake" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bindings-test", @@ -561,9 +561,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elliptic-curve" @@ -602,7 +602,7 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fee-splitter" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bindings-test", @@ -748,9 +748,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" @@ -760,9 +760,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "num-traits" @@ -828,9 +828,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", "prost-derive", @@ -867,15 +867,15 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9554e3ab233f0a932403704f1a1d08c30d5ccd931adfdfa1e8b5a19b52c1d55a" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -940,9 +940,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rfc6979" @@ -987,9 +987,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schemars" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6e7ed6919cb46507fb01ff1654309219f62b4d603822501b0b80d42f6f21ef" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "schemars_derive", @@ -999,14 +999,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185f2b7aa7e02d418e453790dde16890256bbd2bcd04b7dc5348811052b53f49" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -1031,9 +1031,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.201" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -1049,24 +1049,24 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] name = "serde_derive_internals" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -1149,9 +1149,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.63" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -1194,22 +1194,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -1349,6 +1349,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 48e147f..77cfca2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["contracts/*", "packages/*"] resolver = "2" [workspace.package] -version = "1.1.0" +version = "1.1.1" edition = "2021" license = "GPL 3.0" repository = "https://github.com/WHELP-project/whelp-contracts" diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 7471312..06b90bf 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -24,8 +24,9 @@ use crate::{ error::ContractError, querier::query_pair_info, state::{ - check_asset_infos, pair_key, read_pairs, Config, TmpPoolInfo, CONFIG, OWNERSHIP_PROPOSAL, - PAIRS, PAIRS_TO_MIGRATE, PAIR_CONFIGS, STAKING_ADDRESSES, TMP_PAIR_INFO, + check_asset_infos, pair_key, read_pairs, Config, TmpPoolInfo, CONFIG, NATIVE_DENOM, + OWNERSHIP_PROPOSAL, PAIRS, PAIRS_TO_MIGRATE, PAIR_CONFIGS, STAKING_ADDRESSES, + TMP_PAIR_INFO, }, }; @@ -99,6 +100,7 @@ pub fn instantiate( PAIR_CONFIGS.save(deps.storage, pc.pool_type.to_string(), pc)?; } CONFIG.save(deps.storage, &config)?; + NATIVE_DENOM.save(deps.storage, &msg.native_denom)?; Ok(Response::new()) } @@ -530,8 +532,9 @@ pub fn execute_create_pair( }, verified, circuit_breaker: None, + native_denom: NATIVE_DENOM.load(deps.storage)?, })?, - funds: vec![coin(20000000, "ucore")], + funds: vec![coin(20000000, NATIVE_DENOM.load(deps.storage)?)], label: "Dex pair".to_string(), } .into(), @@ -867,8 +870,10 @@ pub fn migrate( } MigrateMsg::UpdatePoolId { pool_type, + set_native_denom, new_pool_id, } => { + NATIVE_DENOM.save(deps.storage, &set_native_denom)?; PAIR_CONFIGS.update( deps.storage, pool_type.to_string(), diff --git a/contracts/factory/src/state.rs b/contracts/factory/src/state.rs index 84bd079..efce33d 100644 --- a/contracts/factory/src/state.rs +++ b/contracts/factory/src/state.rs @@ -46,6 +46,9 @@ pub const TMP_PAIR_INFO: Item = Item::new("tmp_pair_info"); /// Saves factory settings pub const CONFIG: Item = Item::new("config"); +/// Native denom of the chain in order to pay the contract instantiation fees +pub const NATIVE_DENOM: Item = Item::new("native"); + /// Saves created pairs (from olders to latest) pub const PAIRS: Map<&[u8], Addr> = Map::new("pair_info"); diff --git a/contracts/factory/src/testing.rs b/contracts/factory/src/testing.rs index 3da3d68..9795a18 100644 --- a/contracts/factory/src/testing.rs +++ b/contracts/factory/src/testing.rs @@ -74,6 +74,7 @@ fn proper_initialization() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -101,6 +102,7 @@ fn proper_initialization() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -132,6 +134,7 @@ fn proper_initialization() { is_disabled: false, }, ], + native_denom: "ucore".to_string(), fee_address: None, owner: owner.clone(), max_referral_commission: Decimal::one(), @@ -173,6 +176,7 @@ fn trading_starts_validation() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; // in the past @@ -221,6 +225,7 @@ fn update_config() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -279,6 +284,7 @@ fn update_owner() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -370,6 +376,7 @@ fn update_pair_config() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -487,6 +494,7 @@ fn create_pair() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -554,6 +562,7 @@ fn create_pair() { fee_config: pair_config.fee_config, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }) .unwrap(), code_id: pair_config.code_id, @@ -594,6 +603,7 @@ fn create_permissionless_pair() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000u128), }, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -651,6 +661,7 @@ fn create_permissionless_pair() { fee_config: pair_config.fee_config, circuit_breaker: None, verified: false, + native_denom: "ucore".to_string(), }) .unwrap(), code_id: pair_config.code_id, @@ -691,6 +702,7 @@ fn create_permissionless_pair_too_small_deposit() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000u128), }, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -744,6 +756,7 @@ fn register() { }, is_disabled: false, }], + native_denom: "ucore".to_string(), fee_address: None, owner: owner.to_string(), max_referral_commission: Decimal::one(), diff --git a/contracts/factory/tests/factory_helper.rs b/contracts/factory/tests/factory_helper.rs index ae5b049..7ac20de 100644 --- a/contracts/factory/tests/factory_helper.rs +++ b/contracts/factory/tests/factory_helper.rs @@ -128,6 +128,7 @@ impl FactoryHelper { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; let factory = router diff --git a/contracts/factory/tests/integration.rs b/contracts/factory/tests/integration.rs index f79f24a..ee2cbeb 100644 --- a/contracts/factory/tests/integration.rs +++ b/contracts/factory/tests/integration.rs @@ -72,6 +72,7 @@ fn proper_initialization() { info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(320_000_000), }, + native_denom: "ucore".to_string(), }; let factory_instance = app diff --git a/contracts/pool/src/contract.rs b/contracts/pool/src/contract.rs index 26ed65d..e06dd85 100644 --- a/contracts/pool/src/contract.rs +++ b/contracts/pool/src/contract.rs @@ -33,7 +33,7 @@ use dex::{ querier::query_factory_config, }; -use crate::state::{Config, CIRCUIT_BREAKER, CONFIG, FROZEN, LP_SHARE_AMOUNT}; +use crate::state::{Config, CIRCUIT_BREAKER, CONFIG, FROZEN, LP_SHARE_AMOUNT, NATIVE_DENOM}; pub type Response = cosmwasm_std::Response; pub type SubMsg = cosmwasm_std::SubMsg; @@ -85,6 +85,7 @@ pub fn instantiate( CONFIG.save(deps.storage, &config)?; FROZEN.save(deps.storage, &false)?; + NATIVE_DENOM.save(deps.storage, &msg.native_denom)?; LP_SHARE_AMOUNT.save(deps.storage, &Uint128::zero())?; save_tmp_staking_config(deps.storage, &msg.staking_config)?; @@ -111,7 +112,7 @@ pub fn instantiate( admin: Some(info.sender.to_string()), unbonder: None, // TODO: allow specifying unbonder })?, - funds: vec![coin(10000000, "ucore")], + funds: vec![coin(10000000, NATIVE_DENOM.load(deps.storage)?)], admin: Some(info.sender.to_string()), label: String::from("Dex-Stake"), }, @@ -136,6 +137,9 @@ pub fn migrate( CIRCUIT_BREAKER.save(deps.storage, &deps.api.addr_validate(&circuit_breaker)?)?; } } + MigrateMsg::UpdateNativeDenom(native_denom) => { + NATIVE_DENOM.save(deps.storage, &native_denom)?; + } } Ok(Response::new()) diff --git a/contracts/pool/src/state.rs b/contracts/pool/src/state.rs index 5f1eeae..7f486e8 100644 --- a/contracts/pool/src/state.rs +++ b/contracts/pool/src/state.rs @@ -22,6 +22,8 @@ pub struct Config { /// Stores the config struct at the given key pub const CONFIG: Item = Item::new("config"); +/// Native denom of the chain in order to sent the initial fee +pub const NATIVE_DENOM: Item = Item::new("denom"); // Address which can trigger a Freeze or Unfreeze via an ExecuteMsg variant pub const CIRCUIT_BREAKER: Item = Item::new("circuit_breaker"); // Whether the contract is frozen or not diff --git a/packages/dex/src/factory.rs b/packages/dex/src/factory.rs index c39030f..183b779 100644 --- a/packages/dex/src/factory.rs +++ b/packages/dex/src/factory.rs @@ -72,6 +72,8 @@ pub struct InstantiateMsg { pub trading_starts: Option, /// Fee required to create non-verified pool pub pool_creation_fee: Asset, + /// Native denom of the chain in order to pay the contract instantiation fees + pub native_denom: String, } #[cw_serde] @@ -392,6 +394,7 @@ pub enum MigrateMsg { Update(), UpdatePoolId{ pool_type: PoolType, + set_native_denom: String, new_pool_id: u64 }, /// Required with <=2.1.0 migration diff --git a/packages/dex/src/pool.rs b/packages/dex/src/pool.rs index 8f5d76c..bb8d476 100644 --- a/packages/dex/src/pool.rs +++ b/packages/dex/src/pool.rs @@ -113,6 +113,8 @@ pub struct InstantiateMsg { pub trading_starts: u64, /// Address which can call ExecuteMsg::Freeze pub circuit_breaker: Option, + /// Native denom of the chain in order to sent the initial fee + pub native_denom: String } impl InstantiateMsg { @@ -239,6 +241,8 @@ pub enum MigrateMsg { // TODO: better name. this may be an address that can set frozen itself circuit_breaker: Option, }, + /// Update the native token for the fee purposes + UpdateNativeDenom(String) } /// This structure describes the query messages available in the contract. From 0f42d5f47421e6964d6204da5bdb569c3e58325e Mon Sep 17 00:00:00 2001 From: Jakub Date: Tue, 18 Jun 2024 14:50:27 +0200 Subject: [PATCH 6/9] Pool: Implement native denom in tests --- contracts/pool/src/testing.rs | 9 +++++++++ packages/dex/src/factory.rs | 4 ++-- packages/dex/src/pool.rs | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/contracts/pool/src/testing.rs b/contracts/pool/src/testing.rs index 4e44767..0aa6e51 100644 --- a/contracts/pool/src/testing.rs +++ b/contracts/pool/src/testing.rs @@ -65,6 +65,7 @@ fn proper_initialization() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let sender = "addr0000"; @@ -170,6 +171,7 @@ fn test_freezing_a_pool_blocking_actions_then_unfreeze() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -452,6 +454,7 @@ fn provide_liquidity() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -903,6 +906,7 @@ fn withdraw_liquidity() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -1056,6 +1060,7 @@ fn query_twap() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; instantiate(deps.as_mut(), env.clone(), mock_info("owner", &[]), msg).unwrap(); @@ -1214,6 +1219,7 @@ fn try_native_to_token() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -1429,6 +1435,7 @@ fn try_token_to_native() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -1689,6 +1696,7 @@ fn test_query_pool() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -1751,6 +1759,7 @@ fn test_query_share() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let env = mock_env(); diff --git a/packages/dex/src/factory.rs b/packages/dex/src/factory.rs index 183b779..fe8ac1f 100644 --- a/packages/dex/src/factory.rs +++ b/packages/dex/src/factory.rs @@ -392,10 +392,10 @@ pub enum UpdateAddr { #[allow(clippy::large_enum_variant)] pub enum MigrateMsg { Update(), - UpdatePoolId{ + UpdatePoolId { pool_type: PoolType, set_native_denom: String, - new_pool_id: u64 + new_pool_id: u64, }, /// Required with <=2.1.0 migration AddPermissionlessPoolDeposit(Asset), diff --git a/packages/dex/src/pool.rs b/packages/dex/src/pool.rs index bb8d476..fab80dc 100644 --- a/packages/dex/src/pool.rs +++ b/packages/dex/src/pool.rs @@ -114,7 +114,7 @@ pub struct InstantiateMsg { /// Address which can call ExecuteMsg::Freeze pub circuit_breaker: Option, /// Native denom of the chain in order to sent the initial fee - pub native_denom: String + pub native_denom: String, } impl InstantiateMsg { @@ -242,7 +242,7 @@ pub enum MigrateMsg { circuit_breaker: Option, }, /// Update the native token for the fee purposes - UpdateNativeDenom(String) + UpdateNativeDenom(String), } /// This structure describes the query messages available in the contract. From 25b873d0dd2ea5709ae24636ee9bb7829cdb7dca Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 19 Aug 2024 12:08:13 +0200 Subject: [PATCH 7/9] Multihop: Add the pool creation const fee in tests --- contracts/multi-hop/src/multitest/suite.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/contracts/multi-hop/src/multitest/suite.rs b/contracts/multi-hop/src/multitest/suite.rs index 65207d9..57002dd 100644 --- a/contracts/multi-hop/src/multitest/suite.rs +++ b/contracts/multi-hop/src/multitest/suite.rs @@ -158,6 +158,7 @@ impl SuiteBuilder { ], fee_address: None, owner: owner.to_string(), + native_denom: "ucore".to_string(), max_referral_commission: self.max_referral_commission, default_stake_config: DefaultStakeConfig { staking_code_id, @@ -165,7 +166,7 @@ impl SuiteBuilder { }, trading_starts: None, pool_creation_fee: Asset { - info: AssetInfo::Cw20Token("coreum".to_string()), + info: AssetInfo::Cw20Token("ucore".to_string()), amount: Uint128::new(3_000), }, }, @@ -229,8 +230,9 @@ impl Suite { storage, &Addr::unchecked(sender), vec![Coin { - denom: "coreum".to_string(), - amount: Uint128::new(6_000), + denom: "ucore".to_string(), + // mint extra 200k of ucore for the stake contract kickstart amount + amount: Uint128::new(20_000_000 + 6_000), }], ) }) @@ -246,7 +248,9 @@ impl Suite { staking_config: Default::default(), total_fee_bps: None, }, - &[Coin::new(3_000, "coreum")], + // Constant 200k ucore for the kickstart funds on the contract plus the pool creation + // fee + &[Coin::new(20_000_000 + 3_000, "ucore")], )?; let factory = self.factory.clone(); From 2da76f7f4d6cc13631a75e396510ccf4ae25402e Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 19 Aug 2024 12:52:06 +0200 Subject: [PATCH 8/9] Pool: Adjust new amount of LP share tokens burint liquidity withdrawal --- contracts/pool/src/contract.rs | 10 ++++----- contracts/pool/src/testing.rs | 38 ++++++++++++++++++++++++++++++++++ packages/dex/src/pool.rs | 3 +-- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/contracts/pool/src/contract.rs b/contracts/pool/src/contract.rs index e06dd85..31351d4 100644 --- a/contracts/pool/src/contract.rs +++ b/contracts/pool/src/contract.rs @@ -137,8 +137,8 @@ pub fn migrate( CIRCUIT_BREAKER.save(deps.storage, &deps.api.addr_validate(&circuit_breaker)?)?; } } - MigrateMsg::UpdateNativeDenom(native_denom) => { - NATIVE_DENOM.save(deps.storage, &native_denom)?; + MigrateMsg::UpdateSetLPShare(lp_share_amount) => { + LP_SHARE_AMOUNT.save(deps.storage, &Uint128::from(lp_share_amount))? } } @@ -593,9 +593,9 @@ pub fn withdraw_liquidity( coin: coin(amount.u128(), &config.pool_info.liquidity_token), })), ]; - LP_SHARE_AMOUNT.update(deps.storage, |mut amount| -> StdResult<_> { - amount -= amount; - Ok(amount) + LP_SHARE_AMOUNT.update(deps.storage, |mut total_amount| -> StdResult<_> { + total_amount -= amount; + Ok(total_amount) })?; Ok(Response::new().add_messages(messages).add_attributes(vec![ diff --git a/contracts/pool/src/testing.rs b/contracts/pool/src/testing.rs index 0aa6e51..72b6ebc 100644 --- a/contracts/pool/src/testing.rs +++ b/contracts/pool/src/testing.rs @@ -956,6 +956,24 @@ fn withdraw_liquidity() { // Do one successful action before freezing just for sanity execute(deps.as_mut(), env.clone(), info, msg).unwrap(); + let res: PoolResponse = query_pool(deps.as_ref()).unwrap(); + assert_eq!( + res, + PoolResponse { + assets: vec![ + AssetValidated { + info: AssetInfoValidated::SmartToken("uusd".to_string()), + amount: Uint128::from(10_000u128) + }, + AssetValidated { + info: AssetInfoValidated::Cw20Token(Addr::unchecked("asset0000")), + amount: Uint128::from(10_000u128) + } + ], + total_share: Uint128::from(10_000u128) + } + ); + // Withdraw liquidity let msg = ExecuteMsg::WithdrawLiquidity { assets: vec![] }; let env = mock_env(); @@ -1015,6 +1033,26 @@ fn withdraw_liquidity() { } ); + let res: PoolResponse = query_pool(deps.as_ref()).unwrap(); + assert_eq!( + res, + PoolResponse { + // the balance is not updating because we sent a burn message, yet burn is not mocked in + // this environment + assets: vec![ + AssetValidated { + info: AssetInfoValidated::SmartToken("uusd".to_string()), + amount: Uint128::from(10_000u128) + }, + AssetValidated { + info: AssetInfoValidated::Cw20Token(Addr::unchecked("asset0000")), + amount: Uint128::from(10_000u128) + } + ], + total_share: Uint128::from(9_900u128) + } + ); + assert_eq!( log_withdrawn_share, &attr("withdrawn_share", 100u128.to_string()) diff --git a/packages/dex/src/pool.rs b/packages/dex/src/pool.rs index fab80dc..348541e 100644 --- a/packages/dex/src/pool.rs +++ b/packages/dex/src/pool.rs @@ -241,8 +241,7 @@ pub enum MigrateMsg { // TODO: better name. this may be an address that can set frozen itself circuit_breaker: Option, }, - /// Update the native token for the fee purposes - UpdateNativeDenom(String), + UpdateSetLPShare(u128) } /// This structure describes the query messages available in the contract. From 0ae142b1d0b2d6b6b0bfa73f29a76838215336f6 Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 19 Aug 2024 13:26:32 +0200 Subject: [PATCH 9/9] Pool stable: Correctly update the lp share amount --- contracts/pool_stable/src/contract.rs | 11 +- contracts/pool_stable/src/state.rs | 2 + contracts/pool_stable/src/testing.rs | 971 +++++++++++--------------- 3 files changed, 424 insertions(+), 560 deletions(-) diff --git a/contracts/pool_stable/src/contract.rs b/contracts/pool_stable/src/contract.rs index e9ee560..6e9f8c4 100644 --- a/contracts/pool_stable/src/contract.rs +++ b/contracts/pool_stable/src/contract.rs @@ -38,6 +38,7 @@ use crate::{ math::{calc_y, compute_d, AMP_PRECISION, MAX_AMP, MAX_AMP_CHANGE, MIN_AMP_CHANGING_TIME}, state::{ get_precision, store_precisions, Config, CIRCUIT_BREAKER, CONFIG, FROZEN, LP_SHARE_AMOUNT, + NATIVE_DENOM, }, utils::{ accumulate_prices, adjust_precision, calc_new_price_a_per_b, compute_current_amp, @@ -121,6 +122,7 @@ pub fn instantiate( }; CONFIG.save(deps.storage, &config)?; + NATIVE_DENOM.save(deps.storage, &msg.native_denom)?; FROZEN.save(deps.storage, &false)?; LP_SHARE_AMOUNT.save(deps.storage, &Uint128::zero())?; save_tmp_staking_config(deps.storage, &msg.staking_config)?; @@ -156,6 +158,9 @@ pub fn migrate( CIRCUIT_BREAKER.save(deps.storage, &deps.api.addr_validate(&circuit_breaker)?)?; } } + MigrateMsg::UpdateSetLPShare(lp_share_amount) => { + LP_SHARE_AMOUNT.save(deps.storage, &Uint128::from(lp_share_amount))? + } } Ok(Response::new()) @@ -636,9 +641,9 @@ pub fn withdraw_liquidity( coin: coin(burn_amount.u128(), &config.pool_info.liquidity_token), })), ]; - LP_SHARE_AMOUNT.update(deps.storage, |mut amount| -> StdResult<_> { - amount -= amount; - Ok(amount) + LP_SHARE_AMOUNT.update(deps.storage, |mut total_amount| -> StdResult<_> { + total_amount -= amount; + Ok(total_amount) })?; Ok(Response::new().add_messages(messages).add_attributes(vec![ diff --git a/contracts/pool_stable/src/state.rs b/contracts/pool_stable/src/state.rs index ae879ee..975bf33 100644 --- a/contracts/pool_stable/src/state.rs +++ b/contracts/pool_stable/src/state.rs @@ -33,6 +33,8 @@ pub struct Config { /// Stores the config struct at the given key pub const CONFIG: Item = Item::new("config"); +/// Native denom of the chain in order to pay the contract instantiation fees +pub const NATIVE_DENOM: Item = Item::new("denom"); // Address which can trigger a Freeze or Unfreeze via an ExecuteMsg variant pub const CIRCUIT_BREAKER: Item = Item::new("circuit_breaker"); // Whether the contract is frozen or not diff --git a/contracts/pool_stable/src/testing.rs b/contracts/pool_stable/src/testing.rs index 72bbfae..7c904e5 100644 --- a/contracts/pool_stable/src/testing.rs +++ b/contracts/pool_stable/src/testing.rs @@ -1,9 +1,13 @@ use coreum_wasm_sdk::{assetft, core::CoreumMsg}; use cosmwasm_std::{ testing::{mock_env, mock_info, MOCK_CONTRACT_ADDR}, - {coin, to_json_binary, Addr, BlockInfo, Coin, Decimal, Env, ReplyOn, Timestamp, Uint128}, + Response, StdError, WasmMsg, + { + coin, to_json_binary, Addr, BlockInfo, Coin, CosmosMsg, Decimal, Env, ReplyOn, Timestamp, + Uint128, + }, }; -use cw20::Cw20ReceiveMsg; +use cw20::{Cw20ExecuteMsg, Cw20ReceiveMsg}; use dex::{ asset::{Asset, AssetInfo, AssetInfoValidated, MINIMUM_LIQUIDITY_AMOUNT}, @@ -63,6 +67,7 @@ fn proper_initialization() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let sender = "addr0000"; @@ -152,6 +157,7 @@ fn test_freezing_a_pool_blocking_actions_then_unfreeze() { }, circuit_breaker: None, verified: true, + native_denom: "ucore".to_string(), }; let env = mock_env(); @@ -401,452 +407,412 @@ fn test_freezing_a_pool_blocking_actions_then_unfreeze() { execute(deps.as_mut(), env, info, msg).unwrap(); } -// #[test] -// fn provide_liquidity() { -// let mut deps = mock_dependencies(&[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::new(200_000000000000000000u128), -// }]); -// -// deps.querier.with_token_balances(&[ -// ( -// &String::from("asset0000"), -// &[(&String::from(MOCK_CONTRACT_ADDR), &Uint128::new(0))], -// ), -// ( -// &String::from("liquidity0000"), -// &[(&String::from(MOCK_CONTRACT_ADDR), &Uint128::new(0))], -// ), -// ]); -// -// let msg = InstantiateMsg { -// asset_infos: vec![ -// AssetInfo::SmartToken("uusd".to_string()), -// AssetInfo::Cw20Token("asset0000".to_string()), -// ], -// // factory_addr: String::from("factory"), -// init_params: None, -// staking_config: default_stake_config(), -// trading_starts: 0, -// fee_config: FeeConfig { -// total_fee_bps: 0, -// protocol_fee_bps: 0, -// }, -// circuit_breaker: None, -// }; -// -// let env = mock_env(); -// let info = mock_info("addr0000", &[]); -// // We can just call .unwrap() to assert this was a success -// let _res = instantiate(deps.as_mut(), env, info, msg).unwrap(); -// -// // Successfully provide liquidity for the existing pool -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// ], -// slippage_tolerance: None, -// receiver: None, -// }; -// -// let env = mock_env(); -// let info = mock_info( -// "addr0000", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(100_000000000000000000u128), -// }], -// ); -// let res = execute(deps.as_mut(), env.clone(), info, msg).unwrap(); -// let transfer_from_msg = res.messages.get(0).expect("no message"); -// let mint_min_liquidity_msg = res.messages.get(1).expect("no message"); -// let mint_receiver_msg = res.messages.get(2).expect("no message"); -// assert_eq!( -// transfer_from_msg, -// &SubMsg { -// msg: WasmMsg::Execute { -// contract_addr: String::from("asset0000"), -// msg: to_json_binary(&Cw20ExecuteMsg::TransferFrom { -// owner: String::from("addr0000"), -// recipient: String::from(MOCK_CONTRACT_ADDR), -// amount: Uint128::from(100_000000000000000000u128), -// }) -// .unwrap(), -// funds: vec![], -// } -// .into(), -// id: 0, -// gas_limit: None, -// reply_on: ReplyOn::Never -// } -// ); -// assert_eq!( -// mint_min_liquidity_msg, -// &SubMsg { -// msg: CosmosMsg::Custom(CoreumMsg::AssetFT(assetft::Msg::Mint { -// coin: Coin { -// denom: String::from("uuusdmapplp-cosmos2contract"), -// amount: Uint128::from(1_000_u128), -// }, -// })), -// id: 0, -// gas_limit: None, -// reply_on: ReplyOn::Never, -// } -// ); -// assert_eq!( -// mint_receiver_msg, -// &SubMsg { -// msg: CosmosMsg::Custom(CoreumMsg::AssetFT(assetft::Msg::Mint { -// coin: Coin { -// denom: String::from("uuusdmapplp-cosmos2contract"), -// amount: Uint128::from(99_999999999999999000u128), -// }, -// })), -// id: 0, -// gas_limit: None, -// reply_on: ReplyOn::Never, -// } -// ); -// -// // Provide more liquidity 1:2, which is not propotional to 1:1, -// // It must accept 1:1 and treat the leftover amount as a donation -// deps.querier.with_balance(&[( -// &String::from(MOCK_CONTRACT_ADDR), -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::new(200_000000000000000000 + 200_000000000000000000 /* user deposit must be pre-applied */), -// }], -// )]); -// -// deps.querier.with_token_balances(&[ -// ( -// &String::from("liquidity0000"), -// &[( -// &String::from(MOCK_CONTRACT_ADDR), -// &Uint128::new(100_000000000000000000), -// )], -// ), -// ( -// &String::from("asset0000"), -// &[( -// &String::from(MOCK_CONTRACT_ADDR), -// &Uint128::new(200_000000000000000000), -// )], -// ), -// ]); -// -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(200_000000000000000000u128), -// }, -// ], -// slippage_tolerance: Some(Decimal::percent(50)), -// receiver: None, -// }; -// -// let env = mock_env_with_block_time(env.block.time.seconds() + 1000); -// let info = mock_info( -// "addr0000", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(200_000000000000000000u128), -// }], -// ); -// -// // Only accept 100, then 50 share will be generated with 100 * (100 / 200) -// let res: Response = execute(deps.as_mut(), env, info, msg).unwrap(); -// let transfer_from_msg = res.messages.get(0).expect("no message"); -// let mint_msg = res.messages.get(1).expect("no message"); -// assert_eq!( -// transfer_from_msg, -// &SubMsg { -// msg: WasmMsg::Execute { -// contract_addr: String::from("asset0000"), -// msg: to_json_binary(&Cw20ExecuteMsg::TransferFrom { -// owner: String::from("addr0000"), -// recipient: String::from(MOCK_CONTRACT_ADDR), -// amount: Uint128::from(100_000000000000000000u128), -// }) -// .unwrap(), -// funds: vec![], -// } -// .into(), -// id: 0, -// gas_limit: None, -// reply_on: ReplyOn::Never, -// } -// ); -// assert_eq!( -// mint_msg, -// &SubMsg { -// msg: CosmosMsg::Custom(CoreumMsg::AssetFT(assetft::Msg::Mint { -// coin: Coin { -// denom: String::from("uuusdmapplp-cosmos2contract"), -// amount: Uint128::from(50_000_000_000_000_000_000u128), -// }, -// })), -// id: 0, -// gas_limit: None, -// reply_on: ReplyOn::Never, -// } -// ); -// -// // Check wrong argument -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(50_000000000000000000u128), -// }, -// ], -// slippage_tolerance: None, -// receiver: None, -// }; -// -// let env = mock_env(); -// let info = mock_info( -// "addr0000", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(100_000000000000000000u128), -// }], -// ); -// let res = execute(deps.as_mut(), env.clone(), info, msg).unwrap_err(); -// match res { -// ContractError::Std(StdError::GenericErr { msg, .. }) => assert_eq!( -// msg, -// "SmartToken token balance mismatch between the argument and the transferred" -// .to_string() -// ), -// _ => panic!("Must return generic error"), -// } -// -// // Initialize token amount to the 1:1 ratio -// deps.querier.with_balance(&[( -// &String::from(MOCK_CONTRACT_ADDR), -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::new(100_000000000000000000 + 100_000000000000000000 /* user deposit must be pre-applied */), -// }], -// )]); -// -// deps.querier.with_token_balances(&[ -// ( -// &String::from("liquidity0000"), -// &[( -// &String::from(MOCK_CONTRACT_ADDR), -// &Uint128::new(100_000000000000000000), -// )], -// ), -// ( -// &String::from("asset0000"), -// &[( -// &String::from(MOCK_CONTRACT_ADDR), -// &Uint128::new(100_000000000000000000), -// )], -// ), -// ]); -// -// // Failed because the price is under slippage_tolerance -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::from(98_000000000000000000u128), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// ], -// slippage_tolerance: Some(Decimal::percent(1)), -// receiver: None, -// }; -// -// let env = mock_env_with_block_time(env.block.time.seconds() + 1000); -// let info = mock_info( -// "addr0001", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(100_000000000000000000u128), -// }], -// ); -// let res = execute(deps.as_mut(), env.clone(), info, msg).unwrap_err(); -// assert_eq!(res, ContractError::MaxSlippageAssertion {}); -// -// // Initialize token balance to 1:1 -// deps.querier.with_balance(&[( -// &String::from(MOCK_CONTRACT_ADDR), -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::new(100_000000000000000000 + 98_000000000000000000 /* user deposit must be pre-applied */), -// }], -// )]); -// -// // Failed because the price is under slippage_tolerance -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(98_000000000000000000u128), -// }, -// ], -// slippage_tolerance: Some(Decimal::percent(1)), -// receiver: None, -// }; -// -// let env = mock_env_with_block_time(env.block.time.seconds() + 1000); -// let info = mock_info( -// "addr0001", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(98_000000000000000000u128), -// }], -// ); -// let res = execute(deps.as_mut(), env.clone(), info, msg).unwrap_err(); -// assert_eq!(res, ContractError::MaxSlippageAssertion {}); -// -// // Initialize token amount with a 1:1 ratio -// deps.querier.with_balance(&[( -// &String::from(MOCK_CONTRACT_ADDR), -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::new(100_000000000000000000 + 100_000000000000000000 /* user deposit must be pre-applied */), -// }], -// )]); -// -// // Successfully provides liquidity -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::from(99_000000000000000000u128), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// ], -// slippage_tolerance: Some(Decimal::percent(1)), -// receiver: None, -// }; -// -// let env = mock_env_with_block_time(env.block.time.seconds() + 1000); -// let info = mock_info( -// "addr0001", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(100_000000000000000000u128), -// }], -// ); -// let _res = execute(deps.as_mut(), env.clone(), info, msg).unwrap(); -// -// // Initialize token balance to 1:1 -// deps.querier.with_balance(&[( -// &String::from(MOCK_CONTRACT_ADDR), -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::new(100_000000000000000000 + 99_000000000000000000 /* user deposit must be pre-applied */), -// }], -// )]); -// -// // Successfully provides liquidity -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(99_000000000000000000u128), -// }, -// ], -// slippage_tolerance: Some(Decimal::percent(1)), -// receiver: None, -// }; -// -// let env = mock_env_with_block_time(env.block.time.seconds() + 1000); -// let info = mock_info( -// "addr0001", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(99_000000000000000000u128), -// }], -// ); -// execute(deps.as_mut(), env, info, msg).unwrap(); -// -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::zero(), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(99_000000000000000000u128), -// }, -// ], -// slippage_tolerance: Some(Decimal::percent(1)), -// receiver: None, -// }; -// let info = mock_info( -// "addr0001", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(99_000000000000000000u128), -// }], -// ); -// let err = execute(deps.as_mut(), mock_env(), info, msg).unwrap_err(); -// assert_eq!(err, ContractError::InvalidZeroAmount {}); -// -// let msg = ExecuteMsg::ProvideLiquidity { -// assets: vec![ -// Asset { -// info: AssetInfo::Cw20Token("asset0000".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// Asset { -// info: AssetInfo::SmartToken("uusd".to_string()), -// amount: Uint128::from(100_000000000000000000u128), -// }, -// ], -// slippage_tolerance: Some(Decimal::percent(51)), -// receiver: None, -// }; -// let info = mock_info( -// "addr0001", -// &[Coin { -// denom: "uusd".to_string(), -// amount: Uint128::from(100_000000000000000000u128), -// }], -// ); -// let err = execute(deps.as_mut(), mock_env(), info, msg).unwrap_err(); -// assert_eq!(err, ContractError::AllowedSpreadAssertion {}); -// } -// +#[test] +fn provide_liquidity() { + let mut deps = mock_dependencies(&[Coin { + denom: "uusd".to_string(), + amount: Uint128::new(200_000000000000000000u128), + }]); + + deps.querier.with_token_balances(&[ + ( + &String::from("asset0000"), + &[(&String::from(MOCK_CONTRACT_ADDR), &Uint128::new(0))], + ), + ( + &String::from("liquidity0000"), + &[(&String::from(MOCK_CONTRACT_ADDR), &Uint128::new(0))], + ), + ]); + + let msg = InstantiateMsg { + factory_addr: String::from("factory"), + asset_infos: vec![ + AssetInfo::SmartToken("uusd".to_string()), + AssetInfo::Cw20Token("asset0000".to_string()), + ], + // factory_addr: String::from("factory"), + init_params: Some( + to_json_binary(&StablePoolParams { + amp: 100, + owner: None, + lsd: None, + }) + .unwrap(), + ), + staking_config: default_stake_config(), + trading_starts: 0, + fee_config: FeeConfig { + total_fee_bps: 0, + protocol_fee_bps: 0, + }, + circuit_breaker: None, + verified: true, + native_denom: "ucore".to_string(), + }; + + let env = mock_env(); + let info = mock_info("addr0000", &[]); + // We can just call .unwrap() to assert this was a success + let _res = instantiate(deps.as_mut(), env, info, msg).unwrap(); + + // Successfully provide liquidity for the existing pool + let msg = ExecuteMsg::ProvideLiquidity { + assets: vec![ + Asset { + info: AssetInfo::Cw20Token("asset0000".to_string()), + amount: Uint128::from(100_000000000000000000u128), + }, + Asset { + info: AssetInfo::SmartToken("uusd".to_string()), + amount: Uint128::from(100_000000000000000000u128), + }, + ], + slippage_tolerance: None, + receiver: None, + }; + + let env = mock_env(); + let info = mock_info( + "addr0000", + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::from(100_000000000000000000u128), + }], + ); + let res = execute(deps.as_mut(), env.clone(), info, msg).unwrap(); + let transfer_from_msg = res.messages.get(0).expect("no message"); + let mint_min_liquidity_msg = res.messages.get(1).expect("no message"); + let mint_receiver_msg = res.messages.get(2).expect("no message"); + assert_eq!( + transfer_from_msg, + &SubMsg { + msg: WasmMsg::Execute { + contract_addr: String::from("asset0000"), + msg: to_json_binary(&Cw20ExecuteMsg::TransferFrom { + owner: String::from("addr0000"), + recipient: String::from(MOCK_CONTRACT_ADDR), + amount: Uint128::from(100_000000000000000000u128), + }) + .unwrap(), + funds: vec![], + } + .into(), + id: 0, + gas_limit: None, + reply_on: ReplyOn::Never + } + ); + assert_eq!( + mint_min_liquidity_msg, + &SubMsg { + msg: CosmosMsg::Custom(CoreumMsg::AssetFT(assetft::Msg::Mint { + coin: Coin { + denom: String::from("uuusdmapplp-cosmos2contract"), + amount: Uint128::from(1_000_u128), + }, + })), + id: 0, + gas_limit: None, + reply_on: ReplyOn::Never, + } + ); + assert_eq!( + mint_receiver_msg, + &SubMsg { + msg: CosmosMsg::Custom(CoreumMsg::AssetFT(assetft::Msg::Mint { + coin: Coin { + denom: String::from("uuusdmapplp-cosmos2contract"), + amount: Uint128::from(299_814_698_523_989_456_628u128), + }, + })), + id: 0, + gas_limit: None, + reply_on: ReplyOn::Never, + } + ); + + // Provide more liquidity 1:2, which is not propotional to 1:1, + // It must accept 1:1 and treat the leftover amount as a donation + deps.querier.with_balance(&[( + &String::from(MOCK_CONTRACT_ADDR), + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::new(200_000000000000000000 + 200_000000000000000000 /* user deposit must be pre-applied */), + }], + )]); + + deps.querier.with_token_balances(&[ + ( + &String::from("liquidity0000"), + &[( + &String::from(MOCK_CONTRACT_ADDR), + &Uint128::new(100_000000000000000000), + )], + ), + ( + &String::from("asset0000"), + &[( + &String::from(MOCK_CONTRACT_ADDR), + &Uint128::new(200_000000000000000000), + )], + ), + ]); + + let msg = ExecuteMsg::ProvideLiquidity { + assets: vec![ + Asset { + info: AssetInfo::Cw20Token("asset0000".to_string()), + amount: Uint128::from(100_000000000000000000u128), + }, + Asset { + info: AssetInfo::SmartToken("uusd".to_string()), + amount: Uint128::from(200_000000000000000000u128), + }, + ], + slippage_tolerance: Some(Decimal::percent(50)), + receiver: None, + }; + + let env = mock_env_with_block_time(env.block.time.seconds() + 1000); + let info = mock_info( + "addr0000", + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::from(200_000000000000000000u128), + }], + ); + + // Only accept 100, then 50 share will be generated with 100 * (100 / 200) + let res: Response = execute(deps.as_mut(), env, info, msg).unwrap(); + let transfer_from_msg = res.messages.get(0).expect("no message"); + let mint_msg = res.messages.get(1).expect("no message"); + assert_eq!( + transfer_from_msg, + &SubMsg { + msg: WasmMsg::Execute { + contract_addr: String::from("asset0000"), + msg: to_json_binary(&Cw20ExecuteMsg::TransferFrom { + owner: String::from("addr0000"), + recipient: String::from(MOCK_CONTRACT_ADDR), + amount: Uint128::from(100_000000000000000000u128), + }) + .unwrap(), + funds: vec![], + } + .into(), + id: 0, + gas_limit: None, + reply_on: ReplyOn::Never, + } + ); + assert_eq!( + mint_msg, + &SubMsg { + msg: CosmosMsg::Custom(CoreumMsg::AssetFT(assetft::Msg::Mint { + coin: Coin { + denom: String::from("uuusdmapplp-cosmos2contract"), + amount: Uint128::from(223_682_503_077_537_010_434u128), + }, + })), + id: 0, + gas_limit: None, + reply_on: ReplyOn::Never, + } + ); + + // Check wrong argument + let msg = ExecuteMsg::ProvideLiquidity { + assets: vec![ + Asset { + info: AssetInfo::Cw20Token("asset0000".to_string()), + amount: Uint128::from(100_000000000000000000u128), + }, + Asset { + info: AssetInfo::SmartToken("uusd".to_string()), + amount: Uint128::from(50_000000000000000000u128), + }, + ], + slippage_tolerance: None, + receiver: None, + }; + + let env = mock_env(); + let info = mock_info( + "addr0000", + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::from(100_000000000000000000u128), + }], + ); + + let res = execute(deps.as_mut(), env.clone(), info, msg).unwrap_err(); + match res { + ContractError::Std(StdError::GenericErr { msg, .. }) => assert_eq!( + msg, + "SmartToken token balance mismatch between the argument and the transferred" + .to_string() + ), + _ => panic!("Must return generic error"), + } + + // Initialize token amount to the 1:1 ratio + deps.querier.with_balance(&[( + &String::from(MOCK_CONTRACT_ADDR), + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::new(100_000000000000000000 + 100_000000000000000000 /* user deposit must be pre-applied */), + }], + )]); + + deps.querier.with_token_balances(&[ + ( + &String::from("liquidity0000"), + &[( + &String::from(MOCK_CONTRACT_ADDR), + &Uint128::new(100_000000000000000000), + )], + ), + ( + &String::from("asset0000"), + &[( + &String::from(MOCK_CONTRACT_ADDR), + &Uint128::new(100_000000000000000000), + )], + ), + ]); + + let msg = ExecuteMsg::ProvideLiquidity { + assets: vec![ + Asset { + info: AssetInfo::Cw20Token("asset0000".to_string()), + amount: Uint128::from(99_000000000000000000u128), + }, + Asset { + info: AssetInfo::SmartToken("uusd".to_string()), + amount: Uint128::from(100_000000000000000000u128), + }, + ], + slippage_tolerance: Some(Decimal::percent(1)), + receiver: None, + }; + + let env = mock_env_with_block_time(env.block.time.seconds() + 1000); + let info = mock_info( + "addr0001", + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::from(100_000000000000000000u128), + }], + ); + execute(deps.as_mut(), env.clone(), info, msg).unwrap(); + + // Initialize token balance to 1:1 + deps.querier.with_balance(&[( + &String::from(MOCK_CONTRACT_ADDR), + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::new(100_000000000000000000 + 98_000000000000000000 /* user deposit must be pre-applied */), + }], + )]); + + // Failed because the price is under slippage_tolerance + let msg = ExecuteMsg::ProvideLiquidity { + assets: vec![ + Asset { + info: AssetInfo::Cw20Token("asset0000".to_string()), + amount: Uint128::from(100_000000000000000000u128), + }, + Asset { + info: AssetInfo::SmartToken("uusd".to_string()), + amount: Uint128::from(98_000000000000000000u128), + }, + ], + slippage_tolerance: Some(Decimal::percent(1)), + receiver: None, + }; + + let env = mock_env_with_block_time(env.block.time.seconds() + 1000); + let info = mock_info( + "addr0001", + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::from(98_000000000000000000u128), + }], + ); + execute(deps.as_mut(), env.clone(), info, msg).unwrap(); + + // Initialize token amount with a 1:1 ratio + deps.querier.with_balance(&[( + &String::from(MOCK_CONTRACT_ADDR), + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::new(100_000000000000000000 + 100_000000000000000000 /* user deposit must be pre-applied */), + }], + )]); + + // Successfully provides liquidity + let msg = ExecuteMsg::ProvideLiquidity { + assets: vec![ + Asset { + info: AssetInfo::Cw20Token("asset0000".to_string()), + amount: Uint128::from(99_000000000000000000u128), + }, + Asset { + info: AssetInfo::SmartToken("uusd".to_string()), + amount: Uint128::from(100_000000000000000000u128), + }, + ], + slippage_tolerance: Some(Decimal::percent(1)), + receiver: None, + }; + + let env = mock_env_with_block_time(env.block.time.seconds() + 1000); + let info = mock_info( + "addr0001", + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::from(100_000000000000000000u128), + }], + ); + let _res = execute(deps.as_mut(), env.clone(), info, msg).unwrap(); + + // Initialize token balance to 1:1 + deps.querier.with_balance(&[( + &String::from(MOCK_CONTRACT_ADDR), + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::new(100_000000000000000000 + 99_000000000000000000 /* user deposit must be pre-applied */), + }], + )]); + + // Successfully provides liquidity + let msg = ExecuteMsg::ProvideLiquidity { + assets: vec![ + Asset { + info: AssetInfo::Cw20Token("asset0000".to_string()), + amount: Uint128::from(100_000000000000000000u128), + }, + Asset { + info: AssetInfo::SmartToken("uusd".to_string()), + amount: Uint128::from(99_000000000000000000u128), + }, + ], + slippage_tolerance: Some(Decimal::percent(1)), + receiver: None, + }; + + let env = mock_env_with_block_time(env.block.time.seconds() + 1000); + let info = mock_info( + "addr0001", + &[Coin { + denom: "uusd".to_string(), + amount: Uint128::from(99_000000000000000000u128), + }], + ); + execute(deps.as_mut(), env, info, msg).unwrap(); +} + // #[test] // fn withdraw_liquidity() { // let mut deps = mock_dependencies(&[Coin { @@ -1875,112 +1841,3 @@ fn mock_env_with_block_time(time: u64) -> Env { }; env } - -// #[test] -// fn compute_swap_rounding() { -// let offer_pool = Uint128::from(5_000_000_000_000_u128); -// let ask_pool = Uint128::from(1_000_000_000_u128); -// let return_amount = Uint128::from(0_u128); -// let spread_amount = Uint128::from(0_u128); -// let commission_amount = Uint128::from(0_u128); -// let offer_amount = Uint128::from(1_u128); -// -// assert_eq!( -// compute_swap(offer_pool, ask_pool, offer_amount, Decimal::zero()), -// Ok((return_amount, spread_amount, commission_amount)) -// ); -// } -// -// proptest! { -// #[test] -// fn compute_swap_overflow_test( -// offer_pool in 1_000_000..9_000_000_000_000_000_000u128, -// ask_pool in 1_000_000..9_000_000_000_000_000_000u128, -// offer_amount in 1..100_000_000_000u128, -// ) { -// -// let offer_pool = Uint128::from(offer_pool); -// let ask_pool = Uint128::from(ask_pool); -// let offer_amount = Uint128::from(offer_amount); -// let commission_amount = Decimal::zero(); -// -// // Make sure there are no overflows -// compute_swap( -// offer_pool, -// ask_pool, -// offer_amount, -// commission_amount, -// ).unwrap(); -// } -// } -// -// #[test] -// fn ensure_useful_error_messages_are_given_on_swaps() { -// const OFFER: Uint128 = Uint128::new(1_000_000_000_000); -// const ASK: Uint128 = Uint128::new(1_000_000_000_000); -// const AMOUNT: Uint128 = Uint128::new(1_000_000); -// const ZERO: Uint128 = Uint128::zero(); -// const DZERO: Decimal = Decimal::zero(); -// -// // Computing ask -// assert_eq!( -// compute_swap(ZERO, ZERO, ZERO, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_swap(ZERO, ZERO, AMOUNT, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_swap(ZERO, ASK, ZERO, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_swap(ZERO, ASK, AMOUNT, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_swap(OFFER, ZERO, ZERO, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_swap(OFFER, ZERO, AMOUNT, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_swap(OFFER, ASK, ZERO, DZERO).unwrap_err(), -// StdError::generic_err("Swap amount must not be zero") -// ); -// compute_swap(OFFER, ASK, AMOUNT, DZERO).unwrap(); -// -// // Computing offer -// assert_eq!( -// compute_offer_amount(ZERO, ZERO, ZERO, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_offer_amount(ZERO, ZERO, AMOUNT, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_offer_amount(ZERO, ASK, ZERO, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_offer_amount(ZERO, ASK, AMOUNT, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_offer_amount(OFFER, ZERO, ZERO, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_offer_amount(OFFER, ZERO, AMOUNT, DZERO).unwrap_err(), -// StdError::generic_err("One of the pools is empty") -// ); -// assert_eq!( -// compute_offer_amount(OFFER, ASK, ZERO, DZERO).unwrap_err(), -// StdError::generic_err("Swap amount must not be zero") -// ); -// compute_offer_amount(OFFER, ASK, AMOUNT, DZERO).unwrap(); -// }