diff --git a/Cargo.lock b/Cargo.lock index c0a88a9..68a25ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,16 +284,6 @@ dependencies = [ "uint", ] -[[package]] -name = "cosmwasm-storage" -version = "1.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9e21c4f58986fd20184d7685e1c43c5732c9309337b09307d5952fd34dba6e" -dependencies = [ - "cosmwasm-std", - "serde", -] - [[package]] name = "cpufeatures" version = "0.2.8" @@ -344,20 +334,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "cw-controllers" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64bfeaf55f8dba5646cc3daddce17cd23a60f8e0c3fbacbe6735d287d7a6e33a" -dependencies = [ - "cosmwasm-std", - "cw-storage-plus 0.11.1", - "cw-utils 0.11.1", - "schemars", - "serde", - "thiserror", -] - [[package]] name = "cw-controllers" version = "1.0.1" @@ -366,8 +342,8 @@ checksum = "91440ce8ec4f0642798bc8c8cb6b9b53c1926c6dadaf0eed267a5145cd529071" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", + "cw-storage-plus", + "cw-utils", "schemars", "serde", "thiserror", @@ -381,8 +357,8 @@ checksum = "127c7bb95853b8e828bdab97065c81cb5ddc20f7339180b61b2300565aaa99d1" dependencies = [ "anyhow", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", + "cw-storage-plus", + "cw-utils", "derivative", "itertools", "k256", @@ -399,8 +375,8 @@ source = "git+https://github.com/wynddao/wynddex?tag=v2.1.0#a578f8b645433e108a10 dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw2 1.0.1", + "cw-storage-plus", + "cw2", "thiserror", ] @@ -410,8 +386,8 @@ version = "2.2.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw2 1.0.1", + "cw-storage-plus", + "cw2", "thiserror", ] @@ -422,36 +398,14 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", + "cw20-base", "thiserror", ] -[[package]] -name = "cw-storage-plus" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b8b840947313c1a1cccf056836cd79a60b4526bdcd6582995be37dc97be4ae" -dependencies = [ - "cosmwasm-std", - "schemars", - "serde", -] - -[[package]] -name = "cw-storage-plus" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d7ee1963302b0ac2a9d42fe0faec826209c17452bfd36fbfd9d002a88929261" -dependencies = [ - "cosmwasm-std", - "schemars", - "serde", -] - [[package]] name = "cw-storage-plus" version = "1.1.0" @@ -463,18 +417,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cw-utils" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef842a1792e4285beff7b3b518705f760fa4111dc1e296e53f3e92d1ef7f6220" -dependencies = [ - "cosmwasm-std", - "schemars", - "serde", - "thiserror", -] - [[package]] name = "cw-utils" version = "1.0.1" @@ -483,49 +425,13 @@ checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw2 1.0.1", + "cw2", "schemars", "semver", "serde", "thiserror", ] -[[package]] -name = "cw0" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae676b6cced78a3d38ad4b01ab4ed66fc78ac191c3c0d6bfd5372cb2efd473b" -dependencies = [ - "cosmwasm-std", - "schemars", - "serde", - "thiserror", -] - -[[package]] -name = "cw2" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7002e6f9c1a1ef3915dca704a6306ba00c39495efd928551d6077c734f9a3d8" -dependencies = [ - "cosmwasm-std", - "cw-storage-plus 0.10.3", - "schemars", - "serde", -] - -[[package]] -name = "cw2" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1d81d7c359d6c1fba3aa83dad7ec6f999e512571380ae62f81257c3db569743" -dependencies = [ - "cosmwasm-std", - "cw-storage-plus 0.11.1", - "schemars", - "serde", -] - [[package]] name = "cw2" version = "1.0.1" @@ -534,31 +440,7 @@ checksum = "8fb70cee2cf0b4a8ff7253e6bc6647107905e8eb37208f87d54f67810faa62f8" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "schemars", - "serde", -] - -[[package]] -name = "cw20" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56fc9d54b9b365801beb101a5c0375dceaa5a285bfc14438a7b6007f9d362142" -dependencies = [ - "cosmwasm-std", - "cw0", - "schemars", - "serde", -] - -[[package]] -name = "cw20" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9671d7edef5608acaf5b2f1e473ee3f501eced2cd4f7392e2106c8cf02ba0720" -dependencies = [ - "cosmwasm-std", - "cw-utils 0.11.1", + "cw-storage-plus", "schemars", "serde", ] @@ -571,43 +453,11 @@ checksum = "91666da6c7b40c8dd5ff94df655a28114efc10c79b70b4d06f13c31e37d60609" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-utils 1.0.1", + "cw-utils", "schemars", "serde", ] -[[package]] -name = "cw20-base" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5df0a946a4a58dd4fdb158ff1595c55774beeef76d09f108b547bce572dcf" -dependencies = [ - "cosmwasm-std", - "cw-storage-plus 0.10.3", - "cw0", - "cw2 0.10.3", - "cw20 0.10.3", - "schemars", - "serde", - "thiserror", -] - -[[package]] -name = "cw20-base" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f6fc8c4cd451b418fa4f1ac2ea70595811fa9d8b4033617fe47953d7a93ceb" -dependencies = [ - "cosmwasm-std", - "cw-storage-plus 0.11.1", - "cw-utils 0.11.1", - "cw2 0.11.1", - "cw20 0.11.1", - "schemars", - "serde", - "thiserror", -] - [[package]] name = "cw20-base" version = "1.0.1" @@ -616,10 +466,10 @@ checksum = "afcd279230b08ed8afd8be5828221622bd5b9ce25d0b01d58bad626c6ce0169c" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", "schemars", "semver", "serde", @@ -797,10 +647,10 @@ dependencies = [ "cosmwasm-std", "cw-multi-test", "cw-placeholder 2.2.0", - "cw-storage-plus 1.1.0", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw2", + "cw20", + "cw20-base", "palomadex", "palomadex-factory", "palomadex-pair", @@ -925,32 +775,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" -[[package]] -name = "junoswap-staking" -version = "2.2.0" -dependencies = [ - "anyhow", - "cosmwasm-schema", - "cosmwasm-std", - "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw-utils 0.11.1", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 0.10.3", - "cw20 1.0.1", - "cw20-base 0.10.3", - "cw20-base 1.0.1", - "palomadex", - "palomadex-factory", - "palomadex-pair", - "palomadex-stake", - "serde", - "stake-cw20", - "thiserror", - "wasmswap", -] - [[package]] name = "k256" version = "0.11.6" @@ -1001,10 +825,10 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw2", + "cw20", + "cw20-base", "palomadex", "palomadex-factory", "palomadex-pair", @@ -1027,11 +851,11 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", + "cw20-base", "palomadex", "palomadex-factory", "palomadex-multi-hop", @@ -1069,10 +893,10 @@ version = "2.2.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw20", + "cw20-base", "itertools", "thiserror", "uint", @@ -1087,11 +911,11 @@ dependencies = [ "cosmwasm-std", "cw-multi-test", "cw-placeholder 2.2.0", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", + "cw20-base", "itertools", "palomadex", "palomadex-pair", @@ -1108,11 +932,11 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", + "cw20-base", "palomadex", "palomadex-factory", "palomadex-pair", @@ -1127,11 +951,11 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", + "cw20-base", "palomadex", "palomadex-factory", "palomadex-stake", @@ -1146,11 +970,11 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", + "cw20-base", "derivative", "itertools", "palomadex", @@ -1167,13 +991,13 @@ dependencies = [ "anyhow", "cosmwasm-schema", "cosmwasm-std", - "cw-controllers 1.0.1", + "cw-controllers", "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", + "cw20-base", "lp-converter", "palomadex", "serde", @@ -1347,32 +1171,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "raw-migration" -version = "2.2.0" -dependencies = [ - "anyhow", - "cosmwasm-schema", - "cosmwasm-std", - "cw-multi-test", - "cw-storage-plus 1.1.0", - "cw-utils 0.11.1", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 0.10.3", - "cw20 1.0.1", - "cw20-base 0.10.3", - "cw20-base 1.0.1", - "palomadex", - "palomadex-factory", - "palomadex-pair", - "palomadex-stake", - "serde", - "stake-cw20", - "thiserror", - "wasmswap", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -1595,24 +1393,6 @@ dependencies = [ "quickcheck", ] -[[package]] -name = "stake-cw20" -version = "0.2.6" -source = "git+https://github.com/DA0-DA0/dao-contracts?tag=v0.3.0#5d46fc6f4a9a2fed3a85e700215d0421e1c196be" -dependencies = [ - "cosmwasm-std", - "cosmwasm-storage", - "cw-controllers 0.11.1", - "cw-storage-plus 0.11.1", - "cw-utils 0.11.1", - "cw2 0.11.1", - "cw20 0.11.1", - "cw20-base 0.11.1", - "schemars", - "serde", - "thiserror", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -1697,8 +1477,8 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-multi-test", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw20", + "cw20-base", "palomadex", "palomadex-factory", "palomadex-multi-hop", @@ -1783,23 +1563,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasmswap" -version = "1.1.2-beta" -source = "git+https://github.com/Wasmswap/wasmswap-contracts?tag=v1.1.2-beta#621197915656ace61c5cb31f3305a0abf058c62d" -dependencies = [ - "cosmwasm-std", - "cosmwasm-storage", - "cw-storage-plus 0.10.3", - "cw0", - "cw2 0.11.1", - "cw20 0.10.3", - "cw20-base 0.10.3", - "schemars", - "serde", - "thiserror", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -1873,12 +1636,12 @@ source = "git+https://github.com/wynddao/wynd-lsd.git#cbb30b5c521f80848209a36f57 dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-controllers 1.0.1", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-controllers", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", + "cw20-base", "semver", "thiserror", ] @@ -1912,10 +1675,10 @@ source = "git+https://github.com/wynddao/wynddex?tag=v2.0.2#592cee00712aa0c7840a dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw20", + "cw20-base", "itertools", "thiserror", "uint", @@ -1928,10 +1691,10 @@ source = "git+https://github.com/wynddao/wynddex?tag=v2.1.0#a578f8b645433e108a10 dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw20 1.0.1", - "cw20-base 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw20", + "cw20-base", "itertools", "thiserror", "uint", @@ -1945,9 +1708,9 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-placeholder 2.1.0", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", + "cw-storage-plus", + "cw-utils", + "cw2", "itertools", "thiserror", "wyndex 2.1.0", @@ -1961,11 +1724,11 @@ source = "git+https://github.com/wynddao/wynddex?tag=v2.0.2#592cee00712aa0c7840a dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-controllers 1.0.1", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", + "cw-controllers", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", "serde", "thiserror", "wynd-utils 1.6.0 (git+https://github.com/cosmorama/wynddao.git?tag=v1.6.0)", @@ -1979,11 +1742,11 @@ source = "git+https://github.com/wynddao/wynddex?tag=v2.1.0#a578f8b645433e108a10 dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-controllers 1.0.1", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.0.1", - "cw20 1.0.1", + "cw-controllers", + "cw-storage-plus", + "cw-utils", + "cw2", + "cw20", "serde", "thiserror", "wynd-utils 1.6.0 (git+https://github.com/cosmorama/wynddao.git?tag=v1.6.0)", diff --git a/contracts/cw-placeholder/src/contract.rs b/contracts/cw-placeholder/src/contract.rs index e8dbaff..8a41ac2 100644 --- a/contracts/cw-placeholder/src/contract.rs +++ b/contracts/cw-placeholder/src/contract.rs @@ -7,7 +7,7 @@ use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( - deps: DepsMut, + _deps: DepsMut, _env: Env, _info: MessageInfo, _msg: InstantiateMsg, diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 88d49fb..690f916 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -9,9 +9,9 @@ use palomadex::common::{ claim_ownership, drop_ownership_proposal, propose_new_owner, validate_addresses, }; use palomadex::factory::{ - ConfigResponse, DistributionFlow, ExecuteMsg, FeeInfoResponse, InstantiateMsg, MigrateMsg, - PairConfig, PairType, PairsResponse, PartialDefaultStakeConfig, PartialStakeConfig, QueryMsg, - ReceiveMsg, ROUTE, + ConfigResponse, DistributionFlow, ExecuteMsg, FeeInfoResponse, InstantiateMsg, PairConfig, + PairType, PairsResponse, PartialDefaultStakeConfig, PartialStakeConfig, QueryMsg, ReceiveMsg, + ROUTE, }; use palomadex::fee_config::FeeConfig; use palomadex::stake::UnbondingPeriod; @@ -693,8 +693,8 @@ pub fn deregister_pool_and_staking( Ok(pairs .unwrap_or_default() .iter() + .filter(|&pair| pair != pair_addr) .cloned() - .filter(|pair| pair != pair_addr) .collect::>()) }, )?; diff --git a/contracts/factory/tests/integration.rs b/contracts/factory/tests/integration.rs index 4560ee6..14b83fe 100644 --- a/contracts/factory/tests/integration.rs +++ b/contracts/factory/tests/integration.rs @@ -3,8 +3,8 @@ mod factory_helper; use cosmwasm_std::{attr, from_slice, Addr, Decimal, StdError, Uint128}; use palomadex::asset::AssetInfo; use palomadex::factory::{ - ConfigResponse, DefaultStakeConfig, ExecuteMsg, FeeInfoResponse, InstantiateMsg, MigrateMsg, - PairConfig, PairType, PartialDefaultStakeConfig, QueryMsg, + ConfigResponse, DefaultStakeConfig, ExecuteMsg, FeeInfoResponse, InstantiateMsg, PairConfig, + PairType, PartialDefaultStakeConfig, QueryMsg, }; use palomadex::fee_config::FeeConfig; use palomadex::pair::PairInfo; @@ -12,22 +12,11 @@ use palomadex_factory::{error::ContractError, state::Config}; use crate::factory_helper::{instantiate_token, FactoryHelper}; use cw_multi_test::{App, ContractWrapper, Executor}; -use cw_placeholder::msg::InstantiateMsg as PlaceholderContractInstantiateMsg; use palomadex::pair::ExecuteMsg as PairExecuteMsg; fn mock_app() -> App { App::default() } -fn store_placeholder_code(app: &mut App) -> u64 { - let placeholder_contract = Box::new(ContractWrapper::new_with_empty( - cw_placeholder::contract::execute, - cw_placeholder::contract::instantiate, - cw_placeholder::contract::query, - )); - - app.store_code(placeholder_contract) -} - fn store_factory_code(app: &mut App) -> u64 { let factory_contract = Box::new( ContractWrapper::new_with_empty( @@ -868,79 +857,3 @@ fn check_update_owner() { assert_eq!(res.owner, new_owner) } - -#[test] -fn can_migrate_the_placeholder_to_a_factory_properly() { - let mut app = mock_app(); - - let owner = Addr::unchecked("owner"); - - let place_holder_id = store_placeholder_code(&mut app); - let factory_id = store_factory_code(&mut app); - - let pair_configs = vec![PairConfig { - code_id: 321, - pair_type: PairType::Xyk {}, - fee_config: FeeConfig { - total_fee_bps: 100, - protocol_fee_bps: 10, - }, - is_disabled: false, - }]; - // Instantiate an instance of the placeholder contract which we will migrate - let placeholder = app - .instantiate_contract( - place_holder_id, - owner.clone(), - &PlaceholderContractInstantiateMsg {}, - &[], - "placeholder", - Some(owner.clone().into_string()), - ) - .unwrap(); - - let factory_msg = InstantiateMsg { - pair_configs: pair_configs.clone(), - token_code_id: 123, - fee_address: None, - owner: owner.to_string(), - max_referral_commission: Decimal::one(), - default_stake_config: default_stake_config(), - trading_starts: None, - }; - // Migrate the contract - app.migrate_contract( - owner.clone(), - placeholder.clone(), - &MigrateMsg::Init(factory_msg.clone()), - factory_id, - ) - .unwrap(); - - // Now instantiate a normal factory directly - let factory_instance = app - .instantiate_contract( - factory_id, - Addr::unchecked(owner.clone()), - &factory_msg, - &[], - "factory", - None, - ) - .unwrap(); - // To verify we will check configs, confirming its the same ConfigResponse and the same values - let msg = QueryMsg::Config {}; - // Query the 'placeholder' which is now a Factory - let migrated_factory_config: ConfigResponse = - app.wrap().query_wasm_smart(&placeholder, &msg).unwrap(); - let direct_factory_config: ConfigResponse = - app.wrap().query_wasm_smart(factory_instance, &msg).unwrap(); - - assert_eq!(123, migrated_factory_config.token_code_id); - assert_eq!(pair_configs, migrated_factory_config.pair_configs); - assert_eq!(owner, migrated_factory_config.owner); - - assert_eq!(123, direct_factory_config.token_code_id); - assert_eq!(pair_configs, direct_factory_config.pair_configs); - assert_eq!(owner, direct_factory_config.owner); -} diff --git a/contracts/gauge-adapter/src/contract.rs b/contracts/gauge-adapter/src/contract.rs index 90fd08f..5b751f3 100644 --- a/contracts/gauge-adapter/src/contract.rs +++ b/contracts/gauge-adapter/src/contract.rs @@ -11,7 +11,7 @@ use palomadex::stake::{FundingInfo, ReceiveMsg as StakeReceiveDelegationMsg}; use palomadex_stake::msg::ExecuteMsg as StakeExecuteMsg; use crate::error::ContractError; -use crate::msg::{AdapterQueryMsg, ExecuteMsg, InstantiateMsg, MigrateMsg}; +use crate::msg::{AdapterQueryMsg, ExecuteMsg, InstantiateMsg}; use crate::state::{Config, CONFIG}; #[cfg_attr(not(feature = "library"), entry_point)] diff --git a/contracts/gauge-adapter/src/multitest/sample.rs b/contracts/gauge-adapter/src/multitest/sample.rs index dbeeca8..db1b247 100644 --- a/contracts/gauge-adapter/src/multitest/sample.rs +++ b/contracts/gauge-adapter/src/multitest/sample.rs @@ -166,26 +166,6 @@ fn cw20_rewards_work_direct() { cw20_rewards_work(suite); } -#[test] -// Like the above test, but here we create the adapter via migration -fn cw20_rewards_work_via_migration() { - let suite = SuiteBuilder::new() - .with_funds("owner", &[]) - .with_stake_config(DefaultStakeConfig { - staking_code_id: 0, - tokens_per_power: 1000u128.into(), - min_bond: 1000u128.into(), - unbonding_periods: vec![SECONDS_PER_DAY * 7], - max_distributions: 5, - converter: None, - }) - .with_cw20_reward(100) - .via_placeholder() - .build(); - - cw20_rewards_work(suite); -} - fn cw20_rewards_work(mut suite: Suite) { // FIXME: how does this work? AssetInfo::to_string() ?? not a cleaner way to unwrap the enum? let reward_contract = Addr::unchecked(suite.reward.info.to_string()); diff --git a/contracts/gauge-adapter/src/multitest/suite.rs b/contracts/gauge-adapter/src/multitest/suite.rs index 8cf8221..3ff815e 100644 --- a/contracts/gauge-adapter/src/multitest/suite.rs +++ b/contracts/gauge-adapter/src/multitest/suite.rs @@ -126,11 +126,6 @@ impl SuiteBuilder { self } - pub fn via_placeholder(mut self) -> Self { - self.via_placeholder = true; - self - } - pub fn with_native_reward(mut self, amount: u128, denom: &str) -> Self { self.reward = Asset { amount: amount.into(), diff --git a/contracts/junoswap-staking/.cargo/config b/contracts/junoswap-staking/.cargo/config deleted file mode 100644 index de2d36a..0000000 --- a/contracts/junoswap-staking/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[alias] -wasm = "build --release --lib --target wasm32-unknown-unknown" -wasm-debug = "build --lib --target wasm32-unknown-unknown" -unit-test = "test --lib" -schema = "run --bin schema" diff --git a/contracts/junoswap-staking/Cargo.toml b/contracts/junoswap-staking/Cargo.toml deleted file mode 100644 index 892c0d9..0000000 --- a/contracts/junoswap-staking/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -[package] -name = "junoswap-staking" -authors = ["Volume Fi"] -version = { workspace = true } -edition = { workspace = true } -description = "Contract aimed just for migration - take JunoSwap staked LP and migrate to PALOMA DEX" -license = { workspace = true } -repository = { workspace = true } -homepage = "https://www.palomachain.com" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -# for more explicit tests, cargo test --features=backtraces -backtraces = ["cosmwasm-std/backtraces"] -# use library feature to disable all instantiate/execute/query exports -library = [] - -[dependencies] -cosmwasm-schema = { workspace = true } -cosmwasm-std = { workspace = true } -cw-storage-plus = { workspace = true } -cw2 = { workspace = true } -cw20 = { workspace = true } -cw-utils = { workspace = true } -thiserror = { workspace = true } - -palomadex = { workspace = true } -palomadex-factory = { workspace = true } -palomadex-stake = { workspace = true } -# this is old version of cw20 used by wasmswap -wasmswap_cw20 = { package = "cw20", version = "0.10.0" } -# this is the staking contract we are migrating from (use the state variables there) -stake-cw20 = { git="https://github.com/DA0-DA0/dao-contracts", tag="v0.3.0" } -# this is the pool contract we will withdraw from -wasmswap = { git="https://github.com/Wasmswap/wasmswap-contracts", tag="v1.1.2-beta" } - -[dev-dependencies] -anyhow = { workspace = true } -cw-multi-test = { workspace = true } -serde = { workspace = true } -wasmswap_cw20-base = { package = "cw20-base", version = "0.10.0" } -wasmswap_cw-utils = { package = "cw-utils", version = "0.11" } -palomadex-factory = { workspace = true } -palomadex-pair = { workspace = true } -cw20-base = { workspace = true } diff --git a/contracts/junoswap-staking/README.md b/contracts/junoswap-staking/README.md deleted file mode 100644 index 4c3b105..0000000 --- a/contracts/junoswap-staking/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# JunoSwap Staking Migration - -This contract is intended as a migration target for an existing JunoSwap staking contract. -Upon migration it will prepare for a future transfer (we don't know the exact pool address, -as we want to perform the migration proposal concurrently with the pool deployment proposal). - -Once it is migrated, the staking contract will be locked, and the only action is that -a nominated migrator account can trigger the transfer of the LP controlled by the staking pool -to a palomadex pool. We add some constraints to ensure this is transferred to a valid target contract -to minimize any trust requirements on the migrator (they just have "censorship" power). - diff --git a/contracts/junoswap-staking/src/bin/schema.rs b/contracts/junoswap-staking/src/bin/schema.rs deleted file mode 100644 index 617c526..0000000 --- a/contracts/junoswap-staking/src/bin/schema.rs +++ /dev/null @@ -1,12 +0,0 @@ -use cosmwasm_schema::write_api; -use cosmwasm_std::Empty; -use junoswap_staking::msg::{ExecuteMsg, MigrateMsg, QueryMsg}; - -fn main() { - write_api! { - instantiate: Empty, - query: QueryMsg, - execute: ExecuteMsg, - migrate: MigrateMsg, - } -} diff --git a/contracts/junoswap-staking/src/contract.rs b/contracts/junoswap-staking/src/contract.rs deleted file mode 100644 index c88af48..0000000 --- a/contracts/junoswap-staking/src/contract.rs +++ /dev/null @@ -1,448 +0,0 @@ -#[cfg(not(feature = "library"))] -use cosmwasm_std::entry_point; -use cosmwasm_std::{ - coin, ensure_eq, to_binary, Addr, Binary, Coin, Deps, DepsMut, Empty, Env, MessageInfo, Order, - Reply, Response, StdResult, SubMsg, Uint128, WasmMsg, -}; - -use cw2::{get_contract_version, set_contract_version}; -use cw_utils::ensure_from_older_version; -use palomadex::asset::{Asset, AssetInfo}; -use wasmswap::msg::InfoResponse; - -use crate::error::ContractError; -use crate::msg::{ExecuteMsg, MigrateMsg, QueryMsg}; -use crate::state::{MigrateConfig, MigrateStakersConfig, DESTINATION, MIGRATION}; - -// this is the contract we are migrating from -pub const STAKE_CW20_NAME: &str = "crates.io:stake_cw20"; - -// version info for migration info -const CONTRACT_NAME: &str = "crates.io:junoswap-staking"; -const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn instantiate( - _deps: DepsMut, - _env: Env, - _info: MessageInfo, - _msg: Empty, -) -> Result { - Err(ContractError::NotImplemented) -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> Result { - match msg { - QueryMsg::MigrationFinished {} => { - let no_stakers = stake_cw20::state::STAKED_BALANCES - .keys(_deps.storage, None, None, Order::Ascending) - .next() - .is_none(); - Ok(to_binary(&no_stakers)?) - } - } -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn execute( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: ExecuteMsg, -) -> Result { - match msg { - ExecuteMsg::MigrateTokens { palomadex_pool } => migrate_tokens(deps, env, info, palomadex_pool), - ExecuteMsg::MigrateStakers { limit } => migrate_stakers(deps, env, info, limit), - } -} - -/// Allow `migrator` to pull out LP positions and send them to paloma dex pool -/// First step figures out how many LPs we have and withdraws them. -/// Follow up via reply. -pub fn migrate_tokens( - deps: DepsMut, - env: Env, - info: MessageInfo, - palomadex_pool: String, -) -> Result { - // make sure called by proper account - let mut migration = MIGRATION.load(deps.storage)?; - if info.sender != migration.migrator { - return Err(ContractError::Unauthorized); - } - - // ensure the requested target pool is valid - let w_pool = deps.api.addr_validate(&palomadex_pool)?; - if let Some(ref target) = migration.palomadex_pool { - if target != w_pool { - return Err(ContractError::InvalidDestination(palomadex_pool)); - } - } - let ci = deps.querier.query_wasm_contract_info(&w_pool)?; - if ci.creator != migration.factory { - return Err(ContractError::InvalidDestination(palomadex_pool)); - } - - // save target pool for later reply block - DESTINATION.save(deps.storage, &w_pool)?; - - // calculate LP tokens owner by staking contract, - // for withdrawal and for future distribution - let stake_cfg = stake_cw20::state::CONFIG.load(deps.storage)?; - let token = cw20::Cw20Contract(stake_cfg.token_address); - let balance = token.balance(&deps.querier, env.contract.address)?; - - // fill in most of the migration data now (minus paloma dex LP) - let palomadex::pair::PairInfo { - liquidity_token, - staking_addr, - .. - } = deps - .querier - .query_wasm_smart(&w_pool, &palomadex::pair::QueryMsg::Pair {})?; - - // total_staked is same a balance of junoswap lp token held by this contract - migration.migrate_stakers_config = Some(MigrateStakersConfig { - lp_token: liquidity_token, - staking_addr, - total_lp_tokens: Uint128::zero(), - total_staked: balance, - }); - MIGRATION.save(deps.storage, &migration)?; - - // trigger withdrawal of LP tokens - // we need to assign a cw20 allowance to let the pool burn LP - let allowance = WasmMsg::Execute { - contract_addr: token.0.to_string(), - funds: vec![], - msg: to_binary(&cw20::Cw20ExecuteMsg::IncreaseAllowance { - spender: migration.junoswap_pool.to_string(), - amount: balance, - expires: None, - })?, - }; - - // then craft the LP withdrawal message - let withdraw = WasmMsg::Execute { - contract_addr: migration.junoswap_pool.into_string(), - funds: vec![], - msg: to_binary(&wasmswap::msg::ExecuteMsg::RemoveLiquidity { - amount: balance, - min_token1: Uint128::zero(), - min_token2: Uint128::zero(), - expiration: None, - })?, - }; - - // execute these and handle the next step in reply - let res = Response::new() - .add_message(allowance) - .add_submessage(SubMsg::reply_on_success(withdraw, REPLY_ONE)); - Ok(res) -} - -pub fn migrate_stakers( - mut deps: DepsMut, - env: Env, - info: MessageInfo, - limit: u32, -) -> Result { - // make sure called by proper account - let migration = MIGRATION.load(deps.storage)?; - ensure_eq!(info.sender, migration.migrator, ContractError::Unauthorized); - - let config = migration - .migrate_stakers_config - .ok_or(ContractError::TokensNotMigrated)?; - - // calculate next `limit` stakers and their shares - let stakers = find_stakers(deps.as_ref(), limit)?; - - // remove the processed stakers from the state - remove_stakers(deps.branch(), &env, stakers.iter().map(|(addr, _)| addr))?; - - let staker_lps: Vec<_> = stakers - .into_iter() - .map(|(addr, stake)| { - ( - addr.to_string(), - stake * config.total_lp_tokens / config.total_staked, - ) - }) - .filter(|(_, x)| !x.is_zero()) - .collect(); - - // the amount of LP tokens we are migrating in this message - let batch_lp: Uint128 = staker_lps.iter().map(|(_, x)| x).sum(); - - // bonding has full info on who receives the delegation - let bond_msg = palomadex::stake::ReceiveMsg::MassDelegate { - unbonding_period: migration.unbonding_period, - delegate_to: staker_lps, - }; - - // stake it all - let stake_msg = WasmMsg::Execute { - contract_addr: config.lp_token.to_string(), - funds: vec![], - msg: to_binary(&cw20::Cw20ExecuteMsg::Send { - contract: config.staking_addr.into_string(), - amount: batch_lp, - msg: to_binary(&bond_msg)?, - })?, - }; - - Ok(Response::new().add_message(stake_msg)) -} - -const REPLY_ONE: u64 = 111; -const REPLY_TWO: u64 = 222; - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result { - if msg.result.is_err() { - return Err(ContractError::ErrorReply); - } - match msg.id { - REPLY_ONE => reply_one(deps, env), - REPLY_TWO => reply_two(deps, env), - x => Err(ContractError::UnknownReply(x)), - } -} - -/// In this step, we deposit the new raw tokens (eg. JUNO-ATOM) into PALOMA DEX -/// And get some liquid PALOMA DEX LP tokens -pub fn reply_one(deps: DepsMut, env: Env) -> Result { - let migration = MIGRATION.load(deps.storage)?; - let destination = DESTINATION.load(deps.storage)?; - - // get the JS asset types and convert to PALOMA DEX types - let info: InfoResponse = deps - .querier - .query_wasm_smart(migration.junoswap_pool, &wasmswap::msg::QueryMsg::Info {})?; - let assets = to_palomadex_assets(deps.as_ref(), env.contract.address, info)?; - - // figure out how to transfer these... previous cw20 allowances or - // sending native funds inline with providing liquidity - let (allowances, funds) = prepare_denom_deposits(&destination, &assets)?; - let deposit = WasmMsg::Execute { - contract_addr: destination.into_string(), - funds, - msg: to_binary(&palomadex::pair::ExecuteMsg::ProvideLiquidity { - assets, - // TODO: set some value here? - slippage_tolerance: None, - receiver: None, - })?, - }; - - // add any cw20 allowances, then call to deposit the tokens and get LP - let res = Response::new() - .add_messages(allowances) - .add_submessage(SubMsg::reply_on_success(deposit, REPLY_TWO)); - Ok(res) -} - -fn prepare_denom_deposits( - destination: &Addr, - assets: &[Asset], -) -> Result<(Vec, Vec), ContractError> { - let mut msgs = vec![]; - let mut funds = vec![]; - prepare_denom_deposit(destination, &assets[0], &mut msgs, &mut funds)?; - prepare_denom_deposit(destination, &assets[1], &mut msgs, &mut funds)?; - // sort denoms for deposit - funds.sort_by(|coin1, coin2| coin1.denom.cmp(&coin2.denom)); - Ok((msgs, funds)) -} - -fn prepare_denom_deposit( - destination: &Addr, - asset: &Asset, - msgs: &mut Vec, - funds: &mut Vec, -) -> Result<(), ContractError> { - // build allowance msg or funds to transfer for this asset - match &asset.info { - AssetInfo::Token(token) => { - let embed = cw20::Cw20ExecuteMsg::IncreaseAllowance { - spender: destination.to_string(), - amount: asset.amount, - expires: None, - }; - let msg = WasmMsg::Execute { - contract_addr: token.to_string(), - msg: to_binary(&embed)?, - funds: vec![], - }; - msgs.push(msg); - } - AssetInfo::Native(denom) => { - let coin = coin(asset.amount.u128(), denom); - funds.push(coin); - } - } - Ok(()) -} - -fn to_palomadex_assets( - deps: Deps, - me: Addr, - info: InfoResponse, -) -> Result, ContractError> { - let asset1 = to_palomadex_asset(deps, &me, info.token1_denom)?; - let asset2 = to_palomadex_asset(deps, &me, info.token2_denom)?; - Ok(vec![asset1, asset2]) -} - -fn to_palomadex_asset( - deps: Deps, - me: &Addr, - token: wasmswap_cw20::Denom, -) -> Result { - let asset = match token { - wasmswap_cw20::Denom::Native(denom) => { - let balance = deps.querier.query_balance(me, denom)?; - Asset { - info: AssetInfo::Native(balance.denom), - amount: balance.amount, - } - } - wasmswap_cw20::Denom::Cw20(addr) => { - let token = cw20::Cw20Contract(addr); - let amount = token.balance(&deps.querier, me)?; - Asset { - info: AssetInfo::Token(token.0.into_string()), - amount, - } - } - }; - Ok(asset) -} - -/// Finally, with those PALOMA DEX LP tokens, we will take them all on behalf -/// of the original JunoSwap LP stakers. -pub fn reply_two(deps: DepsMut, env: Env) -> Result { - // load config for LP token and staking contract - let mut migration = MIGRATION.load(deps.storage)?; - let config = migration.migrate_stakers_config.as_mut().unwrap(); - - // how many LP do we have total - let lp_token = cw20::Cw20Contract(config.lp_token.clone()); - let total_lp_tokens = lp_token.balance(&deps.querier, env.contract.address)?; - - // store this for `migrate_stakers` to use - config.total_lp_tokens = total_lp_tokens; - MIGRATION.save(deps.storage, &migration)?; - - Ok(Response::new()) -} - -// query logic taken from https://github.com/cosmorama/wyndex-priv/pull/109 -fn find_stakers(deps: Deps, limit: impl Into>) -> StdResult> { - let balances = stake_cw20::state::STAKED_BALANCES - .range(deps.storage, None, None, Order::Ascending) - .map(|stake| { - let (addr, amount) = stake?; - - // query all pending claims and bond them as well - let claims = stake_cw20::state::CLAIMS.query_claims(deps, &addr)?; - let claims_sum = claims.claims.iter().map(|c| c.amount).sum::(); - - Ok((addr, amount + claims_sum)) - }); - match limit.into() { - Some(limit) => balances.take(limit as usize).collect(), - None => balances.collect(), - } -} - -fn remove_stakers<'a>( - deps: DepsMut, - env: &Env, - stakers: impl Iterator, -) -> Result<(), ContractError> { - for staker in stakers { - stake_cw20::state::STAKED_BALANCES.remove(deps.storage, staker, env.block.height)?; - } - Ok(()) -} -#[cfg(test)] -mod tests { - use super::*; - - use cosmwasm_std::coin; - - #[test] - fn prepare_denom_deposits_sorted() { - let destination = Addr::unchecked("destination"); - let assets = vec![ - Asset { - info: AssetInfo::Native("uusdc".to_owned()), - amount: Uint128::new(9_000_000_000u128), - }, - Asset { - info: AssetInfo::Native("ujuno".to_owned()), - amount: Uint128::new(5_000_000_000u128), - }, - ]; - - let (_, rcoins) = prepare_denom_deposits(&destination, &assets).unwrap(); - assert_eq!( - rcoins, - vec![ - coin(5_000_000_000u128, "ujuno".to_owned()), - coin(9_000_000_000u128, "uusdc".to_owned()) - ] - ); - - let assets = vec![ - Asset { - info: AssetInfo::Native("uusdc".to_owned()), - amount: Uint128::new(9_000_000_000u128), - }, - Asset { - info: AssetInfo::Native( - "ibc/0C1FFD27A01B116F10F0BC624A6A24190BC9C57B27837E23E3B43C34A193967C" - .to_owned(), - ), - amount: Uint128::new(1_000_000_000u128), - }, - ]; - let (_, rcoins) = prepare_denom_deposits(&destination, &assets).unwrap(); - assert_eq!( - rcoins, - vec![ - coin( - 1_000_000_000u128, - "ibc/0C1FFD27A01B116F10F0BC624A6A24190BC9C57B27837E23E3B43C34A193967C" - .to_owned() - ), - coin(9_000_000_000u128, "uusdc".to_owned()) - ] - ); - - let assets = vec![ - Asset { - info: AssetInfo::Token("paloma1paloma".to_owned()), - amount: Uint128::new(69_000_000_000u128), - }, - Asset { - info: AssetInfo::Native( - "ibc/0C1FFD27A01B116F10F0BC624A6A24190BC9C57B27837E23E3B43C34A193967C" - .to_owned(), - ), - amount: Uint128::new(1_000_000_000u128), - }, - ]; - let (_, rcoins) = prepare_denom_deposits(&destination, &assets).unwrap(); - assert_eq!( - rcoins, - vec![coin( - 1_000_000_000u128, - "ibc/0C1FFD27A01B116F10F0BC624A6A24190BC9C57B27837E23E3B43C34A193967C".to_owned() - ),] - ); - } -} diff --git a/contracts/junoswap-staking/src/error.rs b/contracts/junoswap-staking/src/error.rs deleted file mode 100644 index ea2a527..0000000 --- a/contracts/junoswap-staking/src/error.rs +++ /dev/null @@ -1,32 +0,0 @@ -use cosmwasm_std::StdError; -use thiserror::Error; - -#[derive(Error, Debug, PartialEq)] -pub enum ContractError { - #[error("{0}")] - Std(#[from] StdError), - - #[error("Unauthorized")] - Unauthorized, - - #[error("Tokens have to be migrated before stakers")] - TokensNotMigrated, - - #[error("{0} isn't an authorized pool to withdraw into")] - InvalidDestination(String), - - #[error("Method not implemented - only intended for migration")] - NotImplemented, - - #[error("Cannot migrate contract type: `{0}`. Only works for wasmswap staking")] - CannotMigrate(String), - - #[error("Got reply with unknown ID: {0}")] - UnknownReply(u64), - - #[error("Target factory doesn't have unbonding period: {0}")] - InvalidUnbondingPeriod(u64), - - #[error("Got reply with error, only handle success case")] - ErrorReply, -} diff --git a/contracts/junoswap-staking/src/junoswap.rs b/contracts/junoswap-staking/src/junoswap.rs deleted file mode 100644 index a239263..0000000 --- a/contracts/junoswap-staking/src/junoswap.rs +++ /dev/null @@ -1,2 +0,0 @@ -// This is state and message definitions copied from the junoswap contracts we migrate from - diff --git a/contracts/junoswap-staking/src/lib.rs b/contracts/junoswap-staking/src/lib.rs deleted file mode 100644 index a3d2c2f..0000000 --- a/contracts/junoswap-staking/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod contract; -mod error; -pub mod msg; -pub mod state; - -#[cfg(test)] -mod multitest; - -pub use error::ContractError; - -// #[cfg(test)] -// mod multitest; diff --git a/contracts/junoswap-staking/src/msg.rs b/contracts/junoswap-staking/src/msg.rs deleted file mode 100644 index 0141c70..0000000 --- a/contracts/junoswap-staking/src/msg.rs +++ /dev/null @@ -1,46 +0,0 @@ -use cosmwasm_schema::{cw_serde, QueryResponses}; - -#[cw_serde] -#[derive(QueryResponses)] -pub enum QueryMsg { - /// Checks whether all stakers have been migrated - #[returns(bool)] - MigrationFinished {}, -} - -#[cw_serde] -pub struct MigrateMsg { - /// This must be Some the first migration (from JunoSwap contracts). - /// This must be None if upgrading from junoswap-staking to junoswap-staking - pub init: Option, -} - -/// For existing contract, we need to specify which pool it can be withdrawn into -#[cw_serde] -pub struct OrigMigrateMsg { - /// This is the address that can run ExecuteMsg::MigrateTokens - pub migrator: String, - /// This is how long it will be staked on PALOMA DEX - pub unbonding_period: u64, - - /// This is the junoswap pool where the LP will be withdrawn from - pub junoswap_pool: String, - - /// Can be deposited in any pool created by this factory - pub factory: String, - /// If set, only can be deposited in this pool (which must also be created by the factory) - pub palomadex_pool: Option, -} - -#[cw_serde] -pub enum ExecuteMsg { - /// Migrate tokens to this pool. - /// This moves the LP tokens to this contract, which are later given to the stakers in `MigrateStakers`. - /// Must be called by migrator. - /// Target pool must match constraints above - MigrateTokens { palomadex_pool: String }, - - /// Give the next `limit` stakers their LP tokens. - /// Must be called by migrator. - MigrateStakers { limit: u32 }, -} diff --git a/contracts/junoswap-staking/src/multitest.rs b/contracts/junoswap-staking/src/multitest.rs deleted file mode 100644 index c5348f3..0000000 --- a/contracts/junoswap-staking/src/multitest.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod migration; -mod suite; diff --git a/contracts/junoswap-staking/src/multitest/migration.rs b/contracts/junoswap-staking/src/multitest/migration.rs deleted file mode 100644 index 106ca51..0000000 --- a/contracts/junoswap-staking/src/multitest/migration.rs +++ /dev/null @@ -1,658 +0,0 @@ -use crate::{multitest::suite::PoolDenom, ContractError}; - -use super::suite::SuiteBuilder; - -use wasmswap_cw20::Denom; - -use cosmwasm_std::{assert_approx_eq, coin, Addr, Coin, Decimal, Uint128}; - -#[test] -fn testsuite_instantiation() { - let ujuno = "ujuno"; - let uluna = "uluna"; - let user = "user"; - - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Native(ujuno.to_owned()), - PoolDenom::Native(uluna.to_owned()), - ) - .build(); - - suite - .provide_liquidity_to_junoswap_pool( - user, - 1_000_000u128, - 1_000_000u128, - None, - None, - vec![coin(1_000_000, "ujuno"), coin(1_000_000, "uluna")], - ) - .unwrap(); - - // stake some of these tokens - let lp = suite.junoswap_lp(user, None).unwrap(); - assert_eq!(lp.u128(), 1_000_000u128); - let to_stake = lp * Decimal::percent(30); - suite.stake_junoswap_lp(user, to_stake, None, None).unwrap(); - let new_lp = suite.junoswap_lp(user, None).unwrap(); - assert_eq!(new_lp, lp - to_stake); -} - -#[test] -fn partial_migration() { - let ujuno = "ujuno"; - let uluna = "uluna"; - let users = (0..10).map(|i| format!("user{}", i)).collect::>(); - - let suite = SuiteBuilder::new().with_denoms( - PoolDenom::Native(ujuno.to_owned()), - PoolDenom::Native(uluna.to_owned()), - ); - let mut suite = suite.build(); - - for (i, user) in users.iter().enumerate() { - // Provide (roughly) 1m of each asset - suite - .provide_liquidity_to_junoswap_pool( - user, - 1_000_000u128, - 1_000_000 + i as u128, - None, - None, - vec![coin(1_000_000, ujuno), coin(1_000_000 + i as u128, uluna)], - ) - .unwrap(); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite.stake_junoswap_lp(user, to_stake, None, None).unwrap(); - } - - // migrate the tokens - suite - .migrate_tokens_with_self_upgrade(None, None, None) - .unwrap(); - - assert!( - !suite.migration_finished().unwrap(), - "stakers not migrated yet" - ); - - suite.migrate_stakers(5).unwrap(); - - // only 5 stakers should have tokens now - let lp_tokens: Vec<_> = users - .iter() - .map(|u| suite.palomadex_staked(u, suite.migration_unbonding_period())) - .filter(|lp| *lp > 0) - .collect(); - assert_eq!(lp_tokens.len(), 5); - assert!(lp_tokens.iter().all(|lp| *lp == 799900)); - - assert!(!suite.migration_finished().unwrap(), "still stakers left"); - - suite.migrate_stakers(5).unwrap(); - - // next 5 stakers should also have tokens now - let lp_tokens: Vec<_> = users - .iter() - .map(|u| suite.palomadex_staked(u, suite.migration_unbonding_period())) - .filter(|lp| *lp > 0) - .collect(); - assert_eq!(lp_tokens.len(), 10); - assert!(lp_tokens.iter().all(|lp| *lp == 799900)); - - assert!(suite.migration_finished().unwrap(), "all stakers migrated"); -} - -#[test] -fn migration_sanity_check() { - // This just does a basic migration of one staked user with no claims - let ujuno = "ujuno"; - let uluna = "uluna"; - let user = "user"; - let liquidity = vec![coin(1_000_000, ujuno), coin(1_000_000, uluna)]; - - let mut suite = setup_basic_suite(ujuno, uluna, user, liquidity.clone()); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite.stake_junoswap_lp(user, to_stake, None, None).unwrap(); - - // make sure no lp before the deposit - let palomadex_total = suite.total_palomadex_lp(); - assert_eq!(palomadex_total, 0u128); - - // cross our fingers this works ;) - suite.migrate_to_palomadex(None, None, None).unwrap(); - - // 80% of liquidity moved to palomadex pool - let palomadex = suite - .app - .wrap() - .query_all_balances(&suite.palomadex_pair_contract) - .unwrap(); - let expected = liquidity - .iter() - .map(|Coin { amount, denom }| coin(amount.u128() * 4 / 5, denom)) - .collect::>(); - assert_eq!(palomadex, expected); - - // 20% of liquidity still in junoswap - let junoswap = suite - .app - .wrap() - .query_all_balances(&suite.junoswap_pool_contract) - .unwrap(); - let expected = liquidity - .iter() - .map(|Coin { amount, denom }| coin(amount.u128() / 5, denom)) - .collect::>(); - assert_eq!(junoswap, expected); - - // ensure all lp belong to the staking contract - // except for the MINIMUM_LIQUIDITY_DEPOSIT - held by pool - // https://github.com/cosmorama/wyndex-priv/blob/d39f7369d22d458a85c6828d151bc3844a1604bf/contracts/pair/src/contract.rs#L381-L395 - let palomadex_total = suite.total_palomadex_lp(); - let palomadex_staked = suite.total_palomadex_staked(); - let pool = suite.palomadex_pair_contract.to_string(); - let pool_own_lp = suite.palomadex_lp(&pool); - assert_eq!(palomadex_total, palomadex_staked + pool_own_lp); - assert_eq!( - pool_own_lp, - palomadex::asset::MINIMUM_LIQUIDITY_AMOUNT.u128() - ); - - // ensure all staked tokens belong to the migrated user - let user_staked = suite.palomadex_staked(user, suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked); -} - -#[test] -fn non_migrator_cant_migrate() { - let ujuno = "ujuno"; - let uluna = "uluna"; - let user = "user"; - let liquidity = vec![coin(1_000_000, ujuno), coin(1_000_000, uluna)]; - - let mut suite = setup_basic_suite(ujuno, uluna, user, liquidity); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite.stake_junoswap_lp(user, to_stake, None, None).unwrap(); - - // this won't work, not the migrator - let err = suite - .migrate_to_palomadex(Some(Addr::unchecked("notthemigrator")), None, None) - .unwrap_err(); - assert_eq!(ContractError::Unauthorized {}, err.downcast().unwrap()) -} -#[test] -fn migrator_cant_migrate_to_own_addr() { - let ujuno = "ujuno"; - let uluna = "uluna"; - let user = "user"; - let liquidity = vec![coin(1_000_000, ujuno), coin(1_000_000, uluna)]; - - let mut suite = setup_basic_suite(ujuno, uluna, user, liquidity); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite.stake_junoswap_lp(user, to_stake, None, None).unwrap(); - - // this won't work, we can only migrate to a deployed pool contract. - let err = suite - .migrate_to_palomadex( - Some(Addr::unchecked("owner")), - Some(suite.palomadex_pair_contract.clone()), - Some(Addr::unchecked("owner")), - ) - .unwrap_err(); - - assert_eq!( - ContractError::InvalidDestination("owner".to_string()), - err.downcast().unwrap() - ); -} - -fn setup_basic_suite( - ujuno: &str, - uluna: &str, - user: &str, - liquidity: Vec, -) -> super::suite::Suite { - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Native(ujuno.to_owned()), - PoolDenom::Native(uluna.to_owned()), - ) - .build(); - suite - .provide_liquidity_to_junoswap_pool( - user, - 1_000_000u128, - 1_000_000u128, - None, - None, - liquidity.clone(), - ) - .unwrap(); - // check balances of pool - let junoswap = suite - .app - .wrap() - .query_all_balances(&suite.junoswap_pool_contract) - .unwrap(); - assert_eq!(junoswap, liquidity); - suite -} - -#[test] -fn migration_multiple_users() { - let ujuno = "ujuno"; - let uluna = "uluna"; - let users = ["user", "user2", "user3"]; - // Setup Pools with initial liquidity - let liquidity = vec![coin(5_000_000, ujuno), coin(5_000_003, uluna)]; - - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Native(ujuno.to_owned()), - PoolDenom::Native(uluna.to_owned()), - ) - .build(); - // First user to provide 1.5m of each asset - suite - .provide_liquidity_to_junoswap_pool( - users[0], - 1_500_000u128, - 1_500_000u128, - None, - None, - vec![coin(1_500_000, ujuno), coin(1_500_000, uluna)], - ) - .unwrap(); - - // Need more coins this time on asset 2, because of this: https://github.com/Wasmswap/wasmswap-contracts/blob/cbca1f2bd8088b2ac6784c47a4509227a227c755/src/contract.rs#L278 - suite - .provide_liquidity_to_junoswap_pool( - users[1], - 500_000u128, - 500_001u128, - None, - None, - vec![coin(500_000, ujuno), coin(500_001, uluna)], - ) - .unwrap(); - - suite - .provide_liquidity_to_junoswap_pool( - users[2], - 3_000_000u128, - 3_000_002u128, - None, - None, - vec![coin(3_000_000, ujuno), coin(3_000_002, uluna)], - ) - .unwrap(); - - // check balances of pool - let junoswap = suite - .app - .wrap() - .query_all_balances(&suite.junoswap_pool_contract) - .unwrap(); - assert_eq!(junoswap, liquidity); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(users[0], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp(users[0], to_stake, None, None) - .unwrap(); - let to_stake = suite.junoswap_lp(users[1], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp(users[1], to_stake, None, None) - .unwrap(); - let to_stake = suite.junoswap_lp(users[2], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp(users[2], to_stake, None, None) - .unwrap(); - - // perform the migration of liquidity - suite.migrate_to_palomadex(None, None, None).unwrap(); - - // 80% of liquidity moved to palomadex pool - let palomadex = suite - .app - .wrap() - .query_all_balances(&suite.palomadex_pair_contract) - .unwrap(); - let expected = liquidity - .iter() - .map(|Coin { amount, denom }| coin(amount.u128() * 4 / 5, denom)) - .collect::>(); - assert_eq!(palomadex, expected); - - // ensure all lp belong to the staking contract - let palomadex_total = suite.total_palomadex_lp(); - let palomadex_staked = suite.total_palomadex_staked(); - assert_approx_eq!(palomadex_total, palomadex_staked, "0.01"); - // ensure all staked tokens belong to the migrated user - let user_staked = suite.palomadex_staked(users[0], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 10 * 3); - // user 2 staked 500k so they should have about 10% of the staked tokens - let user_staked = suite.palomadex_staked(users[1], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 10,); - // user 3 did 3m and should have 60% - let user_staked = suite.palomadex_staked(users[2], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 10 * 6); -} - -#[test] -fn migrate_with_mixed_pairs() { - let ujuno = "ujuno"; - let uraw = "rawtoken"; - let users = ["user", "user2", "user3"]; - // Setup Pools with initial liquidity - let liquidity = vec![coin(3_000_000, ujuno)]; - let liquidity_cw20 = 3_000_002u128; - - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Native(ujuno.to_owned()), - PoolDenom::Cw20(uraw.to_owned()), - ) - .build(); - - let raw_denom = suite.pool_denom2.clone(); - let raw_address = match &raw_denom { - Denom::Cw20(address) => address, - _ => panic!("expected cw20 denom"), - }; - - // Provide Liquidity to the CW20 Native pair - // Note: Second deposits need 1 extra cw20 similar to the above rounding errors - suite - .provide_liquidity_to_junoswap_pool( - users[0], - 1_000_000u128, - 1_000_000u128, - Some(Denom::Native(ujuno.to_owned())), - Some(raw_denom.clone()), - vec![coin(1_000_000, ujuno)], - ) - .unwrap(); - - suite - .provide_liquidity_to_junoswap_pool( - users[1], - 1_000_000u128, - 1_000_001u128, - Some(Denom::Native(ujuno.to_owned())), - Some(raw_denom.clone()), - vec![coin(1_000_000, ujuno)], - ) - .unwrap(); - suite - .provide_liquidity_to_junoswap_pool( - users[2], - 1_000_000u128, - 1_000_001u128, - Some(Denom::Native(ujuno.to_owned())), - Some(raw_denom.clone()), - vec![coin(1_000_000, ujuno)], - ) - .unwrap(); - - // check balances of pool - let junoswap = suite - .app - .wrap() - .query_all_balances(&suite.junoswap_pool_contract) - .unwrap(); - assert_eq!(junoswap, liquidity); - let junoswap = cw20::Cw20Contract(raw_address.clone()) - .balance(&suite.app.wrap(), suite.junoswap_pool_contract.clone()) - .unwrap(); - assert_eq!(junoswap.u128(), liquidity_cw20); - - suite.palomadex_lp_holders(); - - // stake some of these tokens - 80% of liquidity should be moved - // users[0] will keep everything staked - let to_stake = suite.junoswap_lp(users[0], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp( - users[0], - to_stake, - None, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - // users[1] will unstake half - let to_stake = suite.junoswap_lp(users[1], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp( - users[1], - to_stake, - None, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - suite - .unstake_junoswap_lp( - users[1], - to_stake / Uint128::new(2), - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - // users[2] will unstake all - let to_stake = suite.junoswap_lp(users[2], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp( - users[2], - to_stake, - None, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - suite - .unstake_junoswap_lp( - users[2], - to_stake, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - - // perform the migration of liquidity - suite.migrate_to_palomadex(None, None, None).unwrap(); - - // 80% of native liquidity moved to palomadex pool - let palomadex = suite - .app - .wrap() - .query_all_balances(&suite.palomadex_pair_contract) - .unwrap(); - let expected = liquidity - .iter() - .map(|Coin { amount, denom }| coin(amount.u128() * 4 / 5, denom)) - .collect::>(); - assert_eq!(palomadex, expected); - - // 80% of cw20 liquidity moved to palomadex pool - let palomadex = cw20::Cw20Contract(raw_address.clone()) - .balance(&suite.app.wrap(), suite.palomadex_pair_contract.clone()) - .unwrap(); - let expected = liquidity_cw20 * 4 / 5; - assert_eq!(palomadex.u128(), expected); - - // ensure all lp belong to the staking contract - let palomadex_total = suite.total_palomadex_lp(); - let palomadex_staked = suite.total_palomadex_staked(); - assert_approx_eq!(palomadex_total, palomadex_staked, "0.001"); - // ensure all staked tokens belong to the migrated user - let user_staked = suite.palomadex_staked(users[0], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 3); - // user 2 staked 500k so they should have about 10% of the staked tokens - let user_staked = suite.palomadex_staked(users[1], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 3); - // user 3 did 3m and should have 60% - let user_staked = suite.palomadex_staked(users[2], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 3); -} - -#[test] -fn migrate_with_unbonding_claims() { - let ujuno = "ujuno"; - let uluna = "uluna"; - let user = "user"; - let liquidity = vec![coin(1_000_000, ujuno), coin(1_000_000, uluna)]; - - let mut suite = setup_basic_suite(ujuno, uluna, user, liquidity.clone()); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite.stake_junoswap_lp(user, to_stake, None, None).unwrap(); - - // Process an unstake request to generate a claim - suite - .unstake_junoswap_lp(user, 800_000u128.into(), None) - .unwrap(); - assert_eq!( - suite - .query_stake_claims_for_pair(user.to_string()) - .claims - .len(), - 1 - ); - - // make sure no lp before the deposit - let palomadex_total = suite.total_palomadex_lp(); - assert_eq!(palomadex_total, 0u128); - - // Migrate the liquidity to Palomadex, the liquidity includes 1 pair with 1 user who is currently unstaking - suite.migrate_to_palomadex(None, None, None).unwrap(); - - // 80% of liquidity moved to palomadex pool - let palomadex = suite - .app - .wrap() - .query_all_balances(&suite.palomadex_pair_contract) - .unwrap(); - let expected = liquidity - .iter() - .map(|Coin { amount, denom }| coin(amount.u128() * 4 / 5, denom)) - .collect::>(); - assert_eq!(palomadex, expected); - - // 20% of liquidity still in junoswap - let junoswap = suite - .app - .wrap() - .query_all_balances(&suite.junoswap_pool_contract) - .unwrap(); - let expected = liquidity - .iter() - .map(|Coin { amount, denom }| coin(amount.u128() / 5, denom)) - .collect::>(); - assert_eq!(junoswap, expected); - - // ensure all lp belong to the staking contract - // except for the MINIMUM_LIQUIDITY_DEPOSIT - held by pool - // https://github.com/cosmorama/wyndex-priv/blob/d39f7369d22d458a85c6828d151bc3844a1604bf/contracts/pair/src/contract.rs#L381-L395 - let palomadex_total = suite.total_palomadex_lp(); - let palomadex_staked = suite.total_palomadex_staked(); - let pool = suite.palomadex_pair_contract.to_string(); - let pool_own_lp = suite.palomadex_lp(&pool); - assert_eq!(palomadex_total, palomadex_staked + pool_own_lp); - assert_eq!( - pool_own_lp, - palomadex::asset::MINIMUM_LIQUIDITY_AMOUNT.u128() - ); - - // ensure all staked tokens belong to the migrated user - let user_staked = suite.palomadex_staked(user, suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked); -} - -#[test] -fn migration_two_cw20() { - let user = "user"; - let liquidity = 2_000_000u128; - - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Cw20("raw".to_owned()), - PoolDenom::Cw20("cwt".to_owned()), - ) - .build(); - - let raw_denom = suite.pool_denom1.clone(); - let raw_address = match &raw_denom { - Denom::Cw20(address) => address, - _ => panic!("expected cw20 denom"), - }; - let cw20_denom = suite.pool_denom2.clone(); - let cw20_address = match &cw20_denom { - Denom::Cw20(address) => address, - _ => panic!("expected cw20 denom"), - }; - - // Provide Liquidity to the CW20 pair - suite - .provide_liquidity_to_junoswap_pool( - user, - 2_000_000u128, - 2_000_000u128, - Some(cw20_denom.clone()), - Some(raw_denom.clone()), - vec![], - ) - .unwrap(); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp( - user, - to_stake, - None, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - - // make sure no lp before the deposit - let palomadex_total = suite.total_palomadex_lp(); - assert_eq!(palomadex_total, 0u128); - - // cross our fingers this works ;) - suite.migrate_to_palomadex(None, None, None).unwrap(); - - // 80% of liquidity moved to palomadex pool - let palomadex = cw20::Cw20Contract(raw_address.clone()) - .balance(&suite.app.wrap(), suite.palomadex_pair_contract.clone()) - .unwrap(); - let expected = liquidity * 4 / 5; - assert_eq!(palomadex.u128(), expected); - let palomadex = cw20::Cw20Contract(cw20_address.clone()) - .balance(&suite.app.wrap(), suite.palomadex_pair_contract.clone()) - .unwrap(); - let expected = liquidity * 4 / 5; - assert_eq!(palomadex.u128(), expected); - - // ensure all lp belong to the staking contract - let palomadex_total = suite.total_palomadex_lp(); - let palomadex_staked = suite.total_palomadex_staked(); - let pool = suite.palomadex_pair_contract.to_string(); - let pool_own_lp = suite.palomadex_lp(&pool); - assert_eq!(palomadex_total, palomadex_staked + pool_own_lp); - assert_eq!( - pool_own_lp, - palomadex::asset::MINIMUM_LIQUIDITY_AMOUNT.u128() - ); - - // ensure all staked tokens belong to the migrated user - let user_staked = suite.palomadex_staked(user, suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked); -} diff --git a/contracts/junoswap-staking/src/multitest/suite.rs b/contracts/junoswap-staking/src/multitest/suite.rs deleted file mode 100644 index 6438cbb..0000000 --- a/contracts/junoswap-staking/src/multitest/suite.rs +++ /dev/null @@ -1,753 +0,0 @@ -use anyhow::Result as AnyResult; - -use cw20::MinterResponse; -use palomadex::asset::AssetInfo; -use palomadex::factory::{ - DefaultStakeConfig, ExecuteMsg as FactoryExecuteMsg, InstantiateMsg as FactoryInstantiateMsg, - PairConfig, PairType, PartialStakeConfig, QueryMsg as FactoryQueryMsg, -}; -use palomadex::fee_config::FeeConfig; -use palomadex::pair::PairInfo; - -use crate::msg::{MigrateMsg, OrigMigrateMsg, QueryMsg}; -use cosmwasm_std::{coin, to_binary, Addr, Coin, Decimal, Uint128}; -use cw20_base::msg::InstantiateMsg as Cw20BaseInstantiateMsg; -use cw_multi_test::{next_block, App, AppResponse, BankSudo, ContractWrapper, Executor, SudoMsg}; -use stake_cw20::msg::{ClaimsResponse, InstantiateMsg as StakeCw20IntantiateMsg}; -use wasmswap::msg::{ - ExecuteMsg as WasmswapExecuteMsg, InfoResponse, InstantiateMsg as WasmswapInstantiateMsg, - QueryMsg as WasmswapQueryMsg, -}; -use wasmswap_cw20::{Cw20ExecuteMsg, Denom}; -use wasmswap_cw_utils::Duration; - -pub const ONE_DAY: u64 = 86_400; - -pub fn store_stake_cw20(app: &mut App) -> u64 { - let contract = Box::new(ContractWrapper::new( - stake_cw20::contract::execute, - stake_cw20::contract::instantiate, - stake_cw20::contract::query, - )); - app.store_code(contract) -} - -pub fn store_junoswap_pool(app: &mut App) -> u64 { - let contract = Box::new( - ContractWrapper::new( - wasmswap::contract::execute, - wasmswap::contract::instantiate, - wasmswap::contract::query, - ) - .with_reply_empty(wasmswap::contract::reply), - ); - app.store_code(contract) -} - -pub fn store_cw20(app: &mut App) -> u64 { - let contract = Box::new(ContractWrapper::new( - wasmswap_cw20_base::contract::execute, - wasmswap_cw20_base::contract::instantiate, - wasmswap_cw20_base::contract::query, - )); - app.store_code(contract) -} - -pub fn store_palomadex_staking(app: &mut App) -> u64 { - let contract = Box::new(ContractWrapper::new( - palomadex_stake::contract::execute, - palomadex_stake::contract::instantiate, - palomadex_stake::contract::query, - )); - app.store_code(contract) -} - -fn store_palomadex_factory(app: &mut App) -> u64 { - let factory_contract = Box::new( - ContractWrapper::new_with_empty( - palomadex_factory::contract::execute, - palomadex_factory::contract::instantiate, - palomadex_factory::contract::query, - ) - .with_reply_empty(palomadex_factory::contract::reply), - ); - - app.store_code(factory_contract) -} - -fn store_palomadex_pair(app: &mut App) -> u64 { - let factory_contract = Box::new( - ContractWrapper::new_with_empty( - palomadex_pair::contract::execute, - palomadex_pair::contract::instantiate, - palomadex_pair::contract::query, - ) - .with_reply_empty(palomadex_pair::contract::reply), - ); - - app.store_code(factory_contract) -} - -pub fn store_migrator(app: &mut App) -> u64 { - let contract = Box::new( - ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply), - ); - app.store_code(contract) -} - -/// Helper to be able to specify a non-existing cw20 token -#[derive(Debug, Clone)] -pub enum PoolDenom { - Native(String), - /// The string is not the contract address, but the symbol / name of the token. - /// A new token will be instantiated using this name. - Cw20(String), -} - -impl PoolDenom { - pub fn into_denom( - self, - app: &mut App, - owner: impl Into + Clone, - cw20_code_id: u64, - ) -> Denom { - match self { - PoolDenom::Native(denom) => Denom::Native(denom), - PoolDenom::Cw20(symbol) => { - // create cw20 token - let cw20_token = app - .instantiate_contract( - cw20_code_id, - Addr::unchecked(owner.clone()), - &Cw20BaseInstantiateMsg { - name: symbol.clone(), - symbol: symbol.clone(), - decimals: 6, - initial_balances: vec![], - mint: Some(MinterResponse { - minter: owner.into(), - cap: None, - }), - marketing: None, - }, - &[], - symbol, - None, - ) - .unwrap(); - Denom::Cw20(cw20_token) - } - } - } -} - -#[derive(Debug)] -pub struct SuiteBuilder { - funds: Vec<(Addr, Vec)>, - unbonding_periods: Vec, - pool_denom1: PoolDenom, - pool_denom2: PoolDenom, -} - -impl SuiteBuilder { - pub fn new() -> SuiteBuilder { - SuiteBuilder { - unbonding_periods: vec![100, 200, 300], - pool_denom1: PoolDenom::Native("ujuno".to_string()), - pool_denom2: PoolDenom::Native("uluna".to_string()), - funds: vec![], - } - } - - /// Specify the pool denoms. For cw20 denoms, the - pub fn with_denoms(mut self, denom1: PoolDenom, denom2: PoolDenom) -> Self { - self.pool_denom1 = denom1; - self.pool_denom2 = denom2; - self - } - - #[track_caller] - pub fn build(self) -> Suite { - let mut app = App::default(); - let owner = Addr::unchecked("owner"); - - let cw20_code_id = store_cw20(&mut app); - - let pool_denom1 = self - .pool_denom1 - .into_denom(&mut app, owner.clone(), cw20_code_id); - let pool_denom2 = self - .pool_denom2 - .into_denom(&mut app, owner.clone(), cw20_code_id); - - // Instantiate junoswap pool - let junoswap_pool_code_id = store_junoswap_pool(&mut app); - let junoswap_pool_contract = app - .instantiate_contract( - junoswap_pool_code_id, - owner.clone(), - &WasmswapInstantiateMsg { - token1_denom: pool_denom1.clone(), - token2_denom: pool_denom2.clone(), - lp_token_code_id: cw20_code_id, - owner: Some(owner.to_string()), - lp_fee_percent: Decimal::zero(), - protocol_fee_percent: Decimal::zero(), - protocol_fee_recipient: owner.to_string(), - }, - &[], - "wasmswap-pool", - Some(owner.to_string()), - ) - .unwrap(); - app.update_block(next_block); - - // Check address of created token contract - let junoswap_token_contract = Addr::unchecked( - app.wrap() - .query_wasm_smart::( - &junoswap_pool_contract, - &WasmswapQueryMsg::Info {}, - ) - .unwrap() - .lp_token_address, - ); - - // Instantiate junoswap staking contract - let junoswap_staking_code_id = store_stake_cw20(&mut app); - let junoswap_staking_contract = app - .instantiate_contract( - junoswap_staking_code_id, - owner.clone(), - &StakeCw20IntantiateMsg { - owner: Some(owner.to_string()), - manager: Some("manager".to_string()), - token_address: junoswap_token_contract.to_string(), - unstaking_duration: Some(Duration::Time(ONE_DAY * 14)), - }, - &[], - "staking", - Some(owner.to_string()), - ) - .unwrap(); - app.update_block(next_block); - - // Instantiate palomadex factory - let palomadex_stake_code_id = store_palomadex_staking(&mut app); - let palomadex_pair_code_id = store_palomadex_pair(&mut app); - let palomadex_factory_code_id = store_palomadex_factory(&mut app); - let factory_contract = app - .instantiate_contract( - palomadex_factory_code_id, - owner.clone(), - &FactoryInstantiateMsg { - pair_configs: vec![PairConfig { - pair_type: PairType::Xyk {}, - code_id: palomadex_pair_code_id, - fee_config: FeeConfig { - total_fee_bps: 0, - protocol_fee_bps: 0, - }, - is_disabled: false, - }], - token_code_id: cw20_code_id, - fee_address: Some(owner.to_string()), - owner: owner.to_string(), - max_referral_commission: Decimal::one(), - default_stake_config: DefaultStakeConfig { - staking_code_id: palomadex_stake_code_id, - tokens_per_power: Uint128::new(1000), - min_bond: Uint128::new(1000), - unbonding_periods: self.unbonding_periods.clone(), - max_distributions: 6, - converter: None, - }, - trading_starts: None, - }, - &[], - "palomadex-factory", - Some(owner.to_string()), - ) - .unwrap(); - - // Wasmswap is using older version of cw20, so specific From impl - // would have to be created - IMO not worth it - let asset_infos = vec![ - match pool_denom1.clone() { - Denom::Native(s) => AssetInfo::Native(s), - Denom::Cw20(s) => AssetInfo::Token(s.to_string()), - }, - match pool_denom2.clone() { - Denom::Native(s) => AssetInfo::Native(s), - Denom::Cw20(s) => AssetInfo::Token(s.to_string()), - }, - ]; - - // Instantiate palomadex pair contract through factory - app.execute_contract( - owner.clone(), - factory_contract.clone(), - &FactoryExecuteMsg::CreatePair { - pair_type: PairType::Xyk {}, - asset_infos: asset_infos.clone(), - init_params: None, - total_fee_bps: None, - // accept defaults, but ensure there is a staking contract - staking_config: PartialStakeConfig { - staking_code_id: None, - tokens_per_power: None, - min_bond: None, - unbonding_periods: None, - max_distributions: None, - converter: None, - }, - }, - &[], - ) - .unwrap(); - let pair_info = app - .wrap() - .query_wasm_smart::( - Addr::unchecked(&factory_contract), - &FactoryQueryMsg::Pair { asset_infos }, - ) - .unwrap(); - - let palomadex_pair_contract = pair_info.contract_addr; - let palomadex_staking_contract = pair_info.staking_addr; - let palomadex_token_contract = pair_info.liquidity_token; - - // add funds to the contract - let funds = self.funds; - app.init_modules(|router, _, storage| -> AnyResult<()> { - for (addr, coin) in funds { - router.bank.init_balance(storage, &addr, coin)?; - } - Ok(()) - }) - .unwrap(); - - let migrator_code_id = store_migrator(&mut app); - - Suite { - owner, - app, - junoswap_token_contract, - junoswap_pool_contract, - junoswap_staking_contract, - factory_contract, - palomadex_pair_contract, - palomadex_staking_contract, - palomadex_token_contract, - migrator_code_id, - cw20_code_id, - pool_denom1, - pool_denom2, - unbonding_periods: self.unbonding_periods, - } - } -} - -pub struct Suite { - pub owner: Addr, - pub app: App, - pub migrator_code_id: u64, - pub cw20_code_id: u64, - pub unbonding_periods: Vec, - - pub junoswap_token_contract: Addr, - pub junoswap_pool_contract: Addr, - pub junoswap_staking_contract: Addr, - pub palomadex_token_contract: Addr, - pub palomadex_staking_contract: Addr, - pub palomadex_pair_contract: Addr, - pub pool_denom1: Denom, - pub pool_denom2: Denom, - - pub factory_contract: Addr, -} - -#[derive(Debug)] -#[allow(dead_code)] -struct SuiteInfo<'a> { - pub junoswap_token_contract: &'a Addr, - pub junoswap_pool_contract: &'a Addr, - pub junoswap_staking_contract: &'a Addr, - pub factory_contract: &'a Addr, - pub palomadex_token_contract: &'a Addr, - pub palomadex_staking_contract: &'a Addr, - pub palomadex_pair_contract: &'a Addr, -} - -impl Suite { - // for debugging tests - #[allow(dead_code)] - pub fn info(&self) { - let info = SuiteInfo { - junoswap_token_contract: &self.junoswap_token_contract, - junoswap_pool_contract: &self.junoswap_pool_contract, - junoswap_staking_contract: &self.junoswap_staking_contract, - factory_contract: &self.factory_contract, - palomadex_token_contract: &self.palomadex_token_contract, - palomadex_staking_contract: &self.palomadex_staking_contract, - palomadex_pair_contract: &self.palomadex_pair_contract, - }; - println!("{:?}", info); - } - - pub fn migration_unbonding_period(&self) -> u64 { - self.unbonding_periods[1] - } - - /// Returns true if migration is finished - /// Only makes sense to call after the junoswap staking contract has been migrated - pub fn migration_finished(&self) -> AnyResult { - self.app - .wrap() - .query_wasm_smart( - self.junoswap_staking_contract.clone(), - &QueryMsg::MigrationFinished {}, - ) - .map_err(Into::into) - } - - // Like `migrate_tokens`, but after the first migration (from junoswap), - // it migrates to a newer version of this contract - pub fn migrate_tokens_with_self_upgrade( - &mut self, - migrator: Option, - palomadex_pair_migrate: Option, - palomadex_pair: Option, - ) -> AnyResult { - // first set up the migration - self.app.migrate_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &MigrateMsg { - init: Some(OrigMigrateMsg { - migrator: migrator.unwrap_or_else(|| self.owner.clone()).to_string(), - unbonding_period: self.migration_unbonding_period(), - junoswap_pool: self.junoswap_pool_contract.to_string(), - factory: self.factory_contract.to_string(), - palomadex_pool: palomadex_pair_migrate.map(|p| p.to_string()), - }), - }, - self.migrator_code_id, - )?; - - // then migrate again (self-migrate) - self.app.migrate_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &MigrateMsg { init: None }, - self.migrator_code_id, - )?; - - // then trigger the actual migration - self.app.execute_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &crate::msg::ExecuteMsg::MigrateTokens { - palomadex_pool: palomadex_pair - .unwrap_or_else(|| self.palomadex_pair_contract.clone()) - .to_string(), - }, - &[], - ) - } - - /// Migrates the junoswap staking contract to our migration contract and migrates the tokens - pub fn migrate_tokens( - &mut self, - migrator: Option, - palomadex_pair_migrate: Option, - palomadex_pair: Option, - ) -> AnyResult { - // first set up the migration - self.app.migrate_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &MigrateMsg { - init: Some(OrigMigrateMsg { - migrator: migrator.unwrap_or_else(|| self.owner.clone()).to_string(), - unbonding_period: self.migration_unbonding_period(), - junoswap_pool: self.junoswap_pool_contract.to_string(), - factory: self.factory_contract.to_string(), - palomadex_pool: palomadex_pair_migrate.map(|p| p.to_string()), - }), - }, - self.migrator_code_id, - )?; - - // then trigger the actual migration - self.app.execute_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &crate::msg::ExecuteMsg::MigrateTokens { - palomadex_pool: palomadex_pair - .unwrap_or_else(|| self.palomadex_pair_contract.clone()) - .to_string(), - }, - &[], - ) - } - - /// Migrates the next `limit` staker's LP tokens. - /// Only makes sense to call after the junoswap staking contract has been migrated. - pub fn migrate_stakers(&mut self, limit: u32) -> AnyResult { - self.app.execute_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &crate::msg::ExecuteMsg::MigrateStakers { limit }, - &[], - ) - } - - pub fn migrate_to_palomadex( - &mut self, - migrator: Option, - palomadex_pair_migrate: Option, - palomadex_pair: Option, - ) -> AnyResult<()> { - self.migrate_tokens(migrator, palomadex_pair_migrate, palomadex_pair)?; - - // now migrate all the stakers - while !self.migration_finished()? { - self.migrate_stakers(10)?; - } - - Ok(()) - } - - fn increase_allowance( - &mut self, - owner: &str, - contract: &Addr, - spender: &str, - amount: u128, - ) -> AnyResult { - self.app.execute_contract( - Addr::unchecked(owner), - contract.clone(), - &Cw20ExecuteMsg::IncreaseAllowance { - spender: spender.to_owned(), - amount: amount.into(), - expires: None, - }, - &[], - ) - } - - pub fn mint_cw20( - &mut self, - owner: &str, - token: &Addr, - amount: u128, - recipient: &str, - ) -> AnyResult { - self.app.execute_contract( - Addr::unchecked(owner), - token.clone(), - &Cw20ExecuteMsg::Mint { - recipient: recipient.to_owned(), - amount: amount.into(), - }, - &[], - ) - } - - pub fn junoswap_lp(&mut self, user: &str, lp_contract: Option<&Addr>) -> AnyResult { - let query = cw20::Cw20QueryMsg::Balance { - address: user.to_string(), - }; - println!("querying junoswap lp: {:?}", lp_contract); - let cw20::BalanceResponse { balance } = self - .app - .wrap() - .query_wasm_smart(lp_contract.unwrap_or(&self.junoswap_token_contract), &query)?; - Ok(balance) - } - - /// Requirement: if using native token provide coins to sent as last argument - #[allow(clippy::too_many_arguments)] - pub fn provide_liquidity_to_junoswap_pool( - &mut self, - user: &str, - first_asset: u128, - second_asset: u128, - first_denom: Option, - second_denom: Option, - native_tokens: Vec, - ) -> AnyResult { - let owner = self.owner.to_string(); - - let assets = vec![ - ( - first_denom.unwrap_or_else(|| self.pool_denom1.clone()), - first_asset, - ), - ( - second_denom.unwrap_or_else(|| self.pool_denom2.clone()), - second_asset, - ), - ]; - for (denom, amount) in assets { - match denom { - Denom::Cw20(addr) => { - // Mint some initial balances for whale user - self.mint_cw20(&owner, &addr, amount, user).unwrap(); - // Increases allowances for given LP contracts in order to provide liquidity to pool - let spender = self.junoswap_pool_contract.to_string(); - self.increase_allowance(user, &addr, &spender, amount) - .unwrap(); - } - Denom::Native(denom) => { - self.app - .sudo(SudoMsg::Bank(BankSudo::Mint { - to_address: user.to_owned(), - amount: vec![coin(amount, denom)], - })) - .unwrap(); - } - } - } - - self.app.execute_contract( - Addr::unchecked(user), - self.junoswap_pool_contract.clone(), - &WasmswapExecuteMsg::AddLiquidity { - token1_amount: first_asset.into(), - min_liquidity: Uint128::new(100), - max_token2: second_asset.into(), - expiration: None, - }, - &native_tokens, - ) - } - - pub fn stake_junoswap_lp( - &mut self, - user: &str, - amount: Uint128, - lp_contract: Option<&Addr>, - staking_contract: Option<&Addr>, - ) -> AnyResult { - let msg = to_binary(&stake_cw20::msg::ReceiveMsg::Stake {})?; - self.app.execute_contract( - Addr::unchecked(user), - lp_contract - .unwrap_or(&self.junoswap_token_contract.clone()) - .to_owned(), - &cw20::Cw20ExecuteMsg::Send { - contract: staking_contract - .unwrap_or(&self.junoswap_staking_contract.clone()) - .to_string(), - amount, - msg, - }, - &[], - ) - } - - pub fn unstake_junoswap_lp( - &mut self, - user: &str, - amount: Uint128, - staking_contract: Option<&Addr>, - ) -> AnyResult { - self.app.execute_contract( - Addr::unchecked(user), - staking_contract - .unwrap_or(&self.junoswap_staking_contract) - .clone(), - &stake_cw20::msg::ExecuteMsg::Unstake { amount }, - &[], - ) - } - - pub fn query_stake_claims_for_pair(&mut self, address: String) -> ClaimsResponse { - let resp: ClaimsResponse = self - .app - .wrap() - .query_wasm_smart( - &self.junoswap_staking_contract, - &stake_cw20::msg::QueryMsg::Claims { address }, - ) - .unwrap(); - resp - } - - pub fn total_palomadex_lp(&mut self) -> u128 { - let cw20::TokenInfoResponse { total_supply, .. } = self - .app - .wrap() - .query_wasm_smart( - &self.palomadex_token_contract, - &cw20::Cw20QueryMsg::TokenInfo {}, - ) - .unwrap(); - - total_supply.u128() - } - - pub fn palomadex_lp(&mut self, user: &str) -> u128 { - let cw20::BalanceResponse { balance } = self - .app - .wrap() - .query_wasm_smart( - &self.palomadex_token_contract, - &cw20::Cw20QueryMsg::Balance { - address: user.to_string(), - }, - ) - .unwrap(); - - balance.u128() - } - - // for debugging tests - #[allow(dead_code)] - pub fn palomadex_lp_holders(&mut self) -> Vec<(String, u128)> { - let cw20::AllAccountsResponse { accounts } = self - .app - .wrap() - .query_wasm_smart( - &self.palomadex_token_contract, - &cw20::Cw20QueryMsg::AllAccounts { - start_after: None, - limit: None, - }, - ) - .unwrap(); - accounts - .into_iter() - .map(|addr| (addr.clone(), self.palomadex_lp(&addr))) - .collect() - } - - pub fn total_palomadex_staked(&mut self) -> u128 { - let addr = self.palomadex_staking_contract.clone(); - self.palomadex_lp(addr.as_str()) - } - - pub fn palomadex_staked(&mut self, user: &str, unbonding_period: u64) -> u128 { - let palomadex_stake::msg::StakedResponse { stake, .. } = self - .app - .wrap() - .query_wasm_smart( - &self.palomadex_staking_contract, - &palomadex_stake::msg::QueryMsg::Staked { - address: user.to_string(), - unbonding_period, - }, - ) - .unwrap(); - - stake.u128() - } -} diff --git a/contracts/junoswap-staking/src/state.rs b/contracts/junoswap-staking/src/state.rs deleted file mode 100644 index 804de3b..0000000 --- a/contracts/junoswap-staking/src/state.rs +++ /dev/null @@ -1,42 +0,0 @@ -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, Uint128}; -use cw_storage_plus::Item; - -#[cw_serde] -pub struct MigrateConfig { - /// This is the address that can run ExecuteMsg::MigrateTokens - pub migrator: Addr, - /// This is how long it will be staked on PALOMA DEX - pub unbonding_period: u64, - - /// This is the junoswap pool where the LP will be withdrawn from - pub junoswap_pool: Addr, - - /// Can be deposited in any pool created by this factory - pub factory: Addr, - /// If set, only can be deposited in this pool (which must also be created by the factory) - pub palomadex_pool: Option, - - /// This is set when token migration is finished. - /// It is used to calculate the amount of LP tokens to give to each staker. - pub migrate_stakers_config: Option, -} - -/// The necessary information to migrate stakers. -#[cw_serde] -pub struct MigrateStakersConfig { - /// The palomadex LP token contract - pub lp_token: Addr, - /// The palomadex LP staking contract - pub staking_addr: Addr, - /// The total amount of palomadex LP tokens this contract received after token migration. - pub total_lp_tokens: Uint128, - /// The total amount of staked junoswap LP tokens. - pub total_staked: Uint128, -} - -/// Stores the contract configuration at the given key -pub const MIGRATION: Item = Item::new("migration"); - -/// This is set once MigrateTokens is called -pub const DESTINATION: Item = Item::new("destination"); diff --git a/contracts/lp-converter/src/contract.rs b/contracts/lp-converter/src/contract.rs index db351a0..9a1366d 100644 --- a/contracts/lp-converter/src/contract.rs +++ b/contracts/lp-converter/src/contract.rs @@ -1,7 +1,6 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult}; -use cw2::set_contract_version; use palomadex::lp_converter::ExecuteMsg; use wynd_lsd_hub::msg::{ ConfigResponse as HubConfigResponse, QueryMsg as HubQueryMsg, SupplyResponse, diff --git a/contracts/lp-converter/src/multitest/migrate_stake.rs b/contracts/lp-converter/src/multitest/migrate_stake.rs index 81a25f7..4bcc75d 100644 --- a/contracts/lp-converter/src/multitest/migrate_stake.rs +++ b/contracts/lp-converter/src/multitest/migrate_stake.rs @@ -1,5 +1,4 @@ -use palomadex::{asset::MINIMUM_LIQUIDITY_AMOUNT, stake::ConverterConfig}; -use palomadex_stake::msg::MigrateMsg; +use palomadex::asset::MINIMUM_LIQUIDITY_AMOUNT; use super::suite::{juno, uusd, Pair, SuiteBuilder, DAY}; @@ -72,75 +71,6 @@ fn migrate_to_existing_pool() { ); } -#[test] -fn migrate_converter_config() { - let user = "user"; - - let ujuno_amount = 1_000_000u128; - let uusd_amount = 1_000_000u128; - - let unbonding_period = 14 * DAY; - - let mut suite = SuiteBuilder::new() - .with_native_balances("ujuno", vec![(user, ujuno_amount)]) - .with_native_balances("uusd", vec![(user, uusd_amount)]) - .without_converter() - .build(); - - // provide some liquidity to the native pair - let native_lp = suite - .provide_liquidity(user, juno(ujuno_amount), uusd(uusd_amount)) - .unwrap(); - - // stake native LP - suite - .stake_lp(Pair::Native, user, native_lp, unbonding_period) - .unwrap(); - - // migrating the liquidity before the converter is set should fail - let err = suite - .migrate_stake(Pair::Native, user, native_lp, unbonding_period) - .unwrap_err(); - assert_eq!( - palomadex_stake::ContractError::NoConverter {}, - err.downcast().unwrap() - ); - - // migrate the staking contract to add the converter - suite - .migrate_staking_contract( - Pair::Native, - MigrateMsg { - unbonder: None, - converter: Some(ConverterConfig { - contract: suite.converter.to_string(), - pair_to: suite.lsd_pair.to_string(), - }), - unbond_all: false, - }, - ) - .unwrap(); - - // migrate liquidity to lsd pair - suite - .migrate_stake(Pair::Native, user, native_lp, unbonding_period) - .unwrap(); - - // check that the stake was migrated - let stake = suite - .query_stake(Pair::Native, user, unbonding_period) - .unwrap(); - assert_eq!(stake.stake.u128(), 0); - let stake = suite - .query_stake(Pair::Lsd, user, unbonding_period) - .unwrap(); - assert_eq!( - stake.stake.u128(), - ujuno_amount - 2 * MINIMUM_LIQUIDITY_AMOUNT.u128(), // 2x because we lp'd twice on empty pools - "all of the stake that was previously in native LP should now be migrated to lsd LP" - ); -} - #[test] fn partial_migration() { let user = "user"; diff --git a/contracts/lp-converter/src/multitest/suite.rs b/contracts/lp-converter/src/multitest/suite.rs index f5789ca..9a1e7db 100644 --- a/contracts/lp-converter/src/multitest/suite.rs +++ b/contracts/lp-converter/src/multitest/suite.rs @@ -121,11 +121,6 @@ impl SuiteBuilder { } } - pub fn without_converter(mut self) -> Self { - self.no_converter = true; - self - } - pub fn with_native_balances(mut self, denom: &str, balances: Vec<(&str, u128)>) -> Self { self.native_balances .extend(balances.into_iter().map(|(addr, amount)| { @@ -352,8 +347,6 @@ impl SuiteBuilder { Suite { app, - staking_code_id, - converter, factory, native_pair, @@ -369,7 +362,6 @@ impl SuiteBuilder { pub struct Suite { pub app: App, - staking_code_id: u64, pub converter: Addr, factory: Addr, pub native_pair: Addr, @@ -549,19 +541,6 @@ impl Suite { ) } - pub fn migrate_staking_contract( - &mut self, - pair: Pair, - msg: palomadex_stake::msg::MigrateMsg, - ) -> AnyResult { - self.app.migrate_contract( - Addr::unchecked("owner"), - pair.staking_addr(self), - &msg, - self.staking_code_id, // same code id - ) - } - pub fn query_stake( &self, pair: Pair, diff --git a/contracts/multi-hop/src/contract.rs b/contracts/multi-hop/src/contract.rs index a37dce7..aa67341 100644 --- a/contracts/multi-hop/src/contract.rs +++ b/contracts/multi-hop/src/contract.rs @@ -5,10 +5,9 @@ use cosmwasm_std::{ DepsMut, Env, MessageInfo, Response, StdError, StdResult, Uint128, WasmMsg, }; use cw20::{Cw20ExecuteMsg, Cw20ReceiveMsg}; -use cw_utils::ensure_from_older_version; use crate::msg::{ - ConfigResponse, Cw20HookMsg, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, + ConfigResponse, Cw20HookMsg, ExecuteMsg, InstantiateMsg, QueryMsg, SimulateSwapOperationsResponse, SwapOperation, MAX_SWAP_OPERATIONS, }; use palomadex::asset::{addr_opt_validate, Asset, AssetInfo, AssetInfoExt}; diff --git a/contracts/pair/src/testing.rs b/contracts/pair/src/testing.rs index 204917b..a9380b4 100644 --- a/contracts/pair/src/testing.rs +++ b/contracts/pair/src/testing.rs @@ -9,17 +9,15 @@ use cw_utils::MsgInstantiateContractResponse; use proptest::prelude::*; use cw20_base::msg::InstantiateMsg as TokenInstantiateMsg; -use palomadex::asset::{ - Asset, AssetInfo, AssetInfoValidated, AssetValidated, MINIMUM_LIQUIDITY_AMOUNT, -}; +use palomadex::asset::{Asset, AssetInfo, AssetInfoValidated, AssetValidated}; use palomadex::factory::PairType; use palomadex::fee_config::FeeConfig; use palomadex::oracle::{SamplePeriod, TwapResponse}; +use palomadex::pair::QueryMsg; use palomadex::pair::{ assert_max_spread, ContractError, Cw20HookMsg, ExecuteMsg, InstantiateMsg, PairInfo, PoolResponse, ReverseSimulationResponse, SimulationResponse, StakeConfig, TWAP_PRECISION, }; -use palomadex::pair::{MigrateMsg, QueryMsg}; use crate::contract::{ accumulate_prices, compute_swap, execute, instantiate, query_pool, query_reverse_simulation, @@ -132,294 +130,6 @@ fn proper_initialization() { ); } -// Rather long test the does a few things -// First for sanity, does a provide liquidity -// Then through migration marks the contract as frozen and assigns addr0000 as the circuit_breaker, the one who can unfreeze the contract and refreeze via an ExecuteMsg -// Then we try to provide liquidity again, which should fail -// We also try a native swap, a cw20 swap and an UpdateFees, all fails with ContractFrozen -// However, withdraw liquidity is not frozen and people can still withdraw -// We then try to unfreeze with addr0001, which should fail -// We then try to unfreeze with addr0000, which should succeed and to prove this we try to -// provide liquidity again and swap, which should both succeed -#[test] -fn test_freezing_a_pool_blocking_actions_then_unfreeze() { - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(200_000000000000000000u128), - }]); - let offer_amount = Uint128::new(1500000000u128); - - 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::Native("uusd".to_string()), - AssetInfo::Token("asset0000".to_string()), - ], - token_code_id: 10u64, - 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(); - - // Store liquidity token - store_liquidity_token(deps.as_mut(), "liquidity0000".to_string()); - - // Successfully provide liquidity for the existing pool - let msg = ExecuteMsg::ProvideLiquidity { - assets: vec![ - Asset { - info: AssetInfo::Token("asset0000".to_string()), - amount: Uint128::from(100_000000000000000000u128), - }, - Asset { - info: AssetInfo::Native("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), - }], - ); - // Do one successful action before freezing just for sanity - execute(deps.as_mut(), env.clone(), info, msg).unwrap(); - - // Manually set the correct balances for the pool - deps.querier.with_balance(&[( - &String::from(MOCK_CONTRACT_ADDR), - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(100_000000000000000000), - }], - )]); - deps.querier.with_token_balances(&[ - ( - &String::from("liquidity0000"), - &[ - (&String::from(MOCK_CONTRACT_ADDR), &MINIMUM_LIQUIDITY_AMOUNT), - ( - &String::from("addr0000"), - &(Uint128::new(100_000000000000000000) - MINIMUM_LIQUIDITY_AMOUNT), - ), - ], - ), - ( - &String::from("asset0000"), - &[( - &String::from(MOCK_CONTRACT_ADDR), - &Uint128::new(100_000000000000000000), - )], - ), - ]); - - // Failing Execute Actions due to frozen - - // This should now fail, its a good TX with all the normal setup done but because of freezing it should fail - let msg = ExecuteMsg::ProvideLiquidity { - assets: vec![ - Asset { - info: AssetInfo::Token("asset0000".to_string()), - amount: Uint128::from(100_000000000000000000u128), - }, - Asset { - info: AssetInfo::Native("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), - }], - ); - - // Assert an error and that its frozen - let res: ContractError = execute(deps.as_mut(), env.clone(), info, msg).unwrap_err(); - assert_eq!(res, ContractError::ContractFrozen {}); - // Also do a swap, which should also fail - let msg = ExecuteMsg::Swap { - offer_asset: Asset { - info: AssetInfo::Native("uusd".to_string()), - amount: 1_000u128.into(), - }, - to: None, - max_spread: None, - belief_price: None, - ask_asset_info: None, - referral_address: None, - referral_commission: None, - }; - - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(1000u128), - }], - ); - // Assert an error and that its frozen - let res: ContractError = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap_err(); - assert_eq!(res, ContractError::ContractFrozen {}); - - let msg = ExecuteMsg::UpdateFees { - fee_config: FeeConfig { - total_fee_bps: 5, - protocol_fee_bps: 5, - }, - }; - let res = execute(deps.as_mut(), env.clone(), info, msg).unwrap_err(); - assert_eq!(res, ContractError::ContractFrozen {}); - - // Normal sell but with CW20 - let msg = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: String::from("addr0000"), - amount: offer_amount, - msg: to_binary(&Cw20HookMsg::Swap { - ask_asset_info: None, - belief_price: None, - max_spread: Some(Decimal::percent(50)), - to: None, - referral_address: None, - referral_commission: None, - }) - .unwrap(), - }); - let info = mock_info("asset0000", &[]); - - let res = execute(deps.as_mut(), env.clone(), info, msg).unwrap_err(); - assert_eq!(res, ContractError::ContractFrozen {}); - - // But we can withdraw liquidity - - // Withdraw liquidity - let msg = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: String::from("addr0000"), - msg: to_binary(&Cw20HookMsg::WithdrawLiquidity { assets: vec![] }).unwrap(), - amount: Uint128::new(100u128), - }); - - let info = mock_info("liquidity0000", &[]); - // We just want to ensure it doesn't fail with a ContractFrozen error - execute(deps.as_mut(), env.clone(), info, msg).unwrap(); - - // Unfreeze the pool again using the Freeze message rather than another migrate - let msg = ExecuteMsg::Freeze { frozen: false }; - // First try a failing case with addr0001 - let info = mock_info("addr0001", &[]); - // Rather than being unfrozen it returns unauthorized as addr0000 is the only addr that can currently call Freeze unless another migration changes that - let err = execute(deps.as_mut(), env.clone(), info, msg.clone()).unwrap_err(); - assert_eq!(err, ContractError::Unauthorized {}); - // But the assigned circuit_breaker address can do an unfreeze with the ExecuteMsg variant - let info = mock_info("addr0000", &[]); - // And it works - execute(deps.as_mut(), env.clone(), info, msg).unwrap(); - - // Testing actions working again after unfreeze - - // 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 */), - }], - )]); - - 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), - )], - ), - ]); - - // Successfully provides liquidity - let msg = ExecuteMsg::ProvideLiquidity { - assets: vec![ - Asset { - info: AssetInfo::Token("asset0000".to_string()), - amount: Uint128::from(100_000000000000000000u128), - }, - Asset { - info: AssetInfo::Native("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), - }], - ); - execute(deps.as_mut(), env.clone(), info, msg).unwrap(); - - // Normal sell but with CW20 - let msg = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: String::from("addr0000"), - amount: offer_amount, - msg: to_binary(&Cw20HookMsg::Swap { - ask_asset_info: None, - belief_price: None, - max_spread: Some(Decimal::percent(50)), - to: None, - referral_address: None, - referral_commission: None, - }) - .unwrap(), - }); - let info = mock_info("asset0000", &[]); - - execute(deps.as_mut(), env, info, msg).unwrap(); -} - #[test] fn provide_liquidity() { let mut deps = mock_dependencies(&[Coin { diff --git a/contracts/raw-migration/.cargo/config b/contracts/raw-migration/.cargo/config deleted file mode 100644 index de2d36a..0000000 --- a/contracts/raw-migration/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[alias] -wasm = "build --release --lib --target wasm32-unknown-unknown" -wasm-debug = "build --lib --target wasm32-unknown-unknown" -unit-test = "test --lib" -schema = "run --bin schema" diff --git a/contracts/raw-migration/Cargo.toml b/contracts/raw-migration/Cargo.toml deleted file mode 100644 index e003a0b..0000000 --- a/contracts/raw-migration/Cargo.toml +++ /dev/null @@ -1,50 +0,0 @@ -[package] -name = "raw-migration" -authors = ["Volume Fi"] -version = { workspace = true } -edition = { workspace = true } -description = "Contract aimed just for migration - take JunoSwap RAW paired tokens and swap them to PALOMA" -license = { workspace = true } -repository = { workspace = true } -homepage = "https://www.palomachain.com" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -# for more explicit tests, cargo test --features=backtraces -backtraces = ["cosmwasm-std/backtraces"] -# use library feature to disable all instantiate/execute/query exports -library = [] - -[dependencies] -cosmwasm-schema = { workspace = true } -cosmwasm-std = { workspace = true } -cw-storage-plus = { workspace = true } -cw2 = { workspace = true } -cw20 = { workspace = true } -cw-utils = { workspace = true } -thiserror = { workspace = true } - -palomadex = { workspace = true } -palomadex-factory = { workspace = true } -palomadex-stake = { workspace = true } - -# this is old version of cw20 used by wasmswap -wasmswap_cw20 = { package = "cw20", version = "0.10.0" } -# this is the staking contract we are migrating from (use the state variables there) -stake-cw20 = { git="https://github.com/DA0-DA0/dao-contracts", tag="v0.3.0" } -# this is the pool contract we will withdraw from -wasmswap = { git="https://github.com/Wasmswap/wasmswap-contracts", tag="v1.1.2-beta" } - -[dev-dependencies] -anyhow = { workspace = true } -cw20-base = { workspace = true } -cw-multi-test = { workspace = true } -serde = { workspace = true } -wasmswap_cw20-base = { package = "cw20-base", version = "0.10.0" } -wasmswap_cw-utils = { package = "cw-utils", version = "0.11" } -palomadex-factory = { workspace = true } -palomadex-pair = { workspace = true } diff --git a/contracts/raw-migration/README.md b/contracts/raw-migration/README.md deleted file mode 100644 index cf65945..0000000 --- a/contracts/raw-migration/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# JunoSwap RAW Staking Migration - -This contract is intended as a migration target for an existing JunoSwap staking contract -that are configure for RAW pools. -Upon migration it will prepare for a future transfer (we don't know the exact pool address, -as we want to perform the migration proposal concurrently with the pool deployment proposal). - -Once it is migrated, the staking contract will be locked, and the only action is that -a nominated migrator account can trigger the transfer - all RAW tokens will be burned, and in its place -Grain tokens will be staked using predefined exchange rate from configuration. -We add some constraints to ensure this is transferred to a valid target contract -to minimize any trust requirements on the migrator (they just have "censorship" power). - diff --git a/contracts/raw-migration/src/bin/schema.rs b/contracts/raw-migration/src/bin/schema.rs deleted file mode 100644 index 33b4f1a..0000000 --- a/contracts/raw-migration/src/bin/schema.rs +++ /dev/null @@ -1,12 +0,0 @@ -use cosmwasm_schema::write_api; -use cosmwasm_std::Empty; -use raw_migration::msg::{ExecuteMsg, MigrateMsg, QueryMsg}; - -fn main() { - write_api! { - instantiate: Empty, - query: QueryMsg, - execute: ExecuteMsg, - migrate: MigrateMsg, - } -} diff --git a/contracts/raw-migration/src/contract.rs b/contracts/raw-migration/src/contract.rs deleted file mode 100644 index f479f62..0000000 --- a/contracts/raw-migration/src/contract.rs +++ /dev/null @@ -1,413 +0,0 @@ -#[cfg(not(feature = "library"))] -use cosmwasm_std::entry_point; -use cosmwasm_std::{ - coin, ensure_eq, to_binary, Addr, Binary, Coin, Deps, DepsMut, Empty, Env, MessageInfo, Order, - Reply, Response, StdResult, SubMsg, Uint128, WasmMsg, -}; - -use cw20::Cw20ExecuteMsg; -use palomadex::asset::{Asset, AssetInfo}; -use wasmswap::msg::InfoResponse; - -use crate::error::ContractError; -use crate::msg::{ExecuteMsg, QueryMsg}; -use crate::state::{MigrateStakersConfig, DESTINATION, EXCHANGE_CONFIG, MIGRATION}; - -// this is the contract we are migrating from -pub const STAKE_CW20_NAME: &str = "crates.io:stake_cw20"; - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn instantiate( - _deps: DepsMut, - _env: Env, - _info: MessageInfo, - _msg: Empty, -) -> Result { - Err(ContractError::NotImplemented) -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> Result { - match msg { - QueryMsg::MigrationFinished {} => { - let no_stakers = stake_cw20::state::STAKED_BALANCES - .keys(_deps.storage, None, None, Order::Ascending) - .next() - .is_none(); - Ok(to_binary(&no_stakers)?) - } - } -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn execute( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: ExecuteMsg, -) -> Result { - match msg { - ExecuteMsg::MigrateTokens { palomadex_pool } => migrate_tokens(deps, env, info, palomadex_pool), - ExecuteMsg::MigrateStakers { limit } => migrate_stakers(deps, env, info, limit), - } -} - -/// Allow `migrator` to pull out LP positions and send them to paloma dex pool -/// First step figures out how many LPs we have and withdraws them. -/// Follow up via reply. -pub fn migrate_tokens( - deps: DepsMut, - env: Env, - info: MessageInfo, - palomadex_pool: String, -) -> Result { - // make sure called by proper account - let mut migration = MIGRATION.load(deps.storage)?; - if info.sender != migration.migrator { - return Err(ContractError::Unauthorized); - } - - // ensure the requested target pool is valid - let w_pool = deps.api.addr_validate(&palomadex_pool)?; - if let Some(ref target) = migration.palomadex_pool { - if target != w_pool { - return Err(ContractError::InvalidDestination(palomadex_pool)); - } - } - let ci = deps.querier.query_wasm_contract_info(&w_pool)?; - if ci.creator != migration.factory { - return Err(ContractError::InvalidDestination(palomadex_pool)); - } - - // save target pool for later reply block - DESTINATION.save(deps.storage, &w_pool)?; - - // calculate LP tokens owner by staking contract, - // for withdrawal and for future distribution - let stake_cfg = stake_cw20::state::CONFIG.load(deps.storage)?; - let token = cw20::Cw20Contract(stake_cfg.token_address); - let balance = token.balance(&deps.querier, env.contract.address)?; - - // fill in most of the migration data now (minus paloma dex LP) - let palomadex::pair::PairInfo { - liquidity_token, - staking_addr, - .. - } = deps - .querier - .query_wasm_smart(&w_pool, &palomadex::pair::QueryMsg::Pair {})?; - - // total_staked is same a balance of junoswap lp token held by this contract - migration.migrate_stakers_config = Some(MigrateStakersConfig { - lp_token: liquidity_token, - staking_addr, - total_lp_tokens: Uint128::zero(), - total_staked: balance, - }); - MIGRATION.save(deps.storage, &migration)?; - - // trigger withdrawal of LP tokens - // we need to assign a cw20 allowance to let the pool burn LP - let allowance = WasmMsg::Execute { - contract_addr: token.0.to_string(), - funds: vec![], - msg: to_binary(&cw20::Cw20ExecuteMsg::IncreaseAllowance { - spender: migration.junoswap_pool.to_string(), - amount: balance, - expires: None, - })?, - }; - - // then craft the LP withdrawal message - let withdraw = WasmMsg::Execute { - contract_addr: migration.junoswap_pool.into_string(), - funds: vec![], - msg: to_binary(&wasmswap::msg::ExecuteMsg::RemoveLiquidity { - amount: balance, - min_token1: Uint128::zero(), - min_token2: Uint128::zero(), - expiration: None, - })?, - }; - - // execute these and handle the next step in reply - let res = Response::new() - .add_message(allowance) - .add_submessage(SubMsg::reply_on_success(withdraw, REPLY_ONE)); - Ok(res) -} - -pub fn migrate_stakers( - mut deps: DepsMut, - env: Env, - info: MessageInfo, - limit: u32, -) -> Result { - // make sure called by proper account - let migration = MIGRATION.load(deps.storage)?; - ensure_eq!(info.sender, migration.migrator, ContractError::Unauthorized); - - let config = migration - .migrate_stakers_config - .ok_or(ContractError::TokensNotMigrated)?; - - // calculate next `limit` stakers and their shares - let stakers = find_stakers(deps.as_ref(), limit)?; - - // remove the processed stakers from the state - remove_stakers(deps.branch(), &env, stakers.iter().map(|(addr, _)| addr))?; - - let staker_lps: Vec<_> = stakers - .into_iter() - .map(|(addr, stake)| { - ( - addr.to_string(), - stake * config.total_lp_tokens / config.total_staked, - ) - }) - .filter(|(_, x)| !x.is_zero()) - .collect(); - - // the amount of LP tokens we are migrating in this message - let batch_lp: Uint128 = staker_lps.iter().map(|(_, x)| x).sum(); - - // bonding has full info on who receives the delegation - let bond_msg = palomadex::stake::ReceiveMsg::MassDelegate { - unbonding_period: migration.unbonding_period, - delegate_to: staker_lps, - }; - - // stake it all - let stake_msg = WasmMsg::Execute { - contract_addr: config.lp_token.to_string(), - funds: vec![], - msg: to_binary(&cw20::Cw20ExecuteMsg::Send { - contract: config.staking_addr.into_string(), - amount: batch_lp, - msg: to_binary(&bond_msg)?, - })?, - }; - - Ok(Response::new().add_message(stake_msg)) -} - -const REPLY_ONE: u64 = 111; -const REPLY_TWO: u64 = 222; - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result { - if msg.result.is_err() { - return Err(ContractError::ErrorReply); - } - match msg.id { - REPLY_ONE => reply_one(deps, env), - REPLY_TWO => reply_two(deps, env), - x => Err(ContractError::UnknownReply(x)), - } -} - -/// In this step, we deposit the new raw tokens (eg. JUNO-ATOM) into PALOMA DEX -/// And get some liquid PALOMA DEX LP tokens -pub fn reply_one(deps: DepsMut, env: Env) -> Result { - let migration = MIGRATION.load(deps.storage)?; - let destination = DESTINATION.load(deps.storage)?; - - // get the JS asset types and convert to PALOMA DEX types - let info: InfoResponse = deps - .querier - .query_wasm_smart(migration.junoswap_pool, &wasmswap::msg::QueryMsg::Info {})?; - let assets = to_palomadex_assets(deps.as_ref(), env.contract.address, info)?; - - // figure out how to transfer these... previous cw20 allowances or - // sending native funds inline with providing liquidity - let DenomDeposits { - allowances, - funds, - new_assets, - } = prepare_denom_deposits(deps.as_ref(), &destination, &assets)?; - let deposit = WasmMsg::Execute { - contract_addr: destination.into_string(), - funds, - msg: to_binary(&palomadex::pair::ExecuteMsg::ProvideLiquidity { - assets: new_assets, - // TODO: set some value here? - slippage_tolerance: None, - receiver: None, - })?, - }; - - // add any cw20 allowances, then call to deposit the tokens and get LP - let res = Response::new() - .add_messages(allowances) - .add_submessage(SubMsg::reply_on_success(deposit, REPLY_TWO)); - Ok(res) -} - -struct DenomDeposits { - allowances: Vec, - funds: Vec, - new_assets: Vec, -} - -/// Checks if one of the denoms matches RAW address, then prepares extra BurnMsg -/// and provides PALOMA equivalent given by specified exchange rate -fn prepare_denom_deposits( - deps: Deps, - destination: &Addr, - assets: &[Asset], -) -> Result { - let mut allowances = vec![]; - let mut funds = vec![]; - - let exchange_config = EXCHANGE_CONFIG.load(deps.storage)?; - - let raw_asset = AssetInfo::Token(exchange_config.raw_token.to_string()); - let new_assets = assets - .iter() - .map(|asset| { - if asset.info == raw_asset { - // first burn raw tokens - let burn_msg = WasmMsg::Execute { - contract_addr: exchange_config.raw_token.to_string(), - msg: to_binary(&Cw20ExecuteMsg::Burn { - amount: asset.amount, - })?, - funds: vec![], - }; - // add BurnMsg to messages - allowances.push(burn_msg); - // now return grain tokens instead - Ok(Asset { - info: AssetInfo::Token(exchange_config.grain_token.to_string()), - amount: asset.amount * exchange_config.raw_to_grain_exchange_rate, - }) - } else { - Ok(asset.clone()) - } - }) - .collect::>>()?; - - // sanity check - debug_assert_eq!(new_assets.len(), 2); - - prepare_denom_deposit(destination, &new_assets[0], &mut allowances, &mut funds)?; - prepare_denom_deposit(destination, &new_assets[1], &mut allowances, &mut funds)?; - - Ok(DenomDeposits { - allowances, - funds, - new_assets, - }) -} - -fn prepare_denom_deposit( - destination: &Addr, - asset: &Asset, - msgs: &mut Vec, - funds: &mut Vec, -) -> Result<(), ContractError> { - // build allowance msg or funds to transfer for this asset - match &asset.info { - AssetInfo::Token(token) => { - let embed = cw20::Cw20ExecuteMsg::IncreaseAllowance { - spender: destination.to_string(), - amount: asset.amount, - expires: None, - }; - let msg = WasmMsg::Execute { - contract_addr: token.to_string(), - msg: to_binary(&embed)?, - funds: vec![], - }; - msgs.push(msg); - } - AssetInfo::Native(denom) => { - let coin = coin(asset.amount.u128(), denom); - funds.push(coin); - } - } - Ok(()) -} - -fn to_palomadex_assets( - deps: Deps, - me: Addr, - info: InfoResponse, -) -> Result, ContractError> { - let asset1 = to_palomadex_asset(deps, &me, info.token1_denom)?; - let asset2 = to_palomadex_asset(deps, &me, info.token2_denom)?; - Ok(vec![asset1, asset2]) -} - -fn to_palomadex_asset( - deps: Deps, - me: &Addr, - token: wasmswap_cw20::Denom, -) -> Result { - let asset = match token { - wasmswap_cw20::Denom::Native(denom) => { - let balance = deps.querier.query_balance(me, denom)?; - Asset { - info: AssetInfo::Native(balance.denom), - amount: balance.amount, - } - } - wasmswap_cw20::Denom::Cw20(addr) => { - let token = cw20::Cw20Contract(addr); - let amount = token.balance(&deps.querier, me)?; - Asset { - info: AssetInfo::Token(token.0.into_string()), - amount, - } - } - }; - Ok(asset) -} - -/// Finally, with those PALOMA DEX LP tokens, we will take them all on behalf -/// of the original JunoSwap LP stakers. -pub fn reply_two(deps: DepsMut, env: Env) -> Result { - // load config for LP token and staking contract - let mut migration = MIGRATION.load(deps.storage)?; - let config = migration.migrate_stakers_config.as_mut().unwrap(); - - // how many LP do we have total - let lp_token = cw20::Cw20Contract(config.lp_token.clone()); - let total_lp_tokens = lp_token.balance(&deps.querier, env.contract.address)?; - - // store this for `migrate_stakers` to use - config.total_lp_tokens = total_lp_tokens; - MIGRATION.save(deps.storage, &migration)?; - - Ok(Response::new()) -} - -// query logic taken from https://github.com/cosmorama/wyndex-priv/pull/109 -fn find_stakers(deps: Deps, limit: impl Into>) -> StdResult> { - let balances = stake_cw20::state::STAKED_BALANCES - .range(deps.storage, None, None, Order::Ascending) - .map(|stake| { - let (addr, amount) = stake?; - - // query all pending claims and bond them as well - let claims = stake_cw20::state::CLAIMS.query_claims(deps, &addr)?; - let claims_sum = claims.claims.iter().map(|c| c.amount).sum::(); - - Ok((addr, amount + claims_sum)) - }); - match limit.into() { - Some(limit) => balances.take(limit as usize).collect(), - None => balances.collect(), - } -} - -fn remove_stakers<'a>( - deps: DepsMut, - env: &Env, - stakers: impl Iterator, -) -> Result<(), ContractError> { - for staker in stakers { - stake_cw20::state::STAKED_BALANCES.remove(deps.storage, staker, env.block.height)?; - } - Ok(()) -} diff --git a/contracts/raw-migration/src/error.rs b/contracts/raw-migration/src/error.rs deleted file mode 100644 index b91d5dc..0000000 --- a/contracts/raw-migration/src/error.rs +++ /dev/null @@ -1,32 +0,0 @@ -use cosmwasm_std::StdError; -use thiserror::Error; - -#[derive(Debug, Error, PartialEq)] -pub enum ContractError { - #[error("{0}")] - Std(#[from] StdError), - - #[error("Unauthorized")] - Unauthorized, - - #[error("Tokens have to be migrated before stakers")] - TokensNotMigrated, - - #[error("{0} isn't an authorized pool to withdraw into")] - InvalidDestination(String), - - #[error("Method not implemented - only intended for migration")] - NotImplemented, - - #[error("Cannot migrate contract type: `{0}`. Only works for wasmswap staking")] - CannotMigrate(String), - - #[error("Got reply with unknown ID: {0}")] - UnknownReply(u64), - - #[error("Target factory doesn't have unbonding period: {0}")] - InvalidUnbondingPeriod(u64), - - #[error("Got reply with error, only handle success case")] - ErrorReply, -} diff --git a/contracts/raw-migration/src/junoswap.rs b/contracts/raw-migration/src/junoswap.rs deleted file mode 100644 index a239263..0000000 --- a/contracts/raw-migration/src/junoswap.rs +++ /dev/null @@ -1,2 +0,0 @@ -// This is state and message definitions copied from the junoswap contracts we migrate from - diff --git a/contracts/raw-migration/src/lib.rs b/contracts/raw-migration/src/lib.rs deleted file mode 100644 index a3d2c2f..0000000 --- a/contracts/raw-migration/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod contract; -mod error; -pub mod msg; -pub mod state; - -#[cfg(test)] -mod multitest; - -pub use error::ContractError; - -// #[cfg(test)] -// mod multitest; diff --git a/contracts/raw-migration/src/msg.rs b/contracts/raw-migration/src/msg.rs deleted file mode 100644 index a5e9e38..0000000 --- a/contracts/raw-migration/src/msg.rs +++ /dev/null @@ -1,60 +0,0 @@ -use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::Decimal; - -#[cw_serde] -pub struct InstantiateMsg {} - -#[cw_serde] -#[derive(QueryResponses)] -pub enum QueryMsg { - /// Checks whether all stakers have been migrated - #[returns(bool)] - MigrationFinished {}, -} - -/// For existing contract, we need to specify which pool it can be withdrawn into -#[cw_serde] -pub struct MigrateMsg { - /// This must be Some the first migration (from JunoSwap contracts). - /// This must be None if upgrading from raw-migration to raw-migration - pub init: Option, -} - -/// For existing contract, we need to specify which pool it can be withdrawn into -#[cw_serde] -pub struct OrigMigrateMsg { - /// This is the address that can run ExecuteMsg::MigrateTokens - pub migrator: String, - /// This is how long it will be staked on PALOMA DEX - pub unbonding_period: u64, - - /// This is the junoswap pool where the LP will be withdrawn from - pub junoswap_pool: String, - - /// Can be deposited in any pool created by this factory - pub factory: String, - /// If set, only can be deposited in this pool (which must also be created by the factory) - pub palomadex_pool: Option, - // Multiplier applied on amount of RAW to get Grain tokens. - // Example: - // exchange_rate = 1.5 - // 10 RAW * exchange_rate = 15 PALOMA - pub raw_to_grain_exchange_rate: Decimal, - // Address of cw20 RAW token - pub raw_address: String, - // Address of cw20 Grain token - pub grain_address: String, -} - -#[cw_serde] -pub enum ExecuteMsg { - /// Migrate tokens to this pool. - /// This moves the LP tokens to this contract, which are later given to the stakers in `MigrateStakers`. - /// Must be called by migrator. - /// Target pool must match constraints above - MigrateTokens { palomadex_pool: String }, - - /// Give the next `limit` stakers their LP tokens. - /// Must be called by migrator. - MigrateStakers { limit: u32 }, -} diff --git a/contracts/raw-migration/src/multitest.rs b/contracts/raw-migration/src/multitest.rs deleted file mode 100644 index c5348f3..0000000 --- a/contracts/raw-migration/src/multitest.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod migration; -mod suite; diff --git a/contracts/raw-migration/src/multitest/migration.rs b/contracts/raw-migration/src/multitest/migration.rs deleted file mode 100644 index 63eb70b..0000000 --- a/contracts/raw-migration/src/multitest/migration.rs +++ /dev/null @@ -1,430 +0,0 @@ -use super::suite::SuiteBuilder; -use crate::{multitest::suite::PoolDenom, ContractError}; - -use palomadex::asset::{AssetInfoValidated, AssetValidated}; - -use wasmswap_cw20::Denom; - -use cosmwasm_std::{assert_approx_eq, coin, Addr, Coin, Decimal, Uint128}; - -#[test] -fn migrate_raw_with_native() { - let ujuno = "ujuno"; - let raw = "RAW"; - let users = ["user", "user2", "user3"]; - // Setup Pools with initial liquidity - let liquidity = vec![coin(3_000_000, ujuno)]; - let liquidity_cw20 = 3_000_002u128; - - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Native(ujuno.to_owned()), - PoolDenom::Cw20(raw.to_owned()), - ) - .build(); - - let raw_denom = suite.pool_denom2.clone(); - let raw_address = match &raw_denom { - Denom::Cw20(address) => address, - _ => panic!("expected cw20 denom"), - }; - - let grain_token = suite.grain_cw20_token.clone(); - - // mint PALOMA tokens for migration contract - let junoswap_staking_contract = suite.junoswap_staking_contract.to_string(); - suite - .mint_cw20( - "owner", - &grain_token, - 5_000_000u128, - &junoswap_staking_contract, - ) - .unwrap(); - - // Provide Liquidity to the CW20 Native pair - // Note: Second deposits need 1 extra cw20 similar to the above rounding errors - suite - .provide_liquidity_to_junoswap_pool( - users[0], - 1_000_000u128, - 1_000_000u128, - Some(Denom::Native(ujuno.to_owned())), - Some(raw_denom.clone()), - vec![coin(1_000_000, ujuno)], - ) - .unwrap(); - - suite - .provide_liquidity_to_junoswap_pool( - users[1], - 1_000_000u128, - 1_000_001u128, - Some(Denom::Native(ujuno.to_owned())), - Some(raw_denom.clone()), - vec![coin(1_000_000, ujuno)], - ) - .unwrap(); - suite - .provide_liquidity_to_junoswap_pool( - users[2], - 1_000_000u128, - 1_000_001u128, - Some(Denom::Native(ujuno.to_owned())), - Some(raw_denom.clone()), - vec![coin(1_000_000, ujuno)], - ) - .unwrap(); - - // check balances of pool - let junoswap = suite - .app - .wrap() - .query_all_balances(&suite.junoswap_pool_contract) - .unwrap(); - assert_eq!(junoswap, liquidity); - let junoswap = cw20::Cw20Contract(raw_address.clone()) - .balance(&suite.app.wrap(), suite.junoswap_pool_contract.clone()) - .unwrap(); - assert_eq!(junoswap.u128(), liquidity_cw20); - - suite.palomadex_lp_holders(); - - // stake some of these tokens - 80% of liquidity should be moved - // users[0] will keep everything staked - let to_stake = suite.junoswap_lp(users[0], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp( - users[0], - to_stake, - None, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - // users[1] will unstake half - let to_stake = suite.junoswap_lp(users[1], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp( - users[1], - to_stake, - None, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - suite - .unstake_junoswap_lp( - users[1], - to_stake / Uint128::new(2), - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - // users[2] will unstake all - let to_stake = suite.junoswap_lp(users[2], None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp( - users[2], - to_stake, - None, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - suite - .unstake_junoswap_lp( - users[2], - to_stake, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - - // perform the migration of liquidity - let raw_to_grain_exchange_rate = Decimal::percent(200); - suite - .migrate_to_palomadex( - None, - None, - None, - raw_to_grain_exchange_rate, - raw_address.clone(), - ) - .unwrap(); - - // 80% of native liquidity moved to palomadex pool - let palomadex = suite - .app - .wrap() - .query_all_balances(&suite.palomadex_pair_contract) - .unwrap(); - let expected = liquidity - .iter() - .map(|Coin { amount, denom }| coin(amount.u128() * 4 / 5, denom)) - .collect::>(); - assert_eq!(palomadex, expected); - - // 80% of cw20 liquidity moved to palomadex pool - // RAW token is now GONE, it was swapped in prepare_denom_deposits at a rate of 200% (set above) - // Check the balance of PALOMA token instead, it should have been swapped at a 2-1 rate (200%) - let palomadex = cw20::Cw20Contract(grain_token.clone()) - .balance(&suite.app.wrap(), suite.palomadex_pair_contract.clone()) - .unwrap(); - let expected = liquidity_cw20 * 4 / 5; - assert_eq!(palomadex.u128(), expected * 2); - - // ensure all lp belong to the staking contract - let palomadex_total = suite.total_palomadex_lp(); - let palomadex_staked = suite.total_palomadex_staked(); - assert_approx_eq!(palomadex_total, palomadex_staked, "0.001"); - // ensure all staked tokens belong to the migrated user - let user_staked = suite.palomadex_staked(users[0], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 3); - // user 2 staked 500k so they should have about 10% of the staked tokens - let user_staked = suite.palomadex_staked(users[1], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 3); - // user 3 did 3m and should have 60% - let user_staked = suite.palomadex_staked(users[2], suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked / 3); - - // now to the meat - check assets of the pool and balance - // verify amounts here, for cw20 its 3mil * 2 (exchange rate) * 4/5 (80% of liquidity was moved) = 4.8M - // for native, just the 3 mil * 4/5 (80% of liquidity was moved) = 2.4M - let pool_info = suite.query_palomadex_pool(); - assert_eq!( - pool_info.assets, - vec![ - AssetValidated { - info: AssetInfoValidated::Native(ujuno.to_string()), - amount: Uint128::new(2_400_000) - }, - AssetValidated { - info: AssetInfoValidated::Token(grain_token.clone()), - amount: Uint128::new(4_800_002) - } - ] - ); -} - -#[test] -fn non_migrator_cant_migrate() { - let user = "user"; - - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Cw20("raw".to_owned()), - PoolDenom::Cw20("cwt".to_owned()), - ) - .build(); - - let raw_denom = suite.pool_denom1.clone(); - let raw_address = match &raw_denom { - Denom::Cw20(address) => address, - _ => panic!("expected cw20 denom"), - }; - let cw20_denom = suite.pool_denom2.clone(); - let grain_token = suite.grain_cw20_token.clone(); - - // mint PALOMA tokens for migration contract - let junoswap_staking_contract = suite.junoswap_staking_contract.to_string(); - suite - .mint_cw20( - "owner", - &grain_token, - 5_000_000u128, - &junoswap_staking_contract, - ) - .unwrap(); - - // Provide Liquidity to the CW20 pair - suite - .provide_liquidity_to_junoswap_pool( - user, - 2_000_000u128, - 2_000_000u128, - Some(cw20_denom), - Some(raw_denom.clone()), - vec![], - ) - .unwrap(); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite.stake_junoswap_lp(user, to_stake, None, None).unwrap(); - - // this won't work, not the migrator - let err = suite - .migrate_to_palomadex( - Some(Addr::unchecked("notthemigrator")), - None, - None, - Decimal::percent(100), - raw_address.clone(), - ) - .unwrap_err(); - assert_eq!(ContractError::Unauthorized {}, err.downcast().unwrap()) -} -#[test] -fn migrator_cant_migrate_to_own_addr() { - let user = "user"; - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Cw20("cwt".to_owned()), - PoolDenom::Cw20("raw".to_owned()), - ) - .build(); - - let raw_denom = suite.pool_denom1.clone(); - let cw20_denom = suite.pool_denom2.clone(); - let raw_address = match &cw20_denom { - Denom::Cw20(address) => address, - _ => panic!("expected cw20 denom"), - }; - let grain_token = suite.grain_cw20_token.clone(); - - // mint PALOMA tokens for migration contract - let junoswap_staking_contract = suite.junoswap_staking_contract.to_string(); - suite - .mint_cw20( - "owner", - &grain_token, - 5_000_000u128, - &junoswap_staking_contract, - ) - .unwrap(); - - // Provide Liquidity to the CW20 pair - suite - .provide_liquidity_to_junoswap_pool( - user, - 2_000_000u128, - 2_000_000u128, - Some(cw20_denom.clone()), - Some(raw_denom), - vec![], - ) - .unwrap(); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite.stake_junoswap_lp(user, to_stake, None, None).unwrap(); - - // this won't work, we can only migrate to a deployed pool contract. - let err = suite - .migrate_to_palomadex( - Some(Addr::unchecked("owner")), - Some(suite.palomadex_pair_contract.clone()), - Some(Addr::unchecked("owner")), - Decimal::percent(100), - raw_address.clone(), - ) - .unwrap_err(); - - assert_eq!( - ContractError::InvalidDestination("owner".to_string()), - err.downcast().unwrap() - ); -} - -#[test] -fn migration_two_cw20() { - let user = "user"; - let liquidity = 2_000_000u128; - - let mut suite = SuiteBuilder::new() - .with_denoms( - PoolDenom::Cw20("cwt".to_owned()), - PoolDenom::Cw20("raw".to_owned()), - ) - .build(); - - let cw20_denom = suite.pool_denom1.clone(); - let cw20_address = match &cw20_denom { - Denom::Cw20(address) => address, - _ => panic!("expected cw20 denom"), - }; - let raw_denom = suite.pool_denom2.clone(); - let raw_address = match &raw_denom { - Denom::Cw20(address) => address, - _ => panic!("expected cw20 denom"), - }; - let grain_token = suite.grain_cw20_token.clone(); - - // mint PALOMA tokens for migration contract - let junoswap_staking_contract = suite.junoswap_staking_contract.to_string(); - suite - .mint_cw20( - "owner", - &grain_token, - 5_000_000u128, - &junoswap_staking_contract, - ) - .unwrap(); - - // Provide Liquidity to the CW20 pair - suite - .provide_liquidity_to_junoswap_pool( - user, - 2_000_000u128, - 2_000_000u128, - Some(cw20_denom.clone()), - Some(raw_denom.clone()), - vec![], - ) - .unwrap(); - - // stake some of these tokens - 80% of liquidity should be moved - let to_stake = suite.junoswap_lp(user, None).unwrap() * Decimal::percent(80); - suite - .stake_junoswap_lp( - user, - to_stake, - None, - Some(&suite.junoswap_staking_contract.clone()), - ) - .unwrap(); - - // make sure no lp before the deposit - let palomadex_total = suite.total_palomadex_lp(); - assert_eq!(palomadex_total, 0u128); - - // perform the migration of liquidity - let raw_to_grain_exchange_rate = Decimal::percent(200); - suite - .migrate_to_palomadex( - None, - None, - None, - raw_to_grain_exchange_rate, - raw_address.clone(), - ) - .unwrap(); - // 80% of liquidity moved to palomadex pool - let cw20_token_liquidity = cw20::Cw20Contract(cw20_address.clone()) - .balance(&suite.app.wrap(), suite.palomadex_pair_contract.clone()) - .unwrap(); - let expected = liquidity * 4 / 5; - assert_eq!(cw20_token_liquidity.u128(), expected); - // Grin given for RAW tokens - let palomadex = cw20::Cw20Contract(grain_token.clone()) - .balance(&suite.app.wrap(), suite.palomadex_pair_contract.clone()) - .unwrap(); - let expected = Uint128::from(liquidity * 4 / 5) * raw_to_grain_exchange_rate; - assert_eq!(palomadex, expected); - - let raw = cw20::Cw20Contract(raw_address.clone()) - .balance(&suite.app.wrap(), suite.palomadex_pair_contract.clone()) - .unwrap(); - assert_eq!(raw.u128(), 0u128); - - // ensure all lp belong to the staking contract - let palomadex_total = suite.total_palomadex_lp(); - let palomadex_staked = suite.total_palomadex_staked(); - let pool = suite.palomadex_pair_contract.to_string(); - let pool_own_lp = suite.palomadex_lp(&pool); - assert_eq!(palomadex_total, palomadex_staked + pool_own_lp); - assert_eq!( - pool_own_lp, - palomadex::asset::MINIMUM_LIQUIDITY_AMOUNT.u128() - ); - - // ensure all staked tokens belong to the migrated user - let user_staked = suite.palomadex_staked(user, suite.migration_unbonding_period()); - assert_eq!(user_staked, palomadex_staked); -} diff --git a/contracts/raw-migration/src/multitest/suite.rs b/contracts/raw-migration/src/multitest/suite.rs deleted file mode 100644 index d8d0f62..0000000 --- a/contracts/raw-migration/src/multitest/suite.rs +++ /dev/null @@ -1,761 +0,0 @@ -use anyhow::Result as AnyResult; - -use cw20::MinterResponse; -use palomadex::asset::AssetInfo; -use palomadex::factory::{ - DefaultStakeConfig, ExecuteMsg as FactoryExecuteMsg, InstantiateMsg as FactoryInstantiateMsg, - PairConfig, PairType, PartialStakeConfig, QueryMsg as FactoryQueryMsg, -}; -use palomadex::fee_config::FeeConfig; -use palomadex::pair::{PairInfo, PoolResponse, QueryMsg as PairQueryMsg}; - -use crate::msg::{MigrateMsg, OrigMigrateMsg, QueryMsg}; -use cosmwasm_std::{coin, to_binary, Addr, Coin, Decimal, Uint128}; -use cw20_base::msg::InstantiateMsg as Cw20BaseInstantiateMsg; -use cw_multi_test::{next_block, App, AppResponse, BankSudo, ContractWrapper, Executor, SudoMsg}; -use stake_cw20::msg::{ClaimsResponse, InstantiateMsg as StakeCw20IntantiateMsg}; -use wasmswap::msg::{ - ExecuteMsg as WasmswapExecuteMsg, InfoResponse, InstantiateMsg as WasmswapInstantiateMsg, - QueryMsg as WasmswapQueryMsg, -}; -use wasmswap_cw20::{Cw20ExecuteMsg, Denom}; -use wasmswap_cw_utils::Duration; - -pub const ONE_DAY: u64 = 86_400; - -pub fn store_stake_cw20(app: &mut App) -> u64 { - let contract = Box::new(ContractWrapper::new( - stake_cw20::contract::execute, - stake_cw20::contract::instantiate, - stake_cw20::contract::query, - )); - app.store_code(contract) -} - -pub fn store_junoswap_pool(app: &mut App) -> u64 { - let contract = Box::new( - ContractWrapper::new( - wasmswap::contract::execute, - wasmswap::contract::instantiate, - wasmswap::contract::query, - ) - .with_reply_empty(wasmswap::contract::reply), - ); - app.store_code(contract) -} - -pub fn store_cw20(app: &mut App) -> u64 { - let contract = Box::new(ContractWrapper::new( - wasmswap_cw20_base::contract::execute, - wasmswap_cw20_base::contract::instantiate, - wasmswap_cw20_base::contract::query, - )); - app.store_code(contract) -} - -pub fn store_palomadex_staking(app: &mut App) -> u64 { - let contract = Box::new(ContractWrapper::new( - palomadex_stake::contract::execute, - palomadex_stake::contract::instantiate, - palomadex_stake::contract::query, - )); - app.store_code(contract) -} - -fn store_palomadex_factory(app: &mut App) -> u64 { - let factory_contract = Box::new( - ContractWrapper::new_with_empty( - palomadex_factory::contract::execute, - palomadex_factory::contract::instantiate, - palomadex_factory::contract::query, - ) - .with_reply_empty(palomadex_factory::contract::reply), - ); - - app.store_code(factory_contract) -} - -fn store_palomadex_pair(app: &mut App) -> u64 { - let factory_contract = Box::new( - ContractWrapper::new_with_empty( - palomadex_pair::contract::execute, - palomadex_pair::contract::instantiate, - palomadex_pair::contract::query, - ) - .with_reply_empty(palomadex_pair::contract::reply), - ); - - app.store_code(factory_contract) -} - -pub fn store_migrator(app: &mut App) -> u64 { - let contract = Box::new( - ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply), - ); - app.store_code(contract) -} - -/// Helper to be able to specify a non-existing cw20 token -#[derive(Debug, Clone)] -pub enum PoolDenom { - Native(String), - /// The string is not the contract address, but the symbol / name of the token. - /// A new token will be instantiated using this name. - Cw20(String), -} - -impl PoolDenom { - pub fn into_denom( - self, - app: &mut App, - owner: impl Into + Clone, - cw20_code_id: u64, - ) -> Denom { - match self { - PoolDenom::Native(denom) => Denom::Native(denom), - PoolDenom::Cw20(symbol) => { - // create cw20 token - let cw20_token = app - .instantiate_contract( - cw20_code_id, - Addr::unchecked(owner.clone()), - &Cw20BaseInstantiateMsg { - name: symbol.clone(), - symbol: symbol.clone(), - decimals: 6, - initial_balances: vec![], - mint: Some(MinterResponse { - minter: owner.into(), - cap: None, - }), - marketing: None, - }, - &[], - symbol, - None, - ) - .unwrap(); - Denom::Cw20(cw20_token) - } - } - } -} - -#[derive(Debug)] -pub struct SuiteBuilder { - funds: Vec<(Addr, Vec)>, - unbonding_periods: Vec, - pool_denom1: PoolDenom, - pool_denom2: PoolDenom, -} - -impl SuiteBuilder { - pub fn new() -> SuiteBuilder { - SuiteBuilder { - unbonding_periods: vec![100, 200, 300], - pool_denom1: PoolDenom::Native("ujuno".to_string()), - pool_denom2: PoolDenom::Native("uluna".to_string()), - funds: vec![], - } - } - - /// Specify the pool denoms. For cw20 denoms, the - pub fn with_denoms(mut self, denom1: PoolDenom, denom2: PoolDenom) -> Self { - self.pool_denom1 = denom1; - self.pool_denom2 = denom2; - self - } - - #[track_caller] - pub fn build(self) -> Suite { - let mut app = App::default(); - let owner = Addr::unchecked("owner"); - - let cw20_code_id = store_cw20(&mut app); - - let pool_denom1 = self - .pool_denom1 - .into_denom(&mut app, owner.clone(), cw20_code_id); - let pool_denom2 = self - .pool_denom2 - .into_denom(&mut app, owner.clone(), cw20_code_id); - - // Instantiate junoswap pool - let junoswap_pool_code_id = store_junoswap_pool(&mut app); - let junoswap_pool_contract = app - .instantiate_contract( - junoswap_pool_code_id, - owner.clone(), - &WasmswapInstantiateMsg { - token1_denom: pool_denom1.clone(), - token2_denom: pool_denom2.clone(), - lp_token_code_id: cw20_code_id, - owner: Some(owner.to_string()), - lp_fee_percent: Decimal::zero(), - protocol_fee_percent: Decimal::zero(), - protocol_fee_recipient: owner.to_string(), - }, - &[], - "wasmswap-pool", - Some(owner.to_string()), - ) - .unwrap(); - app.update_block(next_block); - - // Check address of created token contract - let junoswap_token_contract = Addr::unchecked( - app.wrap() - .query_wasm_smart::( - &junoswap_pool_contract, - &WasmswapQueryMsg::Info {}, - ) - .unwrap() - .lp_token_address, - ); - - // Instantiate junoswap staking contract - let junoswap_staking_code_id = store_stake_cw20(&mut app); - let junoswap_staking_contract = app - .instantiate_contract( - junoswap_staking_code_id, - owner.clone(), - &StakeCw20IntantiateMsg { - owner: Some(owner.to_string()), - manager: Some("manager".to_string()), - token_address: junoswap_token_contract.to_string(), - unstaking_duration: Some(Duration::Time(ONE_DAY * 14)), - }, - &[], - "staking", - Some(owner.to_string()), - ) - .unwrap(); - app.update_block(next_block); - - // Instantiate palomadex factory - let palomadex_stake_code_id = store_palomadex_staking(&mut app); - let palomadex_pair_code_id = store_palomadex_pair(&mut app); - let palomadex_factory_code_id = store_palomadex_factory(&mut app); - let factory_contract = app - .instantiate_contract( - palomadex_factory_code_id, - owner.clone(), - &FactoryInstantiateMsg { - pair_configs: vec![PairConfig { - pair_type: PairType::Xyk {}, - code_id: palomadex_pair_code_id, - fee_config: FeeConfig { - total_fee_bps: 0, - protocol_fee_bps: 0, - }, - is_disabled: false, - }], - token_code_id: cw20_code_id, - fee_address: Some(owner.to_string()), - owner: owner.to_string(), - max_referral_commission: Decimal::one(), - default_stake_config: DefaultStakeConfig { - staking_code_id: palomadex_stake_code_id, - tokens_per_power: Uint128::new(1000), - min_bond: Uint128::new(1000), - unbonding_periods: self.unbonding_periods.clone(), - max_distributions: 6, - converter: None, - }, - trading_starts: None, - }, - &[], - "palomadex-factory", - Some(owner.to_string()), - ) - .unwrap(); - - let wynd_cw20_token = app - .instantiate_contract( - cw20_code_id, - Addr::unchecked(owner.clone()), - &Cw20BaseInstantiateMsg { - name: "PALOMA".to_owned(), - symbol: "PALOMA".to_owned(), - decimals: 6, - initial_balances: vec![], - mint: Some(MinterResponse { - minter: owner.to_string(), - cap: None, - }), - marketing: None, - }, - &[], - "PALOMA".to_owned(), - None, - ) - .unwrap(); - - // Wasmswap is using older version of cw20, so specific From impl - // would have to be created - IMO not worth it - let asset_infos = vec![ - match pool_denom1.clone() { - Denom::Native(s) => AssetInfo::Native(s), - Denom::Cw20(s) => AssetInfo::Token(s.to_string()), - }, - AssetInfo::Token(wynd_cw20_token.to_string()), - ]; - - // Instantiate palomadex pair contract through factory - app.execute_contract( - owner.clone(), - factory_contract.clone(), - &FactoryExecuteMsg::CreatePair { - pair_type: PairType::Xyk {}, - asset_infos: asset_infos.clone(), - init_params: None, - total_fee_bps: None, - // accept defaults, but ensure there is a staking contract - staking_config: PartialStakeConfig { - staking_code_id: None, - tokens_per_power: None, - min_bond: None, - unbonding_periods: None, - max_distributions: None, - converter: None, - }, - }, - &[], - ) - .unwrap(); - let pair_info = app - .wrap() - .query_wasm_smart::( - Addr::unchecked(&factory_contract), - &FactoryQueryMsg::Pair { asset_infos }, - ) - .unwrap(); - - let palomadex_pair_contract = pair_info.contract_addr; - let palomadex_staking_contract = pair_info.staking_addr; - let palomadex_token_contract = pair_info.liquidity_token; - - // add funds to the contract - let funds = self.funds; - app.init_modules(|router, _, storage| -> AnyResult<()> { - for (addr, coin) in funds { - router.bank.init_balance(storage, &addr, coin)?; - } - Ok(()) - }) - .unwrap(); - - let migrator_code_id = store_migrator(&mut app); - - Suite { - owner, - app, - junoswap_token_contract, - junoswap_pool_contract, - junoswap_staking_contract, - factory_contract, - palomadex_pair_contract, - palomadex_staking_contract, - palomadex_token_contract, - grain_cw20_token: wynd_cw20_token, - migrator_code_id, - cw20_code_id, - pool_denom1, - pool_denom2, - unbonding_periods: self.unbonding_periods, - } - } -} - -pub struct Suite { - pub owner: Addr, - pub app: App, - pub migrator_code_id: u64, - pub cw20_code_id: u64, - pub unbonding_periods: Vec, - - pub junoswap_token_contract: Addr, - pub junoswap_pool_contract: Addr, - pub junoswap_staking_contract: Addr, - pub grain_cw20_token: Addr, - pub palomadex_token_contract: Addr, - pub palomadex_staking_contract: Addr, - pub palomadex_pair_contract: Addr, - pub pool_denom1: Denom, - pub pool_denom2: Denom, - - pub factory_contract: Addr, -} - -#[derive(Debug)] -#[allow(dead_code)] -struct SuiteInfo<'a> { - pub junoswap_token_contract: &'a Addr, - pub junoswap_pool_contract: &'a Addr, - pub junoswap_staking_contract: &'a Addr, - pub factory_contract: &'a Addr, - pub palomadex_token_contract: &'a Addr, - pub palomadex_staking_contract: &'a Addr, - pub palomadex_pair_contract: &'a Addr, -} - -impl Suite { - // for debugging tests - #[allow(dead_code)] - pub fn info(&self) { - let info = SuiteInfo { - junoswap_token_contract: &self.junoswap_token_contract, - junoswap_pool_contract: &self.junoswap_pool_contract, - junoswap_staking_contract: &self.junoswap_staking_contract, - factory_contract: &self.factory_contract, - palomadex_token_contract: &self.palomadex_token_contract, - palomadex_staking_contract: &self.palomadex_staking_contract, - palomadex_pair_contract: &self.palomadex_pair_contract, - }; - println!("{:?}", info); - } - - pub fn migration_unbonding_period(&self) -> u64 { - self.unbonding_periods[1] - } - - /// Returns true if migration is finished - /// Only makes sense to call after the junoswap staking contract has been migrated - pub fn migration_finished(&self) -> AnyResult { - self.app - .wrap() - .query_wasm_smart( - self.junoswap_staking_contract.clone(), - &QueryMsg::MigrationFinished {}, - ) - .map_err(Into::into) - } - - /// Migrates the junoswap staking contract to our migration contract and migrates the tokens - pub fn migrate_tokens( - &mut self, - migrator: Option, - palomadex_pair_migrate: Option, - palomadex_pair: Option, - raw_to_wynd_exchange_rate: Decimal, - raw_address: Addr, - ) -> AnyResult { - // // take RAW token's address by force. We know it is the one. - // let raw_address = match self.pool_denom2.clone() { - // Denom::Cw20(address) => address, - // _ => todo!(), - // }; - // first set up the migration - self.app.migrate_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &MigrateMsg { - init: Some(OrigMigrateMsg { - migrator: migrator.unwrap_or_else(|| self.owner.clone()).to_string(), - unbonding_period: self.migration_unbonding_period(), - junoswap_pool: self.junoswap_pool_contract.to_string(), - factory: self.factory_contract.to_string(), - palomadex_pool: palomadex_pair_migrate.map(|p| p.to_string()), - raw_to_grain_exchange_rate: raw_to_wynd_exchange_rate, - raw_address: raw_address.to_string(), - grain_address: self.grain_cw20_token.to_string(), - }), - }, - self.migrator_code_id, - )?; - - // then migrate again (self-migrate) to ensure it works - self.app.migrate_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &MigrateMsg { init: None }, - self.migrator_code_id, - )?; - - // then trigger the actual migration - self.app.execute_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &crate::msg::ExecuteMsg::MigrateTokens { - palomadex_pool: palomadex_pair - .unwrap_or_else(|| self.palomadex_pair_contract.clone()) - .to_string(), - }, - &[], - ) - } - - /// Migrates the next `limit` staker's LP tokens. - /// Only makes sense to call after the junoswap staking contract has been migrated. - pub fn migrate_stakers(&mut self, limit: u32) -> AnyResult { - self.app.execute_contract( - self.owner.clone(), - self.junoswap_staking_contract.clone(), - &crate::msg::ExecuteMsg::MigrateStakers { limit }, - &[], - ) - } - - pub fn migrate_to_palomadex( - &mut self, - migrator: Option, - palomadex_pair_migrate: Option, - palomadex_pair: Option, - raw_to_wynd_exchange_rate: Decimal, - raw_address: Addr, - ) -> AnyResult<()> { - self.migrate_tokens( - migrator, - palomadex_pair_migrate, - palomadex_pair, - raw_to_wynd_exchange_rate, - raw_address, - )?; - - // now migrate all the stakers - while !self.migration_finished()? { - self.migrate_stakers(10)?; - } - - Ok(()) - } - - fn increase_allowance( - &mut self, - owner: &str, - contract: &Addr, - spender: &str, - amount: u128, - ) -> AnyResult { - self.app.execute_contract( - Addr::unchecked(owner), - contract.clone(), - &Cw20ExecuteMsg::IncreaseAllowance { - spender: spender.to_owned(), - amount: amount.into(), - expires: None, - }, - &[], - ) - } - - pub fn mint_cw20( - &mut self, - owner: &str, - token: &Addr, - amount: u128, - recipient: &str, - ) -> AnyResult { - self.app.execute_contract( - Addr::unchecked(owner), - token.clone(), - &Cw20ExecuteMsg::Mint { - recipient: recipient.to_owned(), - amount: amount.into(), - }, - &[], - ) - } - - pub fn junoswap_lp(&mut self, user: &str, lp_contract: Option<&Addr>) -> AnyResult { - let query = cw20::Cw20QueryMsg::Balance { - address: user.to_string(), - }; - let cw20::BalanceResponse { balance } = self - .app - .wrap() - .query_wasm_smart(lp_contract.unwrap_or(&self.junoswap_token_contract), &query)?; - Ok(balance) - } - - /// Requirement: if using native token provide coins to sent as last argument - #[allow(clippy::too_many_arguments)] - pub fn provide_liquidity_to_junoswap_pool( - &mut self, - user: &str, - first_asset: u128, - second_asset: u128, - first_denom: Option, - second_denom: Option, - native_tokens: Vec, - ) -> AnyResult { - let owner = self.owner.to_string(); - - let assets = vec![ - ( - first_denom.unwrap_or_else(|| self.pool_denom1.clone()), - first_asset, - ), - ( - second_denom.unwrap_or_else(|| self.pool_denom2.clone()), - second_asset, - ), - ]; - for (denom, amount) in assets { - match denom { - Denom::Cw20(addr) => { - // Mint some initial balances for whale user - self.mint_cw20(&owner, &addr, amount, user).unwrap(); - // Increases allowances for given LP contracts in order to provide liquidity to pool - let spender = self.junoswap_pool_contract.to_string(); - self.increase_allowance(user, &addr, &spender, amount) - .unwrap(); - } - Denom::Native(denom) => { - self.app - .sudo(SudoMsg::Bank(BankSudo::Mint { - to_address: user.to_owned(), - amount: vec![coin(amount, denom)], - })) - .unwrap(); - } - } - } - - self.app.execute_contract( - Addr::unchecked(user), - self.junoswap_pool_contract.clone(), - &WasmswapExecuteMsg::AddLiquidity { - token1_amount: first_asset.into(), - min_liquidity: Uint128::new(100), - max_token2: second_asset.into(), - expiration: None, - }, - &native_tokens, - ) - } - - pub fn stake_junoswap_lp( - &mut self, - user: &str, - amount: Uint128, - lp_contract: Option<&Addr>, - staking_contract: Option<&Addr>, - ) -> AnyResult { - let msg = to_binary(&stake_cw20::msg::ReceiveMsg::Stake {})?; - self.app.execute_contract( - Addr::unchecked(user), - lp_contract - .unwrap_or(&self.junoswap_token_contract.clone()) - .to_owned(), - &cw20::Cw20ExecuteMsg::Send { - contract: staking_contract - .unwrap_or(&self.junoswap_staking_contract.clone()) - .to_string(), - amount, - msg, - }, - &[], - ) - } - - pub fn unstake_junoswap_lp( - &mut self, - user: &str, - amount: Uint128, - staking_contract: Option<&Addr>, - ) -> AnyResult { - self.app.execute_contract( - Addr::unchecked(user), - staking_contract - .unwrap_or(&self.junoswap_staking_contract) - .clone(), - &stake_cw20::msg::ExecuteMsg::Unstake { amount }, - &[], - ) - } - - #[allow(dead_code)] - pub fn query_stake_claims_for_pair(&mut self, address: String) -> ClaimsResponse { - let resp: ClaimsResponse = self - .app - .wrap() - .query_wasm_smart( - &self.junoswap_staking_contract, - &stake_cw20::msg::QueryMsg::Claims { address }, - ) - .unwrap(); - resp - } - - pub fn query_palomadex_pool(&mut self) -> PoolResponse { - self.app - .wrap() - .query_wasm_smart::(&self.palomadex_pair_contract, &PairQueryMsg::Pool {}) - .unwrap() - } - - pub fn total_palomadex_lp(&mut self) -> u128 { - let cw20::TokenInfoResponse { total_supply, .. } = self - .app - .wrap() - .query_wasm_smart( - &self.palomadex_token_contract, - &cw20::Cw20QueryMsg::TokenInfo {}, - ) - .unwrap(); - - total_supply.u128() - } - - pub fn palomadex_lp(&mut self, user: &str) -> u128 { - let cw20::BalanceResponse { balance } = self - .app - .wrap() - .query_wasm_smart( - &self.palomadex_token_contract, - &cw20::Cw20QueryMsg::Balance { - address: user.to_string(), - }, - ) - .unwrap(); - - balance.u128() - } - - // for debugging tests - #[allow(dead_code)] - pub fn palomadex_lp_holders(&mut self) -> Vec<(String, u128)> { - let cw20::AllAccountsResponse { accounts } = self - .app - .wrap() - .query_wasm_smart( - &self.palomadex_token_contract, - &cw20::Cw20QueryMsg::AllAccounts { - start_after: None, - limit: None, - }, - ) - .unwrap(); - accounts - .into_iter() - .map(|addr| (addr.clone(), self.palomadex_lp(&addr))) - .collect() - } - - pub fn total_palomadex_staked(&mut self) -> u128 { - let addr = self.palomadex_staking_contract.clone(); - self.palomadex_lp(addr.as_str()) - } - - pub fn palomadex_staked(&mut self, user: &str, unbonding_period: u64) -> u128 { - let palomadex_stake::msg::StakedResponse { stake, .. } = self - .app - .wrap() - .query_wasm_smart( - &self.palomadex_staking_contract, - &palomadex_stake::msg::QueryMsg::Staked { - address: user.to_string(), - unbonding_period, - }, - ) - .unwrap(); - - stake.u128() - } -} diff --git a/contracts/raw-migration/src/state.rs b/contracts/raw-migration/src/state.rs deleted file mode 100644 index 3e69e32..0000000 --- a/contracts/raw-migration/src/state.rs +++ /dev/null @@ -1,51 +0,0 @@ -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, Decimal, Uint128}; -use cw_storage_plus::Item; - -#[cw_serde] -pub struct MigrateConfig { - /// This is the address that can run ExecuteMsg::MigrateTokens - pub migrator: Addr, - /// This is how long it will be staked on PALOMA DEX - pub unbonding_period: u64, - - /// This is the junoswap pool where the LP will be withdrawn from - pub junoswap_pool: Addr, - - /// Can be deposited in any pool created by this factory - pub factory: Addr, - /// If set, only can be deposited in this pool (which must also be created by the factory) - pub palomadex_pool: Option, - - /// This is set when token migration is finished. - /// It is used to calculate the amount of LP tokens to give to each staker. - pub migrate_stakers_config: Option, -} - -/// The necessary information to migrate stakers. -#[cw_serde] -pub struct MigrateStakersConfig { - /// The palomadex LP token contract - pub lp_token: Addr, - /// The palomadex LP staking contract - pub staking_addr: Addr, - /// The total amount of palomadex LP tokens this contract received after token migration. - pub total_lp_tokens: Uint128, - /// The total amount of staked junoswap LP tokens. - pub total_staked: Uint128, -} - -/// Stores the contract configuration at the given key -pub const MIGRATION: Item = Item::new("migration"); - -/// This is set once MigrateTokens is called -pub const DESTINATION: Item = Item::new("destination"); - -#[cw_serde] -pub struct ExchangeConfig { - pub raw_to_grain_exchange_rate: Decimal, - pub raw_token: Addr, - pub grain_token: Addr, -} - -pub const EXCHANGE_CONFIG: Item = Item::new("exchange_config"); diff --git a/contracts/splitter/src/contract.rs b/contracts/splitter/src/contract.rs index e3b94fb..449fc66 100644 --- a/contracts/splitter/src/contract.rs +++ b/contracts/splitter/src/contract.rs @@ -6,9 +6,8 @@ use cosmwasm_std::{ }; use cw20::{BalanceResponse, Cw20ExecuteMsg, Cw20QueryMsg}; -use cw_utils::ensure_from_older_version; -use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; +use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use crate::state::{Config, CONFIG}; use crate::ContractError; @@ -358,7 +357,7 @@ mod tests { .init_balance( storage, &Addr::unchecked("owner"), - vec![coin(1_000_000, "ujuno"), coin(200_000, "grain")], + vec![coin(1_000_000, "ujuno"), coin(200_000, "ugrain")], ) .unwrap() }); @@ -395,7 +394,7 @@ mod tests { Addr::unchecked("owner"), BankMsg::Send { to_address: splitter_contract.to_string(), - amount: vec![coin(200_000, "grain")], + amount: vec![coin(200_000, "ugrain")], } .into(), ) @@ -406,7 +405,7 @@ mod tests { Addr::unchecked("owner"), splitter_contract, &ExecuteMsg::SendTokens { - native_denoms: vec!["ujuno".to_owned(), "grain".to_owned()], + native_denoms: vec!["ujuno".to_owned(), "ugrain".to_owned()], cw20_addresses: None, }, &[], @@ -417,13 +416,13 @@ mod tests { app.wrap() .query_all_balances("address1".to_owned()) .unwrap(), - vec![coin(330_000u128, "ujuno"), coin(66_000u128, "grain")] + vec![coin(66_000u128, "ugrain"), coin(330_000u128, "ujuno")] ); assert_eq!( app.wrap() .query_all_balances("address2".to_owned()) .unwrap(), - vec![coin(670_000u128, "ujuno"), coin(134_000u128, "grain")] + vec![coin(134_000u128, "ugrain"), coin(670_000u128, "ujuno")] ); } @@ -435,7 +434,7 @@ mod tests { .init_balance( storage, &Addr::unchecked("owner"), - vec![coin(1_000_000, "ujuno"), coin(200_000, "grain")], + vec![coin(1_000_000, "ujuno"), coin(200_000, "ugrain")], ) .unwrap() }); @@ -472,7 +471,7 @@ mod tests { Addr::unchecked("owner"), BankMsg::Send { to_address: splitter_contract.to_string(), - amount: vec![coin(200_000, "grain")], + amount: vec![coin(200_000, "ugrain")], } .into(), ) @@ -482,7 +481,7 @@ mod tests { Addr::unchecked("owner"), splitter_contract.clone(), &ExecuteMsg::SendTokens { - native_denoms: vec!["grain".to_owned()], + native_denoms: vec!["ugrain".to_owned()], cw20_addresses: None, }, &[], @@ -493,13 +492,13 @@ mod tests { app.wrap() .query_all_balances("address1".to_owned()) .unwrap(), - vec![coin(66_000u128, "grain")] + vec![coin(66_000u128, "ugrain")] ); assert_eq!( app.wrap() .query_all_balances("address2".to_owned()) .unwrap(), - vec![coin(134_000u128, "grain")] + vec![coin(134_000u128, "ugrain")] ); // make sure other tokens are still on splitter contract's balance assert_eq!( diff --git a/contracts/stake/src/contract.rs b/contracts/stake/src/contract.rs index 9df6ce1..b25deec 100644 --- a/contracts/stake/src/contract.rs +++ b/contracts/stake/src/contract.rs @@ -20,13 +20,12 @@ use crate::distribution::{ query_undistributed_rewards, query_withdraw_adjustment_data, query_withdrawable_rewards, }; use crate::utils::{create_undelegate_msg, CurveExt}; -use cw2::set_contract_version; -use cw_utils::{ensure_from_older_version, maybe_addr, Expiration}; +use cw_utils::{maybe_addr, Expiration}; use crate::error::ContractError; use crate::msg::{ AllStakedResponse, AnnualizedReward, AnnualizedRewardsResponse, BondingInfoResponse, - BondingPeriodInfo, ExecuteMsg, MigrateMsg, QueryMsg, RewardsPowerResponse, StakedResponse, + BondingPeriodInfo, ExecuteMsg, QueryMsg, RewardsPowerResponse, StakedResponse, TotalStakedResponse, TotalUnbondingResponse, UnbondAllResponse, }; use crate::state::{ diff --git a/contracts/stake/src/state.rs b/contracts/stake/src/state.rs index 161a009..907677a 100644 --- a/contracts/stake/src/state.rs +++ b/contracts/stake/src/state.rs @@ -251,7 +251,7 @@ impl Distribution { let totals = TOTAL_PER_PERIOD.load(storage).unwrap_or_default(); self.reward_multipliers .iter() - .zip(totals.into_iter()) + .zip(totals) .map( |(&(unbonding_period, multiplier), (unbonding_period2, total_stake))| { // sanity check diff --git a/packages/palomadex/src/asset.rs b/packages/palomadex/src/asset.rs index 37fd854..e67387a 100644 --- a/packages/palomadex/src/asset.rs +++ b/packages/palomadex/src/asset.rs @@ -242,9 +242,9 @@ impl fmt::Display for AssetInfo { /// ## Examples /// ``` /// # use cosmwasm_std::Addr; -/// # use wyndex::asset::AssetInfo::{Native, Token}; +/// # use palomadex::asset::AssetInfo::{Native, Token}; /// Token("terra...".to_string()); -/// Native(String::from("uluna")); +/// Native(String::from("ugrain")); /// ``` #[cw_serde] #[derive(Hash, Eq)] diff --git a/scripts/deploy/README.md b/scripts/deploy/README.md new file mode 100644 index 0000000..832d880 --- /dev/null +++ b/scripts/deploy/README.md @@ -0,0 +1,18 @@ +## PALOMADEX deploy script + +### Requirements + +npm, nodejs + +### How to use + +Check if configuration files in `configs` directory is correct. +When you run launch script: + +```bash +$ ./run.sh +``` + +it will check checksums of the contracts, then will proceed to store necessary wasm binaries. + +All necessary output is stored in `result.json` file. diff --git a/scripts/deploy/configs/factory_config.json b/scripts/deploy/configs/factory_config.json new file mode 100644 index 0000000..b4be6bc --- /dev/null +++ b/scripts/deploy/configs/factory_config.json @@ -0,0 +1,89 @@ +{ + "label": "palomadex-factory v2.2.0", + "instantiate": { + "owner": "paloma1zwskvpcpvplxacxef2ez5w9rpxcdkd54e9slnv", + "token_code_id": 17, + "pair_configs": [ + { + "code_id": 18, + "pair_type": { + "xyk": {} + }, + "fee_config": { + "total_fee_bps": 30, + "protocol_fee_bps": 3333 + }, + "is_disabled": false + }, + { + "code_id": 19, + "pair_type": { + "stable": {} + }, + "fee_config": { + "total_fee_bps": 10, + "protocol_fee_bps": 3333 + }, + "is_disabled": false + } + ], + "max_referral_commission": "0.05", + "fee_address": "paloma1zwskvpcpvplxacxef2ez5w9rpxcdkd54e9slnv", + "default_stake_config": { + "staking_code_id": 20, + "tokens_per_power": "1", + "min_bond": "1", + "unbonding_periods": [ + 86400, + 172800, + 259200, + 345600 + ], + "max_distributions": 6 + } + }, + "create_pairs": [ + { + "create_pair_and_distribution_flows": { + "pair_type": { + "xyk": {} + }, + "asset_infos": [ + { + "native": "ugrain" + }, + { + "token": "paloma1hw3ej0swtn6sm2anzlndkhkfd3xpltnrggc6rmj8y0v7pta8cqcq9tjlus" + } + ], + "staking_config": {}, + "distribution_flows": [ + { + "asset": { + "native": "ugrain" + }, + "rewards": [ + [ + 86400, + "0.25" + ], + [ + 172800, + "0.6" + ], + [ + 259200, + "0.8" + ], + [ + 345600, + "0.9" + ] + ], + "reward_duration": 86400 + } + ] + } + } + ] +} \ No newline at end of file diff --git a/scripts/deploy/configs/gauges_config.json b/scripts/deploy/configs/gauges_config.json new file mode 100644 index 0000000..cc9c8b0 --- /dev/null +++ b/scripts/deploy/configs/gauges_config.json @@ -0,0 +1,35 @@ +{ + "orchestrator": { + "label": "gauge orchestrator v1.3.0-beta", + "instantiate": { + "voting_powers": "paloma1al324k42hg47fz3qdnuy2s7wcfw8agny8gujmh", + "owner": "paloma1zwskvpcpvplxacxef2ez5w9rpxcdkd54e9slnv" + } + }, + "adapters": [ + { + "label": "gauge-adapter v1.3.0-beta ugrain", + "instantiate": { + "factory": "paloma1pt5d7rnkkz24sfutsld8c40r28py3jzgj95ml4ef7krtdr77xq0q47ufnv", + "rewards_asset": { + "info": { + "native": "ugrains" + }, + "amount": "10000" + }, + "epoch_length": 164000, + "owner": "paloma1zwskvpcpvplxacxef2ez5w9rpxcdkd54e9slnv" + } + } + ], + "gauges": [ + { + "create_gauge": { + "title": "gauge rewards paloma", + "adapter": "paloma1ttrgu24gmfxg0mymf02awyx2kaepvnz7k75zsn87s65kds86yepsc2g2ku", + "epoch_size": 86400, + "max_options_selected": 3 + } + } + ] +} \ No newline at end of file diff --git a/scripts/deploy/configs/multi_hop_config.json b/scripts/deploy/configs/multi_hop_config.json new file mode 100644 index 0000000..c2e4ae1 --- /dev/null +++ b/scripts/deploy/configs/multi_hop_config.json @@ -0,0 +1,6 @@ +{ + "label": "palomadex-multi-hop v0.4.0", + "instantiate": { + "wyndex_factory": "paloma1pt5d7rnkkz24sfutsld8c40r28py3jzgj95ml4ef7krtdr77xq0q47ufnv" + } +} \ No newline at end of file diff --git a/scripts/deploy/configs/paloma_config.json b/scripts/deploy/configs/paloma_config.json new file mode 100644 index 0000000..1aa2520 --- /dev/null +++ b/scripts/deploy/configs/paloma_config.json @@ -0,0 +1,7 @@ +{ + "chainId": "paloma-testnet-16", + "rpcEndpoint": "https://testnet.palomaswap.com", + "prefix": "paloma", + "gasPrice": "0.27ugrain", + "feeToken": "ugrain" +} diff --git a/scripts/deploy/contracts/checksum_cw20_base.txt b/scripts/deploy/contracts/checksum_cw20_base.txt new file mode 100644 index 0000000..c426c35 --- /dev/null +++ b/scripts/deploy/contracts/checksum_cw20_base.txt @@ -0,0 +1 @@ +b5160c638bd9b5ad87c58f325db290c32a4771b1320475c720b64d706d905a83 cw20_base.wasm diff --git a/scripts/deploy/contracts/checksum_gauge_orchestrator.txt b/scripts/deploy/contracts/checksum_gauge_orchestrator.txt new file mode 100644 index 0000000..fe31b18 --- /dev/null +++ b/scripts/deploy/contracts/checksum_gauge_orchestrator.txt @@ -0,0 +1 @@ +d42b87311c03cfea8ea852ae3abea2126a63d1a58daa2dcbdba5efda6435e849 gauge_orchestrator.wasm diff --git a/scripts/deploy/contracts/checksums.txt b/scripts/deploy/contracts/checksums.txt new file mode 100644 index 0000000..5e815b7 --- /dev/null +++ b/scripts/deploy/contracts/checksums.txt @@ -0,0 +1,9 @@ +617d5b327ceac83cd30856cb3dc2fb879df1bd2b930b6398a2f1a3df2613435d cw_placeholder.wasm +61e61387878442c263fe34436ad57480fe181f85282823d26caf838ae8b3b9fb cw_splitter.wasm +04dfe555e2c9222cce5940338c0f4ac6747b59ffd33b9b59635892a2ca1592fa gauge_adapter.wasm +8e1f226e005fd645a91028b593bf3f5b6274b126dca2ae3476d831131fce4b8a nominated_trader.wasm +381558c3101e56e817ae26b4124f60f3287806167a224e320af3176e184a4416 wyndex_factory.wasm +250bb9a0cfe2869f9fdd65e1e81bbe271f2659b92fcdf9973dc3dcb853345f3e wyndex_multi_hop.wasm +fa5d197c947739f5102c2e09b7aa9d51f8aed871f0f500786f6e7a0a3da71ccb wyndex_pair.wasm +115e0e7879eb4981ccc269844e075ea552c4ae537c0db68161555ab2804e5814 wyndex_pair_lsd.wasm +1ab43b4232284d46365ded23db0b184a74186ed3f6e0729e362798c093d7cb40 wyndex_stake.wasm diff --git a/scripts/deploy/contracts/checksums_intermediate.txt b/scripts/deploy/contracts/checksums_intermediate.txt new file mode 100644 index 0000000..b7b4ba4 --- /dev/null +++ b/scripts/deploy/contracts/checksums_intermediate.txt @@ -0,0 +1,6 @@ +f56e453979d6fa52e4c1b5bf02398b83032070ea429d2eb0ed483198cdf0d522 target/wasm32-unknown-unknown/release/gauge_adapter.wasm +61b4f6818de650680af26c3a3c16fceca0147970948f908fb0e174f8c2e49e36 target/wasm32-unknown-unknown/release/wyndex_factory.wasm +874181a20f75614428dc55c415500027c868dd9c2cb55414bc01e19bdb02b896 target/wasm32-unknown-unknown/release/wyndex_multi_hop.wasm +fc59b677676e0145794118a416d895574abc9764a806128040e5d49094a8c9a6 target/wasm32-unknown-unknown/release/wyndex_pair.wasm +674a4e6cb262b255a12680d8b45258fc3df1b07a96e51039426cd5f3d3de3597 target/wasm32-unknown-unknown/release/wyndex_pair_lsd.wasm +1645a4874f6fff87f15fc5e7e8eb1f9b13b3b19afc448645507b4b0ee7465f87 target/wasm32-unknown-unknown/release/wyndex_stake.wasm diff --git a/scripts/deploy/contracts/cw20_base.wasm b/scripts/deploy/contracts/cw20_base.wasm new file mode 100644 index 0000000..59b2dc2 Binary files /dev/null and b/scripts/deploy/contracts/cw20_base.wasm differ diff --git a/scripts/deploy/contracts/dao_dao_core.wasm b/scripts/deploy/contracts/dao_dao_core.wasm new file mode 100644 index 0000000..638a5bc Binary files /dev/null and b/scripts/deploy/contracts/dao_dao_core.wasm differ diff --git a/scripts/deploy/contracts/dao_proposal_single.wasm b/scripts/deploy/contracts/dao_proposal_single.wasm new file mode 100644 index 0000000..149258b Binary files /dev/null and b/scripts/deploy/contracts/dao_proposal_single.wasm differ diff --git a/scripts/deploy/contracts/gauge_adapter.wasm b/scripts/deploy/contracts/gauge_adapter.wasm new file mode 100644 index 0000000..ff08ce1 Binary files /dev/null and b/scripts/deploy/contracts/gauge_adapter.wasm differ diff --git a/scripts/deploy/contracts/gauge_orchestrator.wasm b/scripts/deploy/contracts/gauge_orchestrator.wasm new file mode 100644 index 0000000..686c8d7 Binary files /dev/null and b/scripts/deploy/contracts/gauge_orchestrator.wasm differ diff --git a/scripts/deploy/contracts/wynd_stake.wasm b/scripts/deploy/contracts/wynd_stake.wasm new file mode 100644 index 0000000..069c5d4 Binary files /dev/null and b/scripts/deploy/contracts/wynd_stake.wasm differ diff --git a/scripts/deploy/contracts/wyndex_factory.wasm b/scripts/deploy/contracts/wyndex_factory.wasm new file mode 100644 index 0000000..d8a468d Binary files /dev/null and b/scripts/deploy/contracts/wyndex_factory.wasm differ diff --git a/scripts/deploy/contracts/wyndex_multi_hop.wasm b/scripts/deploy/contracts/wyndex_multi_hop.wasm new file mode 100644 index 0000000..e435329 Binary files /dev/null and b/scripts/deploy/contracts/wyndex_multi_hop.wasm differ diff --git a/scripts/deploy/contracts/wyndex_pair.wasm b/scripts/deploy/contracts/wyndex_pair.wasm new file mode 100644 index 0000000..05e3531 Binary files /dev/null and b/scripts/deploy/contracts/wyndex_pair.wasm differ diff --git a/scripts/deploy/contracts/wyndex_pair_lsd.wasm b/scripts/deploy/contracts/wyndex_pair_lsd.wasm new file mode 100644 index 0000000..5aff244 Binary files /dev/null and b/scripts/deploy/contracts/wyndex_pair_lsd.wasm differ diff --git a/scripts/deploy/contracts/wyndex_pair_stable.wasm b/scripts/deploy/contracts/wyndex_pair_stable.wasm new file mode 100644 index 0000000..55e964c Binary files /dev/null and b/scripts/deploy/contracts/wyndex_pair_stable.wasm differ diff --git a/scripts/deploy/contracts/wyndex_stake.wasm b/scripts/deploy/contracts/wyndex_stake.wasm new file mode 100644 index 0000000..205a469 Binary files /dev/null and b/scripts/deploy/contracts/wyndex_stake.wasm differ diff --git a/scripts/deploy/index.js b/scripts/deploy/index.js new file mode 100755 index 0000000..972bdb0 --- /dev/null +++ b/scripts/deploy/index.js @@ -0,0 +1,432 @@ +#!/usr/bin/env -S yarn node + +/* eslint-disable @typescript-eslint/naming-convention */ +const { assertIsBroadcastTxSuccess, SigningCosmWasmClient, CosmWasmClient } = require("@cosmjs/cosmwasm-stargate"); +const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing"); +const { stringToPath } = require("@cosmjs/crypto"); +const { GasPrice, calculateFee } = require("@cosmjs/stargate"); + +const {env} = require("process"); + +const fs = require("fs"); +const stdio = require("stdio"); + +const factoryConfigPath = "configs/factory_config.json"; +const palomaConfigPath = "configs/paloma_config.json"; +const multiHopConfigPath = "configs/multi_hop_config.json"; +const gaugesConfigPath = "configs/gauges_config.json"; + +const factoryWasmPath = "/contracts/wyndex_factory.wasm"; +const gaugeAdapterWasmPath = "/contracts/gauge_adapter.wasm"; +const gaugeOrchestratorWasmPath = "/contracts/gauge_orchestrator.wasm"; +const multiHopWasmPath = "/contracts/wyndex_multi_hop.wasm"; +const pairWasmPath = "/contracts/wyndex_pair.wasm"; +const pairStableWasmPath = "/contracts/wyndex_pair_stable.wasm"; +const stakeWasmPath = "/contracts/wyndex_stake.wasm"; +const tokenWasmPath = "/contracts/cw20_base.wasm"; +const daoCoreWasmPath = "/contracts/dao_dao_core.wasm"; +const proposalSingleWasmPath = "/contracts/dao_proposal_single.wasm"; +const cw4StakeWasmPath = "/contracts/wynd_stake.wasm"; + +// Check "MNEMONIC" env variable and ensure it is set to a reasonable value +function getMnemonic() { + const mnemonic = env["MNEMONIC"]; + if (!mnemonic || mnemonic.length < 48) { + throw new Error("Must set MNEMONIC to a 12 word phrase"); + } + return mnemonic; +} + +// Function to read and parse JSON config file +function readJsonConfig(filePath) { + return JSON.parse(fs.readFileSync(filePath, 'utf8')); +} + +// Function to write JSON config file +function writeJsonConfig(filePath, data) { + fs.writeFileSync(filePath, JSON.stringify(data, null, 4), "utf8"); + console.info(`Updated ${filePath}`); +} + +async function connect(mnemonic, palomaConfig) { + const { prefix, gasPrice, feeToken, rpcEndpoint } = palomaConfig; + const hdPath = stringToPath("m/44'/118'/0'/0/0"); + + // Setup signer + const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix, hdPaths: [hdPath] }); + const [firstAccount] = await wallet.getAccounts(); + const address = firstAccount.address; + console.info(`Connected to ${address}`); + + // Init SigningCosmWasmClient client + try { + const client = await SigningCosmWasmClient.connectWithSigner(rpcEndpoint, wallet, { gasPrice: GasPrice.fromString(gasPrice) }); + const balance = await client.getBalance(address, feeToken); + console.info(`Balance: ${balance.amount} ${balance.denom}\n`); + + const chainId = await client.getChainId(); + console.info(`Chain ID: ${chainId}`); + + if (chainId !== palomaConfig.chainId) { + throw new Error("Given ChainId doesn't match the client's ChainID!"); + } + + return { client, address }; + } catch (error) { + console.error("Error during connectWithSigner:", error.message); + throw error; + } +} + +async function storeContract(client, wallet, gasPriceS, label, wasmPath) { + console.info('Storing ' + label + '...'); + + const gasPrice = GasPrice.fromString(gasPriceS); + const uploadFee = calculateFee(5_000_000, gasPrice); + + const wasmBinary = fs.readFileSync(__dirname + wasmPath); + const uploadReceipt = await client.upload( + wallet, + wasmBinary, + uploadFee, + "Upload " + label + " contract", + ); + console.info(label + " uploaded successfully. Receipt:\n" + JSON.stringify(uploadReceipt, (key, value) => + typeof value === 'bigint' ? value.toString() : value // Convert BigInt to string + ) + '\n'); + + return uploadReceipt.codeId; +} + +async function instantiateContract(client, wallet, gasPriceS, config, codeId) { + console.info('Instantiating ' + config.label + '...'); + + const gasPrice = GasPrice.fromString(gasPriceS); + const instantiateFee = calculateFee(500_000, gasPrice); + + const {contractAddress} = await client.instantiate( + wallet, + codeId, + config.instantiate, + config.label, + instantiateFee, + { + memo: "Instantiation " + config.label, + admin: wallet, + }, + ); + console.info(config.label + ` contract instantiated at ${contractAddress}\n`); + return contractAddress; +} + +async function createPairsAndDistributionFlows(client, wallet, gasPriceS, config, factoryAddress) { + console.info('Executing CreatePairAndDistributionFlows message...'); + + const gasPrice = GasPrice.fromString(gasPriceS); + const executeFee = calculateFee(1_500_000, gasPrice); + + let pairs = []; + + for (let i = 0; i < config.create_pairs.length; i++) { + const result = await client.execute( + wallet, + factoryAddress, + config.create_pairs[i], + executeFee + ); + + // Correctly filter the wasm events + const wasmEvents = result.events.filter((e) => e.type.trim() === "wasm"); + + if (wasmEvents.length === 0) { + console.error("No 'wasm' events found. Full result:", JSON.stringify(result, (key, value) => + typeof value === 'bigint' ? value.toString() : value, null, 2)); + throw new Error("No 'wasm' events found."); + } + + // Extract the relevant attributes from the wasm events + wasmEvents.forEach((event) => { + const pairName = event.attributes.find(attr => attr.key === 'pair'); + const pairAddress = event.attributes.find(attr => attr.key === 'pair_contract_addr'); + + if (pairName && pairAddress) { + const pairInfo = { + pairName: pairName.value, + pairAddress: pairAddress.value, + }; + console.info(`Pair initialized:\n${JSON.stringify(pairInfo, null, 4)}\n`); + pairs.push(pairInfo); + } + }); + } + + return pairs; +} + +async function instantiateDaoCoreWithModules(client, wallet, gasPriceS, daoCoreCodeId, cw4StakeCodeId, proposalSingleCodeId, cw20Contract) { + console.info('Instantiating DAO Core with modules...'); + + const gasPrice = GasPrice.fromString(gasPriceS); + const instantiateFee = calculateFee(1_000_000, gasPrice); + + // Corrected Voting Module Instantiate Message + const votingModuleInstantiateInfo = { + code_id: cw4StakeCodeId, + msg: Buffer.from(JSON.stringify({ + cw20_contract: cw20Contract, + tokens_per_power: "1000000", + min_bond: "1000000", + stake_config: [ + { + unbonding_period: 86400, // in seconds + voting_multiplier: "1.0", // as a string + reward_multiplier: "1.0" // as a string + } + ], + admin: null // No admin specified for the voting module + })).toString('base64'), + admin: { none: {} }, // Correct use of the "address" variant of Admin enum + label: "CW4 Stake Voting Module" + }; + + // Corrected Proposal Module Instantiate Message + const proposalModulesInstantiateInfo = [{ + code_id: proposalSingleCodeId, + msg: Buffer.from(JSON.stringify({ + threshold: { + threshold_quorum: { + quorum: { majority: {} }, // Correct use of the "majority" variant for quorum + threshold: { majority: {} } // Correct use of the "majority" variant for threshold + } + }, + max_voting_period: { time: 604800 }, // 7 days in seconds + min_voting_period: { time: 86400 }, // 1 day in seconds + allow_revoting: true, + deposit_info: { + token: { + token: { + address: cw20Contract // Correct token address for the deposit + } + }, + deposit: "1000", // Minimum deposit required as a string + refund_failed_proposals: true + }, + executor: { Only: wallet } // Correct use of the "Only" variant with a specific address + })).toString('base64'), + admin: { none: {} }, // Correct use of the "address" variant of Admin enum + label: "Proposal Single Module" + }]; + + // Prepare the DAO Core instantiation message + const daoCoreInstantiateMsg = { + admin: null, // This should be null or a valid address + name: "My DAO", + description: "Description of My DAO", + image_url: "https://example.com/image.png", + automatically_add_cw20s: true, + automatically_add_cw721s: true, + voting_module_instantiate_info: votingModuleInstantiateInfo, + proposal_modules_instantiate_info: proposalModulesInstantiateInfo, + initial_items: [], // Optional, adjust as needed + }; + + // Instantiate DAO Core with the voting and proposal modules + const { contractAddress: daoCoreAddress } = await client.instantiate( + wallet, + daoCoreCodeId, + daoCoreInstantiateMsg, + "DAO Core with Modules", + instantiateFee, + { + memo: "Instantiation of DAO Core with voting and proposal modules", + admin: null, // Set this to null if no admin is required after instantiation + } + ); + + console.info(`DAO Core instantiated at ${daoCoreAddress} with voting and proposal modules\n`); + return daoCoreAddress; +} + +async function instantiateGaugeAdapters(client, wallet, gasPriceS, codeId, config) { + console.info('Instantiating gauge adapters...'); + + const gasPrice = GasPrice.fromString(gasPriceS); + const instantiateFee = calculateFee(1_000_000, gasPrice); + + var adapters = []; + + for (var i = 0; i < config.length; i++) { + const {contractAddress} = await client.instantiate( + wallet, + codeId, + config[i].instantiate, + config[i].label, + instantiateFee, + { + memo: "Instantiation " + config[i].label, + admin: wallet, + }, + ); + console.info(config[i].label + ` contract instantiated at ${contractAddress}\n`); + const adapter = { + "label": config[i].label, + "address": contractAddress + }; + adapters.push(adapter); + }; + + return adapters; +} + +async function createGauges(client, wallet, gasPriceS, messages, gaugeOrchestratorAddress) { + console.info('Executing CreateGauge message...'); + + const gasPrice = GasPrice.fromString(gasPriceS); + const executeFee = calculateFee(1_000_000, gasPrice); + + for (var i = 0; i < messages.length; i++) { + const result = await client.execute( + wallet, + gaugeOrchestratorAddress, + messages[i], + executeFee + ); + console.info(`Gauge initialized: ${messages[i].create_gauge.title}\n`); + }; +} + +async function main() { + const mnemonic = getMnemonic(); + + const palomaConfig = JSON.parse(fs.readFileSync(palomaConfigPath, 'utf8')); + console.info(`Using paloma config:\n${JSON.stringify(palomaConfig, null, 4)}\n`); + + const {client, address} = await connect(mnemonic, palomaConfig); + + const factoryConfig = readJsonConfig(factoryConfigPath); + + // Store palomadex-stake, pair and pair-stable required for factory's instantiation + const tokenCodeId = 17; // await storeContract(client, address, palomaConfig.gasPrice, "token", tokenWasmPath); + const pairCodeId = 18; // await storeContract(client, address, palomaConfig.gasPrice, "pair", pairWasmPath); + const pairStableCodeId = 19; // await storeContract(client, address, palomaConfig.gasPrice, "pair-stable", pairStableWasmPath); + const stakeCodeId = 20; // await storeContract(client, address, palomaConfig.gasPrice, "stake", stakeWasmPath); + const factoryCodeId = 26; // await storeContract(client, address, palomaConfig.gasPrice, "factory", factoryWasmPath); + const multiHopCodeId = 27; // await storeContract(client, address, palomaConfig.gasPrice, "multi-hop", multiHopWasmPath); + const gaugeOrchestratorCodeId = 28; // await storeContract(client, address, palomaConfig.gasPrice, "gauge-orchestrator", gaugeOrchestratorWasmPath); + const gaugeAdapterCodeId = 29; // await storeContract(client, address, palomaConfig.gasPrice, "gauge-adapter", gaugeAdapterWasmPath); + + console.info("token_code_id: " + tokenCodeId); + console.info("pair_code_id: " + pairCodeId); + console.info("pair_stable_code_id: " + pairStableCodeId); + console.info("staking_code_id: " + stakeCodeId); + + // Update the config with new code IDs + factoryConfig.instantiate.token_code_id = tokenCodeId; + factoryConfig.instantiate.pair_configs[0].code_id = pairCodeId; + factoryConfig.instantiate.pair_configs[1].code_id = pairStableCodeId; + factoryConfig.instantiate.default_stake_config.staking_code_id = stakeCodeId; + + writeJsonConfig(factoryConfigPath, factoryConfig); + + + // CW20 token instantiation message with a high initial balance for the wallet + const cw20InstantiateMsg = { + name: "MyToken", + symbol: "MTK", + decimals: 6, + initial_balances: [{ + address: address, // The wallet address receiving the initial balance + amount: "1000000000" // Set a high initial balance for the wallet (1,000,000 MTK) + }], + mint: { + minter: address, + cap: null // No cap on minting + }, + marketing: null // Optional marketing information + }; + + // Instantiate CW20 Token Contract + const cw20TokenAddress = await instantiateContract(client, address, palomaConfig.gasPrice, { + label: "MyToken Contract", + instantiate: cw20InstantiateMsg + }, tokenCodeId); + + console.info(`CW20 token contract instantiated at ${cw20TokenAddress}`); + + // factory + const factoryAddress = await instantiateContract(client, address, palomaConfig.gasPrice, factoryConfig, factoryCodeId); + + // multi hop + const multiHopConfig = readJsonConfig(multiHopConfigPath); + multiHopConfig.instantiate.wyndex_factory = factoryAddress; + writeJsonConfig(multiHopConfigPath, multiHopConfig); + const multiHopAddress = await instantiateContract(client, address, palomaConfig.gasPrice, multiHopConfig, multiHopCodeId); + + // create pairs + const pairs = await createPairsAndDistributionFlows(client, address, palomaConfig.gasPrice, factoryConfig, factoryAddress); + + // INSTANTIATE THE DAO - DAO-CORE, CW-PROPOSAL-SINGLE AND WYND-STAKE + const daoCoreCodeId = 30; // await storeContract(client, address, palomaConfig.gasPrice, "dao-core", daoCoreWasmPath); + const proposalSingleCodeId = 31; // await storeContract(client, address, palomaConfig.gasPrice, "proposal-single", proposalSingleWasmPath); + const cw4StakeCodeId = 32; // await storeContract(client, address, palomaConfig.gasPrice, "cw4-stake", cw4StakeWasmPath); + + // Instantiate DAO Core and its modules + const daoCoreAddress = await instantiateDaoCoreWithModules(client, address, palomaConfig.gasPrice, daoCoreCodeId, cw4StakeCodeId, proposalSingleCodeId, cw20TokenAddress); + + console.info(`DAO Core and its modules have been successfully instantiated. DAO Core Address: ${daoCoreAddress}`); + + // gauges + // Update the gauges config + const gaugesConfig = readJsonConfig(gaugesConfigPath); + gaugesConfig.orchestrator.instantiate.owner = address; + gaugesConfig.adapters.forEach(adapter => { + adapter.instantiate.factory = factoryAddress; + }); + + // Instantiate gauge orchestrator + const gaugeOrchestratorAddress = await instantiateContract(client, address, palomaConfig.gasPrice, gaugesConfig.orchestrator, gaugeOrchestratorCodeId); + + const gaugeAdapters = await instantiateGaugeAdapters(client, address, palomaConfig.gasPrice, gaugeAdapterCodeId, gaugesConfig.adapters); + + gaugesConfig.gauges.forEach(gauge => { + gauge.create_gauge.adapter = gaugeAdapters[0].address; + }); + + // Save the updated gauges config with gauge orchestrator and adapters addresses + writeJsonConfig(gaugesConfigPath, gaugesConfig); + + const gauges = await createGauges(client, address, palomaConfig.gasPrice, gaugesConfig.gauges, gaugeOrchestratorAddress); + + // save output to logfile + const raport = { + tokenCodeId: tokenCodeId, + pairCodeId: pairCodeId, + pairStableCodeId: pairStableCodeId, + stakeCodeId: stakeCodeId, + multiHopCodeId: multiHopCodeId, + factoryCodeId: factoryCodeId, + gaugeOrchestratorCodeId: gaugeOrchestratorCodeId, + gaugeAdapterCodeId: gaugeAdapterCodeId, + factoryAddress: factoryAddress, + multiHopAddress: multiHopAddress, + pairs: pairs, + daoCore: daoCoreAddress, + gaugeOrchestratorAddress: gaugeOrchestratorAddress, + gaugeAdapters: gaugeAdapters, + gauges: gauges + }; + fs.writeFileSync("result.json", JSON.stringify(raport, null, 4), "utf8"); + console.info("Result was saved to result.json file!"); +} + +main().then( + () => { + console.info("All done, let the coins flow."); + process.exit(0); + }, + (error) => { + console.error(error); + process.exit(1); + }, +) + diff --git a/scripts/deploy/package-lock.json b/scripts/deploy/package-lock.json new file mode 100644 index 0000000..f49d6ad --- /dev/null +++ b/scripts/deploy/package-lock.json @@ -0,0 +1,761 @@ +{ + "name": "palomadex-deploy-script", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "palomadex-deploy-script", + "version": "0.1.0", + "license": "ISC", + "dependencies": { + "@cosmjs/cosmwasm-stargate": "^0.32.4", + "stdio": "^2.1.1" + } + }, + "node_modules/@confio/ics23": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@confio/ics23/-/ics23-0.6.8.tgz", + "integrity": "sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w==", + "license": "Apache-2.0", + "dependencies": { + "@noble/hashes": "^1.0.0", + "protobufjs": "^6.8.8" + } + }, + "node_modules/@cosmjs/amino": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.32.4.tgz", + "integrity": "sha512-zKYOt6hPy8obIFtLie/xtygCkH9ZROiQ12UHfKsOkWaZfPQUvVbtgmu6R4Kn1tFLI/SRkw7eqhaogmW/3NYu/Q==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4" + } + }, + "node_modules/@cosmjs/cosmwasm-stargate": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.32.4.tgz", + "integrity": "sha512-Fuo9BGEiB+POJ5WeRyBGuhyKR1ordvxZGLPuPosFJOH9U0gKMgcjwKMCgAlWFkMlHaTB+tNdA8AifWiHrI7VgA==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/amino": "^0.32.4", + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/proto-signing": "^0.32.4", + "@cosmjs/stargate": "^0.32.4", + "@cosmjs/tendermint-rpc": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "cosmjs-types": "^0.9.0", + "pako": "^2.0.2" + } + }, + "node_modules/@cosmjs/crypto": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.32.4.tgz", + "integrity": "sha512-zicjGU051LF1V9v7bp8p7ovq+VyC91xlaHdsFOTo2oVry3KQikp8L/81RkXmUIT8FxMwdx1T7DmFwVQikcSDIw==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers-sumo": "^0.7.11" + } + }, + "node_modules/@cosmjs/encoding": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.32.4.tgz", + "integrity": "sha512-tjvaEy6ZGxJchiizzTn7HVRiyTg1i4CObRRaTRPknm5EalE13SV+TCHq38gIDfyUeden4fCuaBVEdBR5+ti7Hw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "bech32": "^1.1.4", + "readonly-date": "^1.0.0" + } + }, + "node_modules/@cosmjs/json-rpc": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.32.4.tgz", + "integrity": "sha512-/jt4mBl7nYzfJ2J/VJ+r19c92mUKF0Lt0JxM3MXEJl7wlwW5haHAWtzRujHkyYMXOwIR+gBqT2S0vntXVBRyhQ==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/stream": "^0.32.4", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/math": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.32.4.tgz", + "integrity": "sha512-++dqq2TJkoB8zsPVYCvrt88oJWsy1vMOuSOKcdlnXuOA/ASheTJuYy4+oZlTQ3Fr8eALDLGGPhJI02W2HyAQaw==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0" + } + }, + "node_modules/@cosmjs/proto-signing": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.32.4.tgz", + "integrity": "sha512-QdyQDbezvdRI4xxSlyM1rSVBO2st5sqtbEIl3IX03uJ7YiZIQHyv6vaHVf1V4mapusCqguiHJzm4N4gsFdLBbQ==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/amino": "^0.32.4", + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "cosmjs-types": "^0.9.0" + } + }, + "node_modules/@cosmjs/socket": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.32.4.tgz", + "integrity": "sha512-davcyYziBhkzfXQTu1l5NrpDYv0K9GekZCC9apBRvL1dvMc9F/ygM7iemHjUA+z8tJkxKxrt/YPjJ6XNHzLrkw==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/stream": "^0.32.4", + "isomorphic-ws": "^4.0.1", + "ws": "^7", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/stargate": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.32.4.tgz", + "integrity": "sha512-usj08LxBSsPRq9sbpCeVdyLx2guEcOHfJS9mHGCLCXpdAPEIEQEtWLDpEUc0LEhWOx6+k/ChXTc5NpFkdrtGUQ==", + "license": "Apache-2.0", + "dependencies": { + "@confio/ics23": "^0.6.8", + "@cosmjs/amino": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/proto-signing": "^0.32.4", + "@cosmjs/stream": "^0.32.4", + "@cosmjs/tendermint-rpc": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "cosmjs-types": "^0.9.0", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/stream": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.32.4.tgz", + "integrity": "sha512-Gih++NYHEiP+oyD4jNEUxU9antoC0pFSg+33Hpp0JlHwH0wXhtD3OOKnzSfDB7OIoEbrzLJUpEjOgpCp5Z+W3A==", + "license": "Apache-2.0", + "dependencies": { + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/tendermint-rpc": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.32.4.tgz", + "integrity": "sha512-MWvUUno+4bCb/LmlMIErLypXxy7ckUuzEmpufYYYd9wgbdCXaTaO08SZzyFM5PI8UJ/0S2AmUrgWhldlbxO8mw==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/json-rpc": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/socket": "^0.32.4", + "@cosmjs/stream": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "axios": "^1.6.0", + "readonly-date": "^1.0.0", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/utils": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.32.4.tgz", + "integrity": "sha512-D1Yc+Zy8oL/hkUkFUL/bwxvuDBzRGpc4cF7/SkdhxX4iHpSLgdOuTt1mhCh9+kl6NQREy9t7SYZ6xeW5gFe60w==", + "license": "Apache-2.0" + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", + "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "license": "MIT" + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cosmjs-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.9.0.tgz", + "integrity": "sha512-MN/yUe6mkJwHnCFfsNPeCfXVhyxHYW6c/xDUzrSbBycYzw++XvWDMJArXp2pLdgD6FQ8DW79vkPjeNKVrXaHeQ==", + "license": "Apache-2.0" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.7", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", + "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/libsodium-sumo": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.15.tgz", + "integrity": "sha512-5tPmqPmq8T8Nikpm1Nqj0hBHvsLFCXvdhBFV7SGOitQPZAA6jso8XoL0r4L7vmfKXr486fiQInvErHtEvizFMw==", + "license": "ISC" + }, + "node_modules/libsodium-wrappers-sumo": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.15.tgz", + "integrity": "sha512-aSWY8wKDZh5TC7rMvEdTHoyppVq/1dTSAeAR7H6pzd6QRT3vQWcT5pGwCotLcpPEOLXX6VvqihSPkpEhYAjANA==", + "license": "ISC", + "dependencies": { + "libsodium-sumo": "^0.7.15" + } + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "license": "Apache-2.0" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/readonly-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz", + "integrity": "sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ==", + "license": "Apache-2.0" + }, + "node_modules/stdio": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stdio/-/stdio-2.1.3.tgz", + "integrity": "sha512-/kHgeGrbpKhHMbdejfJ7JrmwVWKORkoSrUzeYWPujnSfSlfa0FCOF6QLdRwG5P7/JNw8e9Ko2ECnH1lNf/ythw==", + "license": "MIT" + }, + "node_modules/symbol-observable": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz", + "integrity": "sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xstream": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/xstream/-/xstream-11.14.0.tgz", + "integrity": "sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw==", + "license": "MIT", + "dependencies": { + "globalthis": "^1.0.1", + "symbol-observable": "^2.0.3" + } + } + } +} diff --git a/scripts/deploy/package.json b/scripts/deploy/package.json new file mode 100644 index 0000000..d9746a1 --- /dev/null +++ b/scripts/deploy/package.json @@ -0,0 +1,16 @@ +{ + "name": "palomadex-deploy-script", + "version": "0.1.0", + "description": "Script that makes sure palomadex starts properly", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "deploy": "node index.js" + }, + "author": "Jakub Bogucki ", + "license": "ISC", + "dependencies": { + "@cosmjs/cosmwasm-stargate": "^0.32.4", + "stdio": "^2.1.1" + } +} diff --git a/scripts/deploy/run.sh b/scripts/deploy/run.sh new file mode 100755 index 0000000..142369a --- /dev/null +++ b/scripts/deploy/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +SCRIPT_DIR="$(realpath "$(dirname "$0")")" + +if [[ -z "${MNEMONIC}" ]]; then + echo "MNEMONIC env has not been set!" 1>&2 + exit 1 +fi + +npm install +npm run deploy