diff --git a/Cargo.lock b/Cargo.lock index 8400bd7e..54d4a821 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "autocfg" @@ -33,9 +33,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" @@ -96,9 +96,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmos-sdk-proto" @@ -113,9 +113,9 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bb3c77c3b7ce472056968c745eb501c440fbc07be5004eba02782c35bfbbe3" +checksum = "ad24bc9dae9aac5dc124b4560e3f7678729d701f1bf3cb11140703d91f247d31" dependencies = [ "digest 0.10.7", "ecdsa", @@ -127,18 +127,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea73e9162e6efde00018d55ed0061e93a108b5d6ec4548b4f8ce3c706249687" +checksum = "ca65635b768406eabdd28ba015cc3f2f863ca5a2677a7dc4c237b8ee1298efb3" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df41ea55f2946b6b43579659eec048cc2f66e8c8e2e3652fc5e5e476f673856" +checksum = "77e2a6ce6dbcad572495fd9d9c1072793fe682aebfcc09752c3b0de3fa1814d7" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43609e92ce1b9368aa951b334dd354a2d0dd4d484931a5f83ae10e12a26c8ba9" +checksum = "904408dc6d73fd1d535c764a55370803cccf6b9be5af7423c4db8967058673f0" dependencies = [ "proc-macro2", "quote", @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d6864742e3a7662d024b51a94ea81c9af21db6faea2f9a6d2232bb97c6e53e" +checksum = "1ed4564772e5d779235f2d7353e3d66e37793065c3a5155a2978256bf4c5b7d5" dependencies = [ "base64", "bech32", @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -475,9 +475,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] @@ -612,9 +612,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -641,6 +641,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hex" version = "0.4.3" @@ -682,9 +688,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "k256" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if", "ecdsa", @@ -696,9 +702,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.151" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "lido-core" @@ -789,6 +795,7 @@ dependencies = [ "cw2 1.1.2", "cw20", "lido-interchain-interceptor-base", + "lido-staking-base", "neutron-sdk", "prost", "prost-types", @@ -856,10 +863,13 @@ dependencies = [ "cosmwasm-std", "cosmwasm-storage", "cw-multi-test 0.20.0", + "cw-ownable", "cw-storage-plus 1.2.0", "cw721 0.18.0", "cw721-base 0.18.0", + "lido-interchain-interceptor-base", "neutron-sdk", + "thiserror", ] [[package]] @@ -899,6 +909,11 @@ dependencies = [ "cw-storage-plus 1.2.0", "cw2 1.1.2", "cw20", + "lido-distribution", + "lido-interchain-interceptor", + "lido-interchain-interceptor-base", + "lido-staking-base", + "lido-validators-set", "neutron-sdk", "prost", "prost-types", @@ -963,6 +978,7 @@ dependencies = [ "cw-storage-plus 1.2.0", "cw2 1.1.2", "cw20", + "lido-staking-base", "neutron-sdk", "prost", "prost-types", @@ -998,7 +1014,6 @@ dependencies = [ "schemars", "serde", "serde-json-wasm 1.0.0", - "sha2 0.10.8", "tendermint-proto", "thiserror", ] @@ -1027,7 +1042,6 @@ dependencies = [ "schemars", "serde", "serde-json-wasm 1.0.0", - "sha2 0.10.8", "tendermint-proto", "thiserror", ] @@ -1035,16 +1049,20 @@ dependencies = [ [[package]] name = "neutron-sdk" version = "0.7.0" -source = "git+https://github.com/neutron-org/neutron-sdk?rev=0312d1edfcdca00818e85fc14504be9479efd5ee#0312d1edfcdca00818e85fc14504be9479efd5ee" +source = "git+https://github.com/neutron-org/neutron-sdk?rev=9f0ed09746b4cc75e902315b0a0d5a3e0e5350a7#9f0ed09746b4cc75e902315b0a0d5a3e0e5350a7" dependencies = [ "bech32", "cosmos-sdk-proto", "cosmwasm-schema", "cosmwasm-std", + "prost", + "prost-types", "protobuf", "schemars", "serde", "serde-json-wasm 1.0.0", + "speedate", + "tendermint-proto", "thiserror", ] @@ -1104,9 +1122,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -1131,7 +1149,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -1165,9 +1183,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1197,6 +1215,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.16" @@ -1243,15 +1267,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] @@ -1276,22 +1300,22 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] @@ -1307,9 +1331,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -1350,6 +1374,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "speedate" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "242f76c50fd18cbf098607090ade73a08d39cfd84ea835f3796a2c855223b19b" +dependencies = [ + "strum", + "strum_macros", +] + [[package]] name = "spki" version = "0.7.3" @@ -1366,6 +1400,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + [[package]] name = "subtle" version = "2.5.0" @@ -1394,9 +1450,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.40" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -1423,29 +1479,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.48", ] [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "powerfmt", @@ -1461,9 +1517,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] diff --git a/Cargo.toml b/Cargo.toml index f34d5b1c..f9dbfdba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ resolver = "2" cosmos-sdk-proto = { version = "0.20.0", default-features = false } base64 = "0.21.2" cw-ownable = "0.5.1" -neutron-sdk = { package = "neutron-sdk", git = "https://github.com/neutron-org/neutron-sdk", rev = "0312d1edfcdca00818e85fc14504be9479efd5ee" } +neutron-sdk = { package = "neutron-sdk", git = "https://github.com/neutron-org/neutron-sdk", rev = "9f0ed09746b4cc75e902315b0a0d5a3e0e5350a7" } prost = "0.12.1" prost-types = "0.12.1" protobuf = "3.2.0" diff --git a/contracts/distribution/src/contract.rs b/contracts/distribution/src/contract.rs index 4d8767b0..d28cf31a 100644 --- a/contracts/distribution/src/contract.rs +++ b/contracts/distribution/src/contract.rs @@ -1,13 +1,9 @@ -use cosmwasm_std::{entry_point, to_json_binary, Attribute, Decimal, Deps, Uint128}; +use cosmwasm_std::{entry_point, to_json_binary, Decimal, Deps, Event, Uint128}; use cosmwasm_std::{Binary, DepsMut, Env, MessageInfo, Response}; use cw2::set_contract_version; -use lido_staking_base::helpers::answer::response; +use lido_staking_base::error::distribution::{ContractError, ContractResult}; use lido_staking_base::msg::distribution::{Delegation, IdealDelegation, InstantiateMsg, QueryMsg}; use neutron_sdk::bindings::msg::NeutronMsg; -use neutron_sdk::bindings::query::NeutronQuery; -use neutron_sdk::NeutronResult; - -use crate::error::{ContractError, ContractResult}; const CONTRACT_NAME: &str = concat!("crates.io:lido-staking__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -18,16 +14,14 @@ pub fn instantiate( _env: Env, _info: MessageInfo, _msg: InstantiateMsg, -) -> NeutronResult> { +) -> ContractResult> { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - let empty_attr: Vec = Vec::new(); - - Ok(response("instantiate", CONTRACT_NAME, empty_attr)) + Ok(Response::new().add_event(Event::new(format!("{}-{}", CONTRACT_NAME, "instantiate")))) } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult { +pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult { match msg { QueryMsg::CalcDeposit { deposit, diff --git a/contracts/distribution/src/lib.rs b/contracts/distribution/src/lib.rs index eacc6df2..7380e09b 100644 --- a/contracts/distribution/src/lib.rs +++ b/contracts/distribution/src/lib.rs @@ -1,5 +1,4 @@ pub mod contract; -pub mod error; #[cfg(test)] mod tests; diff --git a/contracts/distribution/src/tests.rs b/contracts/distribution/src/tests.rs index 158d05cd..6cc750c8 100644 --- a/contracts/distribution/src/tests.rs +++ b/contracts/distribution/src/tests.rs @@ -1,12 +1,11 @@ use cosmwasm_std::{ testing::{mock_env, MockApi, MockQuerier, MockStorage}, - to_json_binary, OwnedDeps, Querier, Uint128, + to_json_binary, Empty, OwnedDeps, Querier, Uint128, }; use lido_staking_base::msg::distribution::{Delegation, IdealDelegation, QueryMsg}; -use neutron_sdk::bindings::query::NeutronQuery; use std::marker::PhantomData; -fn mock_dependencies() -> OwnedDeps { +fn mock_dependencies() -> OwnedDeps { OwnedDeps { storage: MockStorage::default(), api: MockApi::default(), diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index e3f23455..08bba74e 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -12,10 +12,13 @@ use cw2::set_contract_version; use lido_staking_base::{ helpers::answer::response, msg::core::{ExecuteMsg as CoreExecuteMsg, InstantiateMsg as CoreInstantiateMsg}, + msg::distribution::InstantiateMsg as DistributionInstantiateMsg, + msg::strategy::InstantiateMsg as StrategyInstantiateMsg, msg::token::{ ConfigResponse as TokenConfigResponse, InstantiateMsg as TokenInstantiateMsg, QueryMsg as TokenQueryMsg, }, + msg::validatorset::InstantiateMsg as ValidatorsSetInstantiateMsg, msg::withdrawal_manager::InstantiateMsg as WithdrawalManagerInstantiateMsg, msg::withdrawal_voucher::InstantiateMsg as WithdrawalVoucherInstantiateMsg, }; @@ -44,6 +47,9 @@ pub fn instantiate( core_code_id: msg.core_code_id, withdrawal_voucher_code_id: msg.withdrawal_voucher_code_id, withdrawal_manager_code_id: msg.withdrawal_manager_code_id, + strategy_code_id: msg.strategy_code_id, + validators_set_code_id: msg.validators_set_code_id, + distribution_code_id: msg.distribution_code_id, owner: info.sender.to_string(), subdenom: msg.subdenom.to_string(), }, @@ -61,6 +67,12 @@ pub fn instantiate( "withdrawal_manager_code_id", msg.withdrawal_manager_code_id.to_string(), ), + attr("strategy_code_id", msg.strategy_code_id.to_string()), + attr( + "validators_set_code_id", + msg.validators_set_code_id.to_string(), + ), + attr("distribution_code_id", msg.distribution_code_id.to_string()), attr("owner", info.sender), attr("subdenom", msg.subdenom), ]; @@ -109,6 +121,12 @@ fn execute_init( get_code_checksum(deps.as_ref(), config.withdrawal_voucher_code_id)?; let withdrawal_manager_contract_checksum = get_code_checksum(deps.as_ref(), config.withdrawal_manager_code_id)?; + let strategy_contract_checksum = get_code_checksum(deps.as_ref(), config.strategy_code_id)?; + let validators_set_contract_checksum = + get_code_checksum(deps.as_ref(), config.validators_set_code_id)?; + let distribution_contract_checksum = + get_code_checksum(deps.as_ref(), config.distribution_code_id)?; + let salt = config.salt.as_bytes(); let token_address = @@ -117,6 +135,7 @@ fn execute_init( let core_address = instantiate2_address(&core_contract_checksum, &canonical_self_address, salt)?; attrs.push(attr("core_address", core_address.to_string())); + let withdrawal_voucher_address = instantiate2_address( &withdrawal_voucher_contract_checksum, &canonical_self_address, @@ -126,6 +145,7 @@ fn execute_init( "withdrawal_voucher_address", withdrawal_voucher_address.to_string(), )); + let withdrawal_manager_address = instantiate2_address( &withdrawal_manager_contract_checksum, &canonical_self_address, @@ -136,6 +156,35 @@ fn execute_init( withdrawal_manager_address.to_string(), )); + let strategy_address = + instantiate2_address(&strategy_contract_checksum, &canonical_self_address, salt)?; + attrs.push(attr("strategy_address", strategy_address.to_string())); + + let validators_set_address = instantiate2_address( + &validators_set_contract_checksum, + &canonical_self_address, + salt, + )?; + attrs.push(attr( + "validators_set_address", + validators_set_address.to_string(), + )); + + attrs.push(attr( + "withdrawal_voucher_address", + withdrawal_voucher_address.to_string(), + )); + + let distribution_address = instantiate2_address( + &distribution_contract_checksum, + &canonical_self_address, + salt, + )?; + attrs.push(attr( + "distribution_address", + distribution_address.to_string(), + )); + let core_contract = deps.api.addr_humanize(&core_address)?.to_string(); let token_contract = deps.api.addr_humanize(&token_address)?.to_string(); let withdrawal_voucher_contract = deps @@ -146,11 +195,18 @@ fn execute_init( .api .addr_humanize(&withdrawal_manager_address)? .to_string(); + let strategy_contract = deps.api.addr_humanize(&strategy_address)?.to_string(); + let validators_set_contract = deps.api.addr_humanize(&validators_set_address)?.to_string(); + let distribution_contract = deps.api.addr_humanize(&distribution_address)?.to_string(); + let state = State { token_contract: token_contract.to_string(), core_contract: core_contract.to_string(), withdrawal_voucher_contract: withdrawal_voucher_contract.to_string(), withdrawal_manager_contract: withdrawal_manager_contract.to_string(), + strategy_contract: strategy_contract.to_string(), + validators_set_contract: validators_set_contract.to_string(), + distribution_contract: distribution_contract.to_string(), }; STATE.save(deps.storage, &state)?; @@ -166,14 +222,47 @@ fn execute_init( funds: vec![], salt: Binary::from(salt), }), + CosmosMsg::Wasm(WasmMsg::Instantiate2 { + admin: Some(env.contract.address.to_string()), + code_id: config.validators_set_code_id, + label: "validators set".to_string(), + msg: to_json_binary(&ValidatorsSetInstantiateMsg { + stats_contract: "neutron1x69dz0c0emw8m2c6kp5v6c08kgjxmu30f4a8w5".to_string(), //FIXME: mock address, replace with real one + core: env.contract.address.to_string(), + })?, + funds: vec![], + salt: Binary::from(salt), + }), + CosmosMsg::Wasm(WasmMsg::Instantiate2 { + admin: Some(env.contract.address.to_string()), + code_id: config.distribution_code_id, + label: "distribution".to_string(), + msg: to_json_binary(&DistributionInstantiateMsg {})?, + funds: vec![], + salt: Binary::from(salt), + }), + CosmosMsg::Wasm(WasmMsg::Instantiate2 { + admin: Some(env.contract.address.to_string()), + code_id: config.strategy_code_id, + label: "strategy".to_string(), + msg: to_json_binary(&StrategyInstantiateMsg { + core_address: env.contract.address.to_string(), + puppeteer_address: "neutron1x69dz0c0emw8m2c6kp5v6c08kgjxmu30f4a8w5".to_string(), //FIXME: mock address, replace with real one + validator_set_address: validators_set_contract.to_string(), + distribution_address: distribution_contract.to_string(), + denom: "uatom".to_string(), + })?, + funds: vec![], + salt: Binary::from(salt), + }), CosmosMsg::Wasm(WasmMsg::Instantiate2 { admin: Some(env.contract.address.to_string()), code_id: config.core_code_id, label: get_contract_label("core"), msg: to_json_binary(&CoreInstantiateMsg { token_contract: token_contract.to_string(), - puppeteer_contract: "".to_string(), - strategy_contract: "".to_string(), + puppeteer_contract: "neutron1x69dz0c0emw8m2c6kp5v6c08kgjxmu30f4a8w5".to_string(), //FIXME: mock address, replace with real one + strategy_contract: strategy_contract.to_string(), withdrawal_voucher_contract: withdrawal_voucher_contract.to_string(), withdrawal_manager_contract: withdrawal_manager_contract.to_string(), base_denom: base_denom.to_string(), diff --git a/contracts/factory/src/msg.rs b/contracts/factory/src/msg.rs index e121573f..c12b6c7c 100644 --- a/contracts/factory/src/msg.rs +++ b/contracts/factory/src/msg.rs @@ -8,6 +8,9 @@ pub struct InstantiateMsg { pub core_code_id: u64, pub withdrawal_voucher_code_id: u64, pub withdrawal_manager_code_id: u64, + pub strategy_code_id: u64, + pub validators_set_code_id: u64, + pub distribution_code_id: u64, pub salt: String, pub subdenom: String, } diff --git a/contracts/factory/src/state.rs b/contracts/factory/src/state.rs index fdc4442d..0c4db724 100644 --- a/contracts/factory/src/state.rs +++ b/contracts/factory/src/state.rs @@ -7,6 +7,9 @@ pub struct Config { pub core_code_id: u64, pub withdrawal_voucher_code_id: u64, pub withdrawal_manager_code_id: u64, + pub strategy_code_id: u64, + pub validators_set_code_id: u64, + pub distribution_code_id: u64, pub owner: String, pub salt: String, pub subdenom: String, @@ -18,6 +21,9 @@ pub struct State { pub core_contract: String, pub withdrawal_voucher_contract: String, pub withdrawal_manager_contract: String, + pub strategy_contract: String, + pub validators_set_contract: String, + pub distribution_contract: String, } pub const CONFIG: Item = Item::new("config"); diff --git a/contracts/interchain-interceptor-authz/src/contract.rs b/contracts/interchain-interceptor-authz/src/contract.rs index d8abf2f0..5066ccc3 100644 --- a/contracts/interchain-interceptor-authz/src/contract.rs +++ b/contracts/interchain-interceptor-authz/src/contract.rs @@ -44,7 +44,7 @@ pub fn instantiate( _env: Env, _info: MessageInfo, msg: InstantiateMsg, -) -> NeutronResult { +) -> ContractResult { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; let owner = deps.api.addr_validate(&msg.owner)?; @@ -62,7 +62,7 @@ pub fn instantiate( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> ContractResult { InterchainInterceptor::default().query(deps, env, msg) } diff --git a/contracts/interchain-interceptor/Cargo.toml b/contracts/interchain-interceptor/Cargo.toml index f7820810..3ed94f94 100644 --- a/contracts/interchain-interceptor/Cargo.toml +++ b/contracts/interchain-interceptor/Cargo.toml @@ -41,6 +41,7 @@ serde = { workspace = true } serde-json-wasm = { workspace = true } lido-interchain-interceptor-base = { workspace = true } +lido-staking-base = { workspace = true } [dev-dependencies] cosmwasm-storage = { workspace = true } diff --git a/contracts/interchain-interceptor/src/bin/lido-interchain-interceptor-schema.rs b/contracts/interchain-interceptor/src/bin/lido-interchain-interceptor-schema.rs index b9158641..3e45f18d 100644 --- a/contracts/interchain-interceptor/src/bin/lido-interchain-interceptor-schema.rs +++ b/contracts/interchain-interceptor/src/bin/lido-interchain-interceptor-schema.rs @@ -1,8 +1,7 @@ use cosmwasm_schema::write_api; - -use lido_interchain_interceptor::{ - msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}, - state::QueryMsg, +use lido_staking_base::{ + msg::puppeteer::{ExecuteMsg, InstantiateMsg, MigrateMsg}, + state::puppeteer::QueryMsg, }; fn main() { diff --git a/contracts/interchain-interceptor/src/contract.rs b/contracts/interchain-interceptor/src/contract.rs index 1038493b..cf58a9d4 100644 --- a/contracts/interchain-interceptor/src/contract.rs +++ b/contracts/interchain-interceptor/src/contract.rs @@ -8,6 +8,10 @@ use cosmos_sdk_proto::cosmos::{ use cosmwasm_std::{entry_point, to_json_vec, CosmosMsg, Deps, Reply, StdError, SubMsg, Uint128}; use cosmwasm_std::{Binary, DepsMut, Env, MessageInfo, Response, StdResult}; use cw2::set_contract_version; +use lido_staking_base::{ + msg::puppeteer::{ExecuteMsg, InstantiateMsg, MigrateMsg, Transaction}, + state::puppeteer::Config, +}; use neutron_sdk::{ bindings::{ msg::{IbcFee, NeutronMsg}, @@ -28,13 +32,11 @@ use lido_interchain_interceptor_base::{ use prost::Message; use crate::{ - msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, Transaction}, proto::cosmos::base::v1beta1::Coin as ProtoCoin, proto::liquidstaking::staking::v1beta1::{ MsgBeginRedelegate, MsgRedeemTokensforShares as MsgRedeemTokensForShares, MsgTokenizeShares, MsgTokenizeSharesResponse, }, - state::Config, }; pub type InterchainInterceptor<'a> = InterchainIntercaptorBase<'a, Config, Transaction>; @@ -49,7 +51,7 @@ pub fn instantiate( _env: Env, _info: MessageInfo, msg: InstantiateMsg, -) -> NeutronResult { +) -> ContractResult { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; let owner = deps.api.addr_validate(&msg.owner)?; @@ -66,7 +68,7 @@ pub fn instantiate( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> ContractResult { InterchainInterceptor::default().query(deps, env, msg) } diff --git a/contracts/interchain-interceptor/src/lib.rs b/contracts/interchain-interceptor/src/lib.rs index 40655591..635a32ff 100644 --- a/contracts/interchain-interceptor/src/lib.rs +++ b/contracts/interchain-interceptor/src/lib.rs @@ -1,4 +1,2 @@ pub mod contract; -pub mod msg; pub mod proto; -pub mod state; diff --git a/contracts/strategy/Cargo.toml b/contracts/strategy/Cargo.toml index 64aef682..5f15a9d6 100644 --- a/contracts/strategy/Cargo.toml +++ b/contracts/strategy/Cargo.toml @@ -40,6 +40,12 @@ serde = { workspace = true } serde-json-wasm = { workspace = true } neutron-sdk = { workspace = true } +lido-staking-base = { workspace = true } +lido-interchain-interceptor-base = { workspace = true } + +lido-distribution = { path = "../distribution", default-features = false } +lido-interchain-interceptor = { path = "../interchain-interceptor", default-features = false } +lido-validators-set = { path = "../validators-set", default-features = false } [dev-dependencies] cosmwasm-storage = { workspace = true } diff --git a/contracts/strategy/src/bin/lido-strategy-schema.rs b/contracts/strategy/src/bin/lido-strategy-schema.rs index db99997c..ef939945 100644 --- a/contracts/strategy/src/bin/lido-strategy-schema.rs +++ b/contracts/strategy/src/bin/lido-strategy-schema.rs @@ -1,7 +1,7 @@ use cosmwasm_schema::write_api; -use lido_strategy::{ - msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}, - state::QueryMsg, +use lido_staking_base::msg::{ + distribution::QueryMsg, + strategy::{ExecuteMsg, InstantiateMsg, MigrateMsg}, }; fn main() { diff --git a/contracts/strategy/src/contract.rs b/contracts/strategy/src/contract.rs index 60be576c..3f372c32 100644 --- a/contracts/strategy/src/contract.rs +++ b/contracts/strategy/src/contract.rs @@ -1,15 +1,16 @@ -use cosmwasm_std::{entry_point, to_json_binary, Deps}; +use std::collections::HashMap; + +use cosmwasm_std::{attr, entry_point, to_json_binary, Attribute, Deps, Uint128}; use cosmwasm_std::{Binary, DepsMut, Env, MessageInfo, Response, StdResult}; use cw2::set_contract_version; -use neutron_sdk::bindings::msg::NeutronMsg; -use neutron_sdk::bindings::query::NeutronQuery; -use neutron_sdk::NeutronResult; - -use crate::state::{QueryMsg, CONFIG}; -use crate::{ - msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}, - state::Config, +use lido_staking_base::helpers::answer::response; +use lido_staking_base::msg::strategy::{ + ConfigResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, }; +use lido_staking_base::state::strategy::{ + CORE_ADDRESS, DENOM, DISTRIBUTION_ADDRESS, PUPPETEER_ADDRESS, VALIDATOR_SET_ADDRESS, +}; +use neutron_sdk::NeutronResult; const CONTRACT_NAME: &str = concat!("crates.io:lido-staking__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -22,38 +23,204 @@ pub fn instantiate( msg: InstantiateMsg, ) -> NeutronResult { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + let core = deps.api.addr_validate(&msg.core_address)?; + cw_ownable::initialize_owner(deps.storage, deps.api, Some(core.as_ref()))?; + CORE_ADDRESS.save(deps.storage, &core)?; - let owner = deps.api.addr_validate(&msg.owner)?; + let puppeteer = deps.api.addr_validate(&msg.puppeteer_address)?; + PUPPETEER_ADDRESS.save(deps.storage, &puppeteer)?; - cw_ownable::initialize_owner(deps.storage, deps.api, Some(&msg.owner))?; + let validator_set = deps.api.addr_validate(&msg.validator_set_address)?; + VALIDATOR_SET_ADDRESS.save(deps.storage, &validator_set)?; - let config = &Config { owner }; + let distribution = deps.api.addr_validate(&msg.distribution_address)?; + DISTRIBUTION_ADDRESS.save(deps.storage, &distribution)?; - CONFIG.save(deps.storage, config)?; + DENOM.save(deps.storage, &msg.denom)?; - Ok(Response::default()) + Ok(response( + "instantiate", + CONTRACT_NAME, + [ + attr("core_address", msg.core_address), + attr("puppeteer_address", msg.puppeteer_address), + attr("validator_set_address", msg.validator_set_address), + attr("distribution_address", msg.distribution_address), + attr("denom", msg.denom), + ], + )) } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> NeutronResult { match msg { QueryMsg::Config {} => query_config(deps, env), + QueryMsg::CalcDeposit { deposit } => query_calc_deposit(deps, deposit), + QueryMsg::CalcWithdraw { withdraw } => query_calc_withdraw(deps, withdraw), } } -fn query_config(deps: Deps, _env: Env) -> StdResult { - let config = CONFIG.load(deps.storage)?; - to_json_binary(&config) +fn query_config(deps: Deps, _env: Env) -> NeutronResult { + let core_address = CORE_ADDRESS.load(deps.storage)?.into_string(); + let puppeteer_address = PUPPETEER_ADDRESS.load(deps.storage)?.into_string(); + let validator_set_address = VALIDATOR_SET_ADDRESS.load(deps.storage)?.into_string(); + let distribution_address = DISTRIBUTION_ADDRESS.load(deps.storage)?.into_string(); + let denom = DENOM.load(deps.storage)?; + + Ok(to_json_binary(&ConfigResponse { + core_address, + puppeteer_address, + validator_set_address, + distribution_address, + denom, + })?) +} + +pub fn query_calc_deposit(deps: Deps, deposit: Uint128) -> NeutronResult { + let distribution_address = DISTRIBUTION_ADDRESS.load(deps.storage)?.into_string(); + + let delegations: Vec = + prepare_delegation_data(deps)?; + + let ideal_deposit: Vec = + deps.querier.query_wasm_smart( + distribution_address, + &lido_staking_base::msg::distribution::QueryMsg::CalcDeposit { + deposit, + delegations, + }, + )?; + + Ok(to_json_binary(&ideal_deposit)?) +} + +pub fn query_calc_withdraw(deps: Deps, withdraw: Uint128) -> NeutronResult { + let distribution_address = DISTRIBUTION_ADDRESS.load(deps.storage)?.into_string(); + + let delegations: Vec = + prepare_delegation_data(deps)?; + + let ideal_deposit: Vec = + deps.querier.query_wasm_smart( + distribution_address, + &lido_staking_base::msg::distribution::QueryMsg::CalcWithdraw { + withdraw, + delegations, + }, + )?; + + Ok(to_json_binary(&ideal_deposit)?) +} + +fn prepare_delegation_data( + deps: Deps, +) -> NeutronResult> { + let puppeteer_address = PUPPETEER_ADDRESS.load(deps.storage)?.into_string(); + let validator_set_address = VALIDATOR_SET_ADDRESS.load(deps.storage)?.into_string(); + let denom = DENOM.load(deps.storage)?; + + let account_delegations: lido_interchain_interceptor_base::msg::DelegationsResponse = + deps.querier.query_wasm_smart( + &puppeteer_address, + &lido_interchain_interceptor_base::msg::QueryMsg::Delegations {}, + )?; + + let validator_set: Vec = + deps.querier.query_wasm_smart( + &validator_set_address, + &lido_staking_base::msg::validatorset::QueryMsg::Validators {}, + )?; + + let mut delegations: Vec = Vec::new(); + let delegation_validator_map: HashMap<_, _> = account_delegations + .delegations + .iter() + .filter(|delegation| delegation.amount.denom == denom) + .map(|delegation| (delegation.validator.clone(), delegation.amount.amount)) + .collect(); + + for validator in validator_set.iter() { + let validator_denom_delegation = delegation_validator_map + .get(&validator.valoper_address) + .copied() + .unwrap_or_default(); + + let delegation = lido_staking_base::msg::distribution::Delegation { + valoper_address: validator.valoper_address.clone(), + stake: validator_denom_delegation, + weight: validator.weight, + }; + + delegations.push(delegation); + } + + Ok(delegations) } #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( - _deps: DepsMut, + deps: DepsMut, _env: Env, _info: MessageInfo, msg: ExecuteMsg, -) -> NeutronResult> { - match msg {} +) -> NeutronResult { + match msg { + ExecuteMsg::UpdateConfig { + core_address, + puppeteer_address, + validator_set_address, + distribution_address, + denom, + } => exec_config_update( + deps, + core_address, + puppeteer_address, + validator_set_address, + distribution_address, + denom, + ), + } +} + +fn exec_config_update( + deps: DepsMut, + core_address: Option, + puppeteer_address: Option, + validator_set_address: Option, + distribution_address: Option, + denom: Option, +) -> NeutronResult { + let mut attrs: Vec = Vec::new(); + if let Some(core_address) = core_address { + let core_address = deps.api.addr_validate(&core_address)?; + CORE_ADDRESS.save(deps.storage, &core_address)?; + attrs.push(attr("core_address", core_address)) + } + + if let Some(puppeteer_address) = puppeteer_address { + let puppeteer_address = deps.api.addr_validate(&puppeteer_address)?; + PUPPETEER_ADDRESS.save(deps.storage, &puppeteer_address)?; + attrs.push(attr("puppeteer_address", puppeteer_address)) + } + + if let Some(validator_set_address) = validator_set_address { + let validator_set_address = deps.api.addr_validate(&validator_set_address)?; + VALIDATOR_SET_ADDRESS.save(deps.storage, &validator_set_address)?; + attrs.push(attr("validator_set_address", validator_set_address)) + } + + if let Some(distribution_address) = distribution_address { + let distribution_address = deps.api.addr_validate(&distribution_address)?; + DISTRIBUTION_ADDRESS.save(deps.storage, &distribution_address)?; + attrs.push(attr("distribution_address", distribution_address)) + } + + if let Some(denom) = denom { + DENOM.save(deps.storage, &denom)?; + attrs.push(attr("denom", denom)) + } + + Ok(response("config_update", CONTRACT_NAME, attrs)) } #[cfg_attr(not(feature = "library"), entry_point)] @@ -61,5 +228,3 @@ pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult = Item::new("config"); diff --git a/contracts/strategy/src/tests.rs b/contracts/strategy/src/tests.rs new file mode 100644 index 00000000..60280ff7 --- /dev/null +++ b/contracts/strategy/src/tests.rs @@ -0,0 +1,389 @@ +use crate::contract::instantiate; + +use cosmwasm_schema::cw_serde; +// use cosmwasm_schema::cw_serde; +use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; +use cosmwasm_std::{ + to_json_binary, Addr, Attribute, Binary, Decimal, Deps, Empty, Env, Event, Response, StdResult, + Uint128, +}; +use cw_multi_test::{custom_app, App, Contract, ContractWrapper, Executor}; +use lido_interchain_interceptor_base::error::ContractError as PuppeteerContractError; +use lido_interchain_interceptor_base::msg::QueryMsg as PuppeteerQueryMsg; +use lido_staking_base::error::distribution::ContractError as DistributionContractError; +use lido_staking_base::error::validatorset::ContractError as ValidatorSetContractError; +use lido_staking_base::msg::distribution::IdealDelegation; +use lido_staking_base::msg::strategy::QueryMsg; +use lido_staking_base::msg::validatorset::QueryMsg as ValidatorSetQueryMsg; +use lido_staking_base::msg::{ + distribution::QueryMsg as DistributionQueryMsg, strategy::InstantiateMsg, +}; + +const CORE_CONTRACT_ADDR: &str = "core_contract"; +const PUPPETEER_CONTRACT_ADDR: &str = "puppeteer_contract"; +const VALIDATOR_SET_CONTRACT_ADDR: &str = "validator_set_contract"; +const DISTRIBUTION_CONTRACT_ADDR: &str = "distribution_contract"; + +#[cw_serde] +pub struct EmptyMsg {} + +fn instantiate_contract( + app: &mut App, + contract: fn() -> Box>, + label: String, +) -> Addr { + let contract_id = app.store_code(contract()); + app.instantiate_contract( + contract_id, + Addr::unchecked(CORE_CONTRACT_ADDR), + &EmptyMsg {}, + &[], + label, + None, + ) + .unwrap() +} + +fn distribution_contract() -> Box> { + let contract: ContractWrapper< + EmptyMsg, + EmptyMsg, + DistributionQueryMsg, + DistributionContractError, + DistributionContractError, + DistributionContractError, + > = ContractWrapper::new( + |_, _, _, _: EmptyMsg| Ok(Response::new()), + |_, _, _, _: EmptyMsg| Ok(Response::new()), + lido_distribution::contract::query, + ); + Box::new(contract) +} + +fn instantiate_distribution_contract(app: &mut App) -> Addr { + instantiate_contract( + app, + distribution_contract, + "lido distribution contract".to_string(), + ) +} + +fn puppeteer_query(_deps: Deps, _env: Env, msg: PuppeteerQueryMsg) -> StdResult { + match msg { + PuppeteerQueryMsg::Config {} => todo!(), + PuppeteerQueryMsg::State {} => todo!(), + PuppeteerQueryMsg::Transactions {} => todo!(), + PuppeteerQueryMsg::InterchainTransactions {} => todo!(), + PuppeteerQueryMsg::Delegations {} => { + let mut delegations_amount: Vec = Vec::new(); + for i in 0..3 { + let delegation = cosmwasm_std::Delegation { + validator: format!("valoper{}", i), + delegator: Addr::unchecked("delegator".to_owned() + i.to_string().as_str()), + amount: cosmwasm_std::Coin { + denom: "uatom".to_string(), + amount: Uint128::from(100u128), + }, + }; + delegations_amount.push(delegation); + } + let delegations = lido_interchain_interceptor_base::msg::DelegationsResponse { + delegations: delegations_amount, + last_updated_height: 0, + }; + Ok(to_json_binary(&delegations)?) + } + } +} + +fn puppeteer_contract() -> Box> { + let contract: ContractWrapper< + EmptyMsg, + EmptyMsg, + PuppeteerQueryMsg, + PuppeteerContractError, + PuppeteerContractError, + cosmwasm_std::StdError, + > = ContractWrapper::new( + |_, _, _, _: EmptyMsg| Ok(Response::new()), + |_, _, _, _: EmptyMsg| Ok(Response::new()), + puppeteer_query, + ); + Box::new(contract) +} + +fn instantiate_puppeteer_contract(app: &mut App) -> Addr { + instantiate_contract( + app, + puppeteer_contract, + "lido puppeteeer contract".to_string(), + ) +} + +fn validator_set_query(_deps: Deps, _env: Env, msg: ValidatorSetQueryMsg) -> StdResult { + match msg { + ValidatorSetQueryMsg::Config {} => todo!(), + ValidatorSetQueryMsg::Validator { valoper: _ } => todo!(), + ValidatorSetQueryMsg::Validators {} => { + let mut validators = Vec::new(); + for i in 0..3 { + let validator = lido_staking_base::state::validatorset::ValidatorInfo { + valoper_address: format!("valoper{}", i), + weight: 100, + last_processed_remote_height: None, + last_processed_local_height: None, + last_validated_height: None, + last_commission_in_range: None, + uptime: Decimal::zero(), + tombstone: false, + jailed_number: None, + }; + validators.push(validator); + } + Ok(to_json_binary(&validators)?) + } + } +} + +fn validator_set_contract() -> Box> { + let contract: ContractWrapper< + EmptyMsg, + EmptyMsg, + ValidatorSetQueryMsg, + ValidatorSetContractError, + ValidatorSetContractError, + cosmwasm_std::StdError, + > = ContractWrapper::new( + |_, _, _, _: EmptyMsg| Ok(Response::new()), + |_, _, _, _: EmptyMsg| Ok(Response::new()), + validator_set_query, + ); + Box::new(contract) +} + +fn instantiate_validator_set_contract(app: &mut App) -> Addr { + instantiate_contract( + app, + validator_set_contract, + "lido validator set contract".to_string(), + ) +} + +fn strategy_contract() -> Box> { + let contract = ContractWrapper::new( + crate::contract::execute, + crate::contract::instantiate, + crate::contract::query, + ); + Box::new(contract) +} + +fn instantiate_strategy_contract(app: &mut App, id: u64, msg: InstantiateMsg) -> Addr { + app.instantiate_contract( + id, + Addr::unchecked(CORE_CONTRACT_ADDR), + &msg, + &[], + "strategy contract", + None, + ) + .unwrap() +} + +fn mock_app() -> App { + custom_app(|_r, _a, _s| {}) +} + +#[test] +fn test_initialization() { + let mut deps = mock_dependencies(); + let msg = InstantiateMsg { + core_address: CORE_CONTRACT_ADDR.to_string(), + distribution_address: DISTRIBUTION_CONTRACT_ADDR.to_string(), + puppeteer_address: PUPPETEER_CONTRACT_ADDR.to_string(), + validator_set_address: VALIDATOR_SET_CONTRACT_ADDR.to_string(), + denom: "uatom".to_string(), + }; + + let info = mock_info(CORE_CONTRACT_ADDR, &[]); + let res = instantiate(deps.as_mut(), mock_env(), info.clone(), msg.clone()).unwrap(); + + assert_eq!( + res.events, + vec![ + Event::new("crates.io:lido-staking__lido-strategy-instantiate".to_string()) + .add_attributes(vec![ + Attribute::new("core_address".to_string(), CORE_CONTRACT_ADDR.to_string()), + Attribute::new( + "puppeteer_address".to_string(), + PUPPETEER_CONTRACT_ADDR.to_string() + ), + Attribute::new( + "validator_set_address".to_string(), + VALIDATOR_SET_CONTRACT_ADDR.to_string() + ), + Attribute::new( + "distribution_address".to_string(), + DISTRIBUTION_CONTRACT_ADDR.to_string() + ), + Attribute::new("denom".to_string(), "uatom".to_string()), + ]) + ] + ); +} + +#[test] +fn test_config_query() { + let mut app = mock_app(); + let validator_set_contract = instantiate_validator_set_contract(&mut app); + let puppeteer_contract = instantiate_puppeteer_contract(&mut app); + let distribution_contract = instantiate_distribution_contract(&mut app); + + let strategy_id = app.store_code(strategy_contract()); + + let strategy_contract = instantiate_strategy_contract( + &mut app, + strategy_id, + InstantiateMsg { + core_address: CORE_CONTRACT_ADDR.to_string(), + distribution_address: distribution_contract.to_string(), + puppeteer_address: puppeteer_contract.to_string(), + validator_set_address: validator_set_contract.to_string(), + denom: "uatom".to_string(), + }, + ); + + let config: lido_staking_base::msg::strategy::ConfigResponse = app + .wrap() + .query_wasm_smart(strategy_contract.clone(), &QueryMsg::Config {}) + .unwrap(); + + assert_eq!( + config, + lido_staking_base::msg::strategy::ConfigResponse { + core_address: CORE_CONTRACT_ADDR.to_string(), + distribution_address: distribution_contract.to_string(), + puppeteer_address: puppeteer_contract.to_string(), + validator_set_address: validator_set_contract.to_string(), + denom: "uatom".to_string(), + } + ); +} + +#[test] +fn test_ideal_deposit_calculation() { + let mut app = mock_app(); + let validator_set_contract = instantiate_validator_set_contract(&mut app); + let puppeteer_contract = instantiate_puppeteer_contract(&mut app); + let distribution_contract = instantiate_distribution_contract(&mut app); + + let strategy_id = app.store_code(strategy_contract()); + + let strategy_contract = instantiate_strategy_contract( + &mut app, + strategy_id, + InstantiateMsg { + core_address: CORE_CONTRACT_ADDR.to_string(), + distribution_address: distribution_contract.to_string(), + puppeteer_address: puppeteer_contract.to_string(), + validator_set_address: validator_set_contract.to_string(), + denom: "uatom".to_string(), + }, + ); + + let ideal_deposit: Vec = app + .wrap() + .query_wasm_smart( + strategy_contract, + &QueryMsg::CalcDeposit { + deposit: 100u128.into(), + }, + ) + .unwrap(); + + assert_eq!( + ideal_deposit, + vec![ + IdealDelegation { + valoper_address: "valoper0".to_string(), + ideal_stake: 134u128.into(), + current_stake: 100u128.into(), + stake_change: 34u128.into(), + weight: 100 + }, + IdealDelegation { + valoper_address: "valoper1".to_string(), + ideal_stake: 134u128.into(), + current_stake: 100u128.into(), + stake_change: 34u128.into(), + weight: 100 + }, + IdealDelegation { + valoper_address: "valoper2".to_string(), + ideal_stake: 132u128.into(), + current_stake: 100u128.into(), + stake_change: 32u128.into(), + weight: 100 + } + ] + ); +} + +#[test] +fn test_ideal_withdraw_calculation() { + let mut app = mock_app(); + let validator_set_contract = instantiate_validator_set_contract(&mut app); + let puppeteer_contract = instantiate_puppeteer_contract(&mut app); + let distribution_contract = instantiate_distribution_contract(&mut app); + + let strategy_id = app.store_code(strategy_contract()); + + let strategy_contract = instantiate_strategy_contract( + &mut app, + strategy_id, + InstantiateMsg { + core_address: CORE_CONTRACT_ADDR.to_string(), + distribution_address: distribution_contract.to_string(), + puppeteer_address: puppeteer_contract.to_string(), + validator_set_address: validator_set_contract.to_string(), + denom: "uatom".to_string(), + }, + ); + + let ideal_deposit: Vec = app + .wrap() + .query_wasm_smart( + strategy_contract, + &QueryMsg::CalcWithdraw { + withdraw: 100u128.into(), + }, + ) + .unwrap(); + + assert_eq!( + ideal_deposit, + vec![ + IdealDelegation { + valoper_address: "valoper0".to_string(), + ideal_stake: 67u128.into(), + current_stake: 100u128.into(), + stake_change: 33u128.into(), + weight: 100 + }, + IdealDelegation { + valoper_address: "valoper1".to_string(), + ideal_stake: 67u128.into(), + current_stake: 100u128.into(), + stake_change: 33u128.into(), + weight: 100 + }, + IdealDelegation { + valoper_address: "valoper2".to_string(), + ideal_stake: 66u128.into(), + current_stake: 100u128.into(), + stake_change: 34u128.into(), + weight: 100 + } + ] + ); +} diff --git a/contracts/validators-set/src/bin/lido-validators-set-schema.rs b/contracts/validators-set/src/bin/lido-validators-set-schema.rs index 16e7b9ce..599d4687 100644 --- a/contracts/validators-set/src/bin/lido-validators-set-schema.rs +++ b/contracts/validators-set/src/bin/lido-validators-set-schema.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::write_api; -use lido_validators_set::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; +use lido_staking_base::msg::validatorset::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; fn main() { write_api! { diff --git a/contracts/validators-set/src/contract.rs b/contracts/validators-set/src/contract.rs index 6dd146b5..07cd0eb0 100644 --- a/contracts/validators-set/src/contract.rs +++ b/contracts/validators-set/src/contract.rs @@ -1,18 +1,15 @@ use cosmwasm_std::{attr, ensure_eq, entry_point, to_json_binary, Addr, Deps, Order}; use cosmwasm_std::{Binary, DepsMut, Env, MessageInfo, Response, StdResult}; use cw2::set_contract_version; +use lido_staking_base::error::validatorset::{ContractError, ContractResult}; use lido_staking_base::helpers::answer::response; +use lido_staking_base::msg::validatorset::{ + ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, ValidatorData, ValidatorInfoUpdate, +}; +use lido_staking_base::state::validatorset::{Config, ValidatorInfo, CONFIG, VALIDATORS_SET}; use neutron_sdk::bindings::msg::NeutronMsg; use neutron_sdk::bindings::query::NeutronQuery; -use crate::error::{ContractError, ContractResult}; -use crate::msg::{ValidatorData, ValidatorInfoUpdate}; -use crate::state::{ValidatorInfo, CONFIG, VALIDATORS_SET}; -use crate::{ - msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, - state::Config, -}; - const CONTRACT_NAME: &str = concat!("crates.io:lido-staking__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -46,7 +43,7 @@ pub fn instantiate( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> ContractResult { match msg { QueryMsg::Config {} => query_config(deps, env), QueryMsg::Validator { valoper } => query_validator(deps, valoper), @@ -54,24 +51,24 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult, _env: Env) -> StdResult { +fn query_config(deps: Deps, _env: Env) -> ContractResult { let config = CONFIG.load(deps.storage)?; - to_json_binary(&config) + Ok(to_json_binary(&config)?) } -fn query_validator(deps: Deps, valoper: Addr) -> StdResult { +fn query_validator(deps: Deps, valoper: Addr) -> ContractResult { let validators = VALIDATORS_SET.may_load(deps.storage, valoper.to_string())?; - to_json_binary(&validators) + Ok(to_json_binary(&validators)?) } -fn query_validators(deps: Deps) -> StdResult { +fn query_validators(deps: Deps) -> ContractResult { let validators: StdResult> = VALIDATORS_SET .range_raw(deps.storage, None, None, Order::Ascending) .map(|item| item.map(|(_key, value)| value)) .collect(); - to_json_binary(&validators?) + Ok(to_json_binary(&validators?)?) } #[cfg_attr(not(feature = "library"), entry_point)] diff --git a/contracts/validators-set/src/lib.rs b/contracts/validators-set/src/lib.rs index f0e2fd34..7380e09b 100644 --- a/contracts/validators-set/src/lib.rs +++ b/contracts/validators-set/src/lib.rs @@ -1,7 +1,4 @@ pub mod contract; -pub mod error; -pub mod msg; -pub mod state; #[cfg(test)] mod tests; diff --git a/contracts/validators-set/src/tests.rs b/contracts/validators-set/src/tests.rs index f144c5d3..0ee047b5 100644 --- a/contracts/validators-set/src/tests.rs +++ b/contracts/validators-set/src/tests.rs @@ -22,17 +22,19 @@ fn instantiate() { deps.as_mut(), mock_env(), mock_info("admin", &[]), - crate::msg::InstantiateMsg { + lido_staking_base::msg::validatorset::InstantiateMsg { core: "core".to_string(), stats_contract: "stats_contract".to_string(), }, ) .unwrap(); - let config = crate::state::CONFIG.load(deps.as_ref().storage).unwrap(); + let config = lido_staking_base::state::validatorset::CONFIG + .load(deps.as_ref().storage) + .unwrap(); assert_eq!( config, - crate::state::Config { + lido_staking_base::state::validatorset::Config { core: Addr::unchecked("core"), stats_contract: Addr::unchecked("stats_contract"), } @@ -54,21 +56,25 @@ fn instantiate() { #[test] fn query_config() { let mut deps = mock_dependencies::(); - crate::state::CONFIG + lido_staking_base::state::validatorset::CONFIG .save( deps.as_mut().storage, - &crate::state::Config { + &lido_staking_base::state::validatorset::Config { core: Addr::unchecked("core"), stats_contract: Addr::unchecked("stats_contract"), }, ) .unwrap(); - let response = - crate::contract::query(deps.as_ref(), mock_env(), crate::msg::QueryMsg::Config {}).unwrap(); + let response = crate::contract::query( + deps.as_ref(), + mock_env(), + lido_staking_base::msg::validatorset::QueryMsg::Config {}, + ) + .unwrap(); assert_eq!( response, - to_json_binary(&crate::state::Config { + to_json_binary(&lido_staking_base::state::validatorset::Config { core: Addr::unchecked("core"), stats_contract: Addr::unchecked("stats_contract") }) @@ -80,10 +86,10 @@ fn query_config() { fn update_config_wrong_owner() { let mut deps = mock_dependencies::(); - crate::state::CONFIG + lido_staking_base::state::validatorset::CONFIG .save( deps.as_mut().storage, - &crate::state::Config { + &lido_staking_base::state::validatorset::Config { core: Addr::unchecked("core"), stats_contract: Addr::unchecked("stats_contract"), }, @@ -94,7 +100,7 @@ fn update_config_wrong_owner() { deps.as_mut(), mock_env(), mock_info("core1", &[]), - crate::msg::ExecuteMsg::UpdateConfig { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateConfig { core: Some(Addr::unchecked("owner1")), stats_contract: Some(Addr::unchecked("stats_contract1")), }, @@ -102,7 +108,7 @@ fn update_config_wrong_owner() { .unwrap_err(); assert_eq!( error, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::Std( + lido_staking_base::error::validatorset::ContractError::OwnershipError(cw_ownable::OwnershipError::Std( cosmwasm_std::StdError::NotFound { kind: "type: cw_ownable::Ownership; key: [6F, 77, 6E, 65, 72, 73, 68, 69, 70]".to_string() } @@ -122,10 +128,10 @@ fn update_config_ok() { Some(Addr::unchecked("core").as_ref()), ); - crate::state::CONFIG + lido_staking_base::state::validatorset::CONFIG .save( deps.as_mut().storage, - &crate::state::Config { + &lido_staking_base::state::validatorset::Config { core: Addr::unchecked("core"), stats_contract: Addr::unchecked("stats_contract"), }, @@ -136,7 +142,7 @@ fn update_config_ok() { deps.as_mut(), mock_env(), mock_info("core", &[]), - crate::msg::ExecuteMsg::UpdateConfig { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateConfig { core: Some(Addr::unchecked("owner1")), stats_contract: Some(Addr::unchecked("stats_contract1")), }, @@ -144,11 +150,15 @@ fn update_config_ok() { .unwrap(); assert_eq!(response.messages.len(), 0); - let config = - crate::contract::query(deps.as_ref(), mock_env(), crate::msg::QueryMsg::Config {}).unwrap(); + let config = crate::contract::query( + deps.as_ref(), + mock_env(), + lido_staking_base::msg::validatorset::QueryMsg::Config {}, + ) + .unwrap(); assert_eq!( config, - to_json_binary(&crate::state::Config { + to_json_binary(&lido_staking_base::state::validatorset::Config { core: Addr::unchecked("owner1"), stats_contract: Addr::unchecked("stats_contract1") }) @@ -164,8 +174,8 @@ fn update_validator_wrong_owner() { deps.as_mut(), mock_env(), mock_info("core1", &[]), - crate::msg::ExecuteMsg::UpdateValidator { - validator: crate::msg::ValidatorData { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateValidator { + validator: lido_staking_base::msg::validatorset::ValidatorData { valoper_address: "valoper_address".to_string(), weight: 1, }, @@ -174,7 +184,7 @@ fn update_validator_wrong_owner() { .unwrap_err(); assert_eq!( error, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::Std( + lido_staking_base::error::validatorset::ContractError::OwnershipError(cw_ownable::OwnershipError::Std( cosmwasm_std::StdError::NotFound { kind: "type: cw_ownable::Ownership; key: [6F, 77, 6E, 65, 72, 73, 68, 69, 70]".to_string() } @@ -198,8 +208,8 @@ fn update_validator_ok() { deps.as_mut(), mock_env(), mock_info("core", &[]), - crate::msg::ExecuteMsg::UpdateValidator { - validator: crate::msg::ValidatorData { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateValidator { + validator: lido_staking_base::msg::validatorset::ValidatorData { valoper_address: "valoper_address".to_string(), weight: 1, }, @@ -211,14 +221,14 @@ fn update_validator_ok() { let validator = crate::contract::query( deps.as_ref(), mock_env(), - crate::msg::QueryMsg::Validator { + lido_staking_base::msg::validatorset::QueryMsg::Validator { valoper: Addr::unchecked("valoper_address"), }, ) .unwrap(); assert_eq!( validator, - to_json_binary(&crate::state::ValidatorInfo { + to_json_binary(&lido_staking_base::state::validatorset::ValidatorInfo { valoper_address: "valoper_address".to_string(), weight: 1, last_processed_remote_height: None, @@ -241,8 +251,8 @@ fn update_validators_wrong_owner() { deps.as_mut(), mock_env(), mock_info("core1", &[]), - crate::msg::ExecuteMsg::UpdateValidators { - validators: vec![crate::msg::ValidatorData { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateValidators { + validators: vec![lido_staking_base::msg::validatorset::ValidatorData { valoper_address: "valoper_address".to_string(), weight: 1, }], @@ -251,7 +261,7 @@ fn update_validators_wrong_owner() { .unwrap_err(); assert_eq!( error, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::Std( + lido_staking_base::error::validatorset::ContractError::OwnershipError(cw_ownable::OwnershipError::Std( cosmwasm_std::StdError::NotFound { kind: "type: cw_ownable::Ownership; key: [6F, 77, 6E, 65, 72, 73, 68, 69, 70]".to_string() } @@ -275,13 +285,13 @@ fn update_validators_ok() { deps.as_mut(), mock_env(), mock_info("core", &[]), - crate::msg::ExecuteMsg::UpdateValidators { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateValidators { validators: vec![ - crate::msg::ValidatorData { + lido_staking_base::msg::validatorset::ValidatorData { valoper_address: "valoper_address1".to_string(), weight: 1, }, - crate::msg::ValidatorData { + lido_staking_base::msg::validatorset::ValidatorData { valoper_address: "valoper_address2".to_string(), weight: 1, }, @@ -294,13 +304,13 @@ fn update_validators_ok() { let validator = crate::contract::query( deps.as_ref(), mock_env(), - crate::msg::QueryMsg::Validators {}, + lido_staking_base::msg::validatorset::QueryMsg::Validators {}, ) .unwrap(); assert_eq!( validator, to_json_binary(&vec![ - crate::state::ValidatorInfo { + lido_staking_base::state::validatorset::ValidatorInfo { valoper_address: "valoper_address1".to_string(), weight: 1, last_processed_remote_height: None, @@ -311,7 +321,7 @@ fn update_validators_ok() { tombstone: false, jailed_number: None, }, - crate::state::ValidatorInfo { + lido_staking_base::state::validatorset::ValidatorInfo { valoper_address: "valoper_address2".to_string(), weight: 1, last_processed_remote_height: None, @@ -339,10 +349,10 @@ fn update_validator_info_wrong_sender() { Some(Addr::unchecked("core").as_ref()), ); - crate::state::CONFIG + lido_staking_base::state::validatorset::CONFIG .save( deps_mut.storage, - &crate::state::Config { + &lido_staking_base::state::validatorset::Config { core: Addr::unchecked("core"), stats_contract: Addr::unchecked("stats_contract"), }, @@ -353,8 +363,8 @@ fn update_validator_info_wrong_sender() { deps_mut, mock_env(), mock_info("core", &[]), - crate::msg::ExecuteMsg::UpdateValidator { - validator: crate::msg::ValidatorData { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateValidator { + validator: lido_staking_base::msg::validatorset::ValidatorData { valoper_address: "valoper_address".to_string(), weight: 1, }, @@ -366,8 +376,8 @@ fn update_validator_info_wrong_sender() { deps.as_mut(), mock_env(), mock_info("stats_contract1", &[]), - crate::msg::ExecuteMsg::UpdateValidatorInfo { - validators: vec![crate::msg::ValidatorInfoUpdate { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateValidatorInfo { + validators: vec![lido_staking_base::msg::validatorset::ValidatorInfoUpdate { valoper_address: "valoper_address".to_string(), last_processed_remote_height: None, last_processed_local_height: None, @@ -380,7 +390,10 @@ fn update_validator_info_wrong_sender() { }, ) .unwrap_err(); - assert_eq!(error, crate::error::ContractError::Unauthorized); + assert_eq!( + error, + lido_staking_base::error::validatorset::ContractError::Unauthorized + ); } #[test] @@ -395,10 +408,10 @@ fn update_validator_info_ok() { Some(Addr::unchecked("core").as_ref()), ); - crate::state::CONFIG + lido_staking_base::state::validatorset::CONFIG .save( deps_mut.storage, - &crate::state::Config { + &lido_staking_base::state::validatorset::Config { core: Addr::unchecked("core"), stats_contract: Addr::unchecked("stats_contract"), }, @@ -409,8 +422,8 @@ fn update_validator_info_ok() { deps.as_mut(), mock_env(), mock_info("core", &[]), - crate::msg::ExecuteMsg::UpdateValidator { - validator: crate::msg::ValidatorData { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateValidator { + validator: lido_staking_base::msg::validatorset::ValidatorData { valoper_address: "valoper_address".to_string(), weight: 1, }, @@ -423,8 +436,8 @@ fn update_validator_info_ok() { deps.as_mut(), mock_env(), mock_info("stats_contract", &[]), - crate::msg::ExecuteMsg::UpdateValidatorInfo { - validators: vec![crate::msg::ValidatorInfoUpdate { + lido_staking_base::msg::validatorset::ExecuteMsg::UpdateValidatorInfo { + validators: vec![lido_staking_base::msg::validatorset::ValidatorInfoUpdate { valoper_address: "valoper_address".to_string(), last_processed_remote_height: Some(1234), last_processed_local_height: Some(2345), @@ -442,7 +455,7 @@ fn update_validator_info_ok() { let validator = crate::contract::query( deps.as_ref(), mock_env(), - crate::msg::QueryMsg::Validator { + lido_staking_base::msg::validatorset::QueryMsg::Validator { valoper: Addr::unchecked("valoper_address"), }, ) @@ -450,7 +463,7 @@ fn update_validator_info_ok() { assert_eq!( validator, - to_json_binary(&crate::state::ValidatorInfo { + to_json_binary(&lido_staking_base::state::validatorset::ValidatorInfo { valoper_address: "valoper_address".to_string(), weight: 1, last_processed_remote_height: Some(1234), diff --git a/contracts/validators-stats/.cargo/config b/contracts/validators-stats/.cargo/config index 4e9fd307..a9441a37 100644 --- a/contracts/validators-stats/.cargo/config +++ b/contracts/validators-stats/.cargo/config @@ -1,5 +1,4 @@ [alias] wasm = "build --release --target wasm32-unknown-unknown" unit-test = "test --lib" -schema = "run --example schema" -integration-test = "test --test integration" +schema = "run --bin lido-validators-stats-schema" diff --git a/contracts/validators-stats/Cargo.toml b/contracts/validators-stats/Cargo.toml index f796cabc..54006393 100644 --- a/contracts/validators-stats/Cargo.toml +++ b/contracts/validators-stats/Cargo.toml @@ -43,6 +43,8 @@ serde = { workspace = true } serde-json-wasm = { workspace = true } sha2 = { workspace = true } +lido-staking-base = { workspace = true } + [dev-dependencies] cosmwasm-storage = { workspace = true } cw-multi-test = "0.17.0" diff --git a/contracts/validators-stats/examples/schema.rs b/contracts/validators-stats/src/bin/lido-validators-stats-schema.rs similarity index 64% rename from contracts/validators-stats/examples/schema.rs rename to contracts/validators-stats/src/bin/lido-validators-stats-schema.rs index 03d912af..f65cce3e 100644 --- a/contracts/validators-stats/examples/schema.rs +++ b/contracts/validators-stats/src/bin/lido-validators-stats-schema.rs @@ -1,8 +1,6 @@ use cosmwasm_schema::write_api; -use lido_validators_stats::{ - msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}, - state::QueryMsg, -}; + +use lido_staking_base::msg::validatorsstats::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; fn main() { write_api! { diff --git a/contracts/validators-stats/src/contract.rs b/contracts/validators-stats/src/contract.rs index f7f59dd2..99e4703a 100644 --- a/contracts/validators-stats/src/contract.rs +++ b/contracts/validators-stats/src/contract.rs @@ -4,6 +4,12 @@ use cosmwasm_std::{ }; use cosmwasm_std::{Binary, DepsMut, Env, MessageInfo, Response, StdResult}; use cw2::set_contract_version; +use lido_staking_base::msg::validatorsstats::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; +use lido_staking_base::state::validatorsstats::{ + Config, MissedBlocks, ValidatorMissedBlocksForPeriod, ValidatorState, CONFIG, MISSED_BLOCKS, + SIGNING_INFO_QUERY_ID, SIGNING_INFO_REPLY_ID, STATE_MAP, VALCONS_TO_VALOPER, + VALIDATOR_PROFILE_QUERY_ID, VALIDATOR_PROFILE_REPLY_ID, +}; use neutron_sdk::bindings::msg::MsgRegisterInterchainQueryResponse; use neutron_sdk::bindings::query::QueryRegisteredQueryResultResponse; use neutron_sdk::interchain_queries::queries::get_raw_interchain_query_result; @@ -20,15 +26,6 @@ use neutron_sdk::{ }; use sha2::{Digest, Sha256}; -use crate::state::{ - MissedBlocks, QueryMsg, ValidatorMissedBlocksForPeriod, ValidatorState, CONFIG, MISSED_BLOCKS, - SIGNING_INFO_QUERY_ID, STATE_MAP, VALCONS_TO_VALOPER, VALIDATOR_PROFILE_QUERY_ID, -}; -use crate::{ - msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}, - state::{Config, SIGNING_INFO_REPLY_ID, VALIDATOR_PROFILE_REPLY_ID}, -}; - const CONTRACT_NAME: &str = concat!("crates.io:lido-staking__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -88,7 +85,6 @@ pub fn execute( _info: MessageInfo, msg: ExecuteMsg, ) -> NeutronResult> { - // TODO: Add code to remove queries and withdraw funds from the contract // TODO: Add update config support // TODO: Add block time change support match msg { @@ -391,6 +387,10 @@ pub fn pubkey_to_address(pubkey: Vec, prefix: &str) -> StdResult { let pubkey_bytes = &pubkey[2..]; + // let mut hasher = Sha256::new(); + // hasher.update(pubkey_bytes); + // let hash = hasher.finalize(); + let hash = Sha256::digest(pubkey_bytes); let addr_bytes = &hash[..20]; diff --git a/contracts/validators-stats/src/lib.rs b/contracts/validators-stats/src/lib.rs index 4934c19d..2943dbb5 100644 --- a/contracts/validators-stats/src/lib.rs +++ b/contracts/validators-stats/src/lib.rs @@ -1,3 +1 @@ pub mod contract; -pub mod msg; -pub mod state; diff --git a/contracts/withdrawal-manager/Cargo.toml b/contracts/withdrawal-manager/Cargo.toml index da89ce66..f8dc4359 100644 --- a/contracts/withdrawal-manager/Cargo.toml +++ b/contracts/withdrawal-manager/Cargo.toml @@ -42,7 +42,6 @@ cw721-base = { workspace = true } schemars = { workspace = true } serde = { workspace = true } serde-json-wasm = { workspace = true } -sha2 = { workspace = true } lido-staking-base = { workspace = true } thiserror = { workspace = true } diff --git a/contracts/withdrawal-voucher/Cargo.toml b/contracts/withdrawal-voucher/Cargo.toml index 4274b6c0..7ca588f3 100644 --- a/contracts/withdrawal-voucher/Cargo.toml +++ b/contracts/withdrawal-voucher/Cargo.toml @@ -42,7 +42,6 @@ cw721-base = { workspace = true } schemars = { workspace = true } serde = { workspace = true } serde-json-wasm = { workspace = true } -sha2 = { workspace = true } lido-staking-base = { workspace = true } thiserror = { workspace = true } diff --git a/integration_tests/src/generated/contractLib/lidoFactory.ts b/integration_tests/src/generated/contractLib/lidoFactory.ts index 1a2092be..86eb9f36 100644 --- a/integration_tests/src/generated/contractLib/lidoFactory.ts +++ b/integration_tests/src/generated/contractLib/lidoFactory.ts @@ -3,9 +3,12 @@ import { StdFee } from "@cosmjs/amino"; import { Coin } from "@cosmjs/amino"; export interface InstantiateMsg { core_code_id: number; + distribution_code_id: number; salt: string; + strategy_code_id: number; subdenom: string; token_code_id: number; + validators_set_code_id: number; withdrawal_manager_code_id: number; withdrawal_voucher_code_id: number; } @@ -16,7 +19,10 @@ export interface LidoFactorySchema { } export interface State { core_contract: string; + distribution_contract: string; + strategy_contract: string; token_contract: string; + validators_set_contract: string; withdrawal_manager_contract: string; withdrawal_voucher_contract: string; } diff --git a/integration_tests/src/generated/contractLib/lidoStrategy.ts b/integration_tests/src/generated/contractLib/lidoStrategy.ts index c47ade26..b9bc1e89 100644 --- a/integration_tests/src/generated/contractLib/lidoStrategy.ts +++ b/integration_tests/src/generated/contractLib/lidoStrategy.ts @@ -2,25 +2,61 @@ import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult import { StdFee } from "@cosmjs/amino"; import { Coin } from "@cosmjs/amino"; export interface InstantiateMsg { - owner: string; + core_address: string; + denom: string; + distribution_address: string; + puppeteer_address: string; + validator_set_address: string; } /** - * A human readable address. + * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. * - * In Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length. + * # Examples * - * This type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances. + * Use `from` to create instances of this and `u128` to get the value out: * - * This type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance. + * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); + * + * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); + * + * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` */ -export type Addr = string; +export type Uint128 = string; +export type ArrayOfIdealDelegation = IdealDelegation[]; +export type ArrayOfIdealDelegation1 = IdealDelegation[]; export interface LidoStrategySchema { - responses: Config; + responses: ArrayOfIdealDelegation | ArrayOfIdealDelegation1; + query: CalcDepositArgs | CalcWithdrawArgs; + execute: UpdateConfigArgs; [k: string]: unknown; } -export interface Config { - owner: Addr; +export interface IdealDelegation { + current_stake: Uint128; + ideal_stake: Uint128; + stake_change: Uint128; + valoper_address: string; + weight: number; +} +export interface CalcDepositArgs { + delegations: Delegation[]; + deposit: Uint128; +} +export interface Delegation { + stake: Uint128; + valoper_address: string; + weight: number; +} +export interface CalcWithdrawArgs { + delegations: Delegation[]; + withdraw: Uint128; +} +export interface UpdateConfigArgs { + core_address?: string | null; + denom?: string | null; + distribution_address?: string | null; + puppeteer_address?: string | null; + validator_set_address?: string | null; } @@ -54,7 +90,14 @@ export class Client { }); return res; } - queryConfig = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { config: {} }); + queryCalcDeposit = async(args: CalcDepositArgs): Promise => { + return this.client.queryContractSmart(this.contractAddress, { calc_deposit: args }); + } + queryCalcWithdraw = async(args: CalcWithdrawArgs): Promise => { + return this.client.queryContractSmart(this.contractAddress, { calc_withdraw: args }); + } + updateConfig = async(sender:string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { + if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } + return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); } } diff --git a/integration_tests/src/testcases/core.test.ts b/integration_tests/src/testcases/core.test.ts index 6eff83fd..83168e67 100644 --- a/integration_tests/src/testcases/core.test.ts +++ b/integration_tests/src/testcases/core.test.ts @@ -61,6 +61,9 @@ describe('Core', () => { tokenCodeId?: number; withdrawalVoucherCodeId?: number; withdrawalManagerCodeId?: number; + strategyCodeId?: number; + validatorsSetCodeId?: number; + distributionCodeId?: number; exchangeRate?: number; tokenContractAddress?: string; neutronIBCDenom?: string; @@ -168,6 +171,39 @@ describe('Core', () => { expect(res.codeId).toBeGreaterThan(0); context.withdrawalManagerCodeId = res.codeId; } + { + const res = await client.upload( + account.address, + fs.readFileSync( + join(__dirname, '../../../artifacts/lido_strategy.wasm'), + ), + 1.5, + ); + expect(res.codeId).toBeGreaterThan(0); + context.strategyCodeId = res.codeId; + } + { + const res = await client.upload( + account.address, + fs.readFileSync( + join(__dirname, '../../../artifacts/lido_distribution.wasm'), + ), + 1.5, + ); + expect(res.codeId).toBeGreaterThan(0); + context.distributionCodeId = res.codeId; + } + { + const res = await client.upload( + account.address, + fs.readFileSync( + join(__dirname, '../../../artifacts/lido_validators_set.wasm'), + ), + 1.5, + ); + expect(res.codeId).toBeGreaterThan(0); + context.validatorsSetCodeId = res.codeId; + } const res = await client.upload( account.address, fs.readFileSync(join(__dirname, '../../../artifacts/lido_factory.wasm')), @@ -183,6 +219,9 @@ describe('Core', () => { token_code_id: context.tokenCodeId, withdrawal_voucher_code_id: context.withdrawalVoucherCodeId, withdrawal_manager_code_id: context.withdrawalManagerCodeId, + strategy_code_id: context.strategyCodeId, + distribution_code_id: context.distributionCodeId, + validators_set_code_id: context.validatorsSetCodeId, salt: 'salt', subdenom: 'lido', }, @@ -203,6 +242,7 @@ describe('Core', () => { await context.wallet.getAccounts() )[0].address; }); + it('transfer tokens to neutron', async () => { const { gaiaClient, gaiaUserAddress, neutronUserAddress, neutronClient } = context; diff --git a/packages/base/Cargo.toml b/packages/base/Cargo.toml index 58c972a5..a831ad62 100644 --- a/packages/base/Cargo.toml +++ b/packages/base/Cargo.toml @@ -29,6 +29,10 @@ cw-storage-plus = { workspace = true } neutron-sdk = { workspace = true } cw721-base = { workspace = true } cw721 = { workspace = true } +thiserror = { workspace = true } +cw-ownable = { workspace = true } + +lido-interchain-interceptor-base = { workspace = true } [dev-dependencies] cosmwasm-storage = { workspace = true } diff --git a/contracts/distribution/src/error.rs b/packages/base/src/error/distribution.rs similarity index 100% rename from contracts/distribution/src/error.rs rename to packages/base/src/error/distribution.rs diff --git a/packages/base/src/error/mod.rs b/packages/base/src/error/mod.rs new file mode 100644 index 00000000..cba5f9bb --- /dev/null +++ b/packages/base/src/error/mod.rs @@ -0,0 +1,2 @@ +pub mod distribution; +pub mod validatorset; diff --git a/contracts/validators-set/src/error.rs b/packages/base/src/error/validatorset.rs similarity index 100% rename from contracts/validators-set/src/error.rs rename to packages/base/src/error/validatorset.rs diff --git a/packages/base/src/helpers/answer.rs b/packages/base/src/helpers/answer.rs index 5a62582f..68ebabb6 100644 --- a/packages/base/src/helpers/answer.rs +++ b/packages/base/src/helpers/answer.rs @@ -1,12 +1,12 @@ use cosmwasm_std::{attr, Attribute, Event, Response}; -use neutron_sdk::bindings::msg::NeutronMsg; -pub fn response>( +pub fn response, T>( ty: &str, contract_name: &str, attrs: impl IntoIterator, -) -> Response { - Response::new().add_event(Event::new(format!("{}-{}", contract_name, ty)).add_attributes(attrs)) +) -> Response { + Response::::new() + .add_event(Event::new(format!("{}-{}", contract_name, ty)).add_attributes(attrs)) } pub fn attr_coin( diff --git a/packages/base/src/lib.rs b/packages/base/src/lib.rs index a801d48d..6971a221 100644 --- a/packages/base/src/lib.rs +++ b/packages/base/src/lib.rs @@ -1,3 +1,4 @@ +pub mod error; pub mod helpers; pub mod msg; pub mod state; diff --git a/packages/base/src/msg/mod.rs b/packages/base/src/msg/mod.rs index 01fe8c74..5e8e36be 100644 --- a/packages/base/src/msg/mod.rs +++ b/packages/base/src/msg/mod.rs @@ -1,5 +1,9 @@ pub mod core; pub mod distribution; +pub mod puppeteer; +pub mod strategy; pub mod token; +pub mod validatorset; +pub mod validatorsstats; pub mod withdrawal_manager; pub mod withdrawal_voucher; diff --git a/contracts/interchain-interceptor/src/msg.rs b/packages/base/src/msg/puppeteer.rs similarity index 100% rename from contracts/interchain-interceptor/src/msg.rs rename to packages/base/src/msg/puppeteer.rs diff --git a/packages/base/src/msg/strategy.rs b/packages/base/src/msg/strategy.rs new file mode 100644 index 00000000..415d0f79 --- /dev/null +++ b/packages/base/src/msg/strategy.rs @@ -0,0 +1,47 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::Uint128; + +use super::distribution::IdealDelegation; + +#[cw_serde] +pub enum ExecuteMsg { + UpdateConfig { + core_address: Option, + puppeteer_address: Option, + validator_set_address: Option, + distribution_address: Option, + denom: Option, + }, +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + #[returns(ConfigResponse)] + Config {}, + #[returns(Vec)] + CalcDeposit { deposit: Uint128 }, + #[returns(Vec)] + CalcWithdraw { withdraw: Uint128 }, +} + +#[cw_serde] +pub struct ConfigResponse { + pub core_address: String, + pub puppeteer_address: String, + pub validator_set_address: String, + pub distribution_address: String, + pub denom: String, +} + +#[cw_serde] +pub struct InstantiateMsg { + pub core_address: String, + pub puppeteer_address: String, + pub validator_set_address: String, + pub distribution_address: String, + pub denom: String, +} + +#[cw_serde] +pub enum MigrateMsg {} diff --git a/contracts/validators-set/src/msg.rs b/packages/base/src/msg/validatorset.rs similarity index 92% rename from contracts/validators-set/src/msg.rs rename to packages/base/src/msg/validatorset.rs index c5239e29..35e80f52 100644 --- a/contracts/validators-set/src/msg.rs +++ b/packages/base/src/msg/validatorset.rs @@ -1,7 +1,7 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{Addr, Decimal}; -use crate::state::{Config, ValidatorInfo}; +use crate::state::validatorset::ValidatorInfo; #[cw_serde] pub struct InstantiateMsg { @@ -47,7 +47,7 @@ pub enum ExecuteMsg { #[cw_serde] #[derive(QueryResponses)] pub enum QueryMsg { - #[returns(Config)] + #[returns(crate::state::validatorset::Config)] Config {}, #[returns(ValidatorInfo)] Validator { valoper: Addr }, diff --git a/contracts/validators-stats/src/msg.rs b/packages/base/src/msg/validatorsstats.rs similarity index 57% rename from contracts/validators-stats/src/msg.rs rename to packages/base/src/msg/validatorsstats.rs index 1eb9ab49..e3f2d026 100644 --- a/contracts/validators-stats/src/msg.rs +++ b/packages/base/src/msg/validatorsstats.rs @@ -1,4 +1,6 @@ -use cosmwasm_schema::cw_serde; +use cosmwasm_schema::{cw_serde, QueryResponses}; + +use crate::state::validatorsstats::{Config, ValidatorState}; #[cw_serde] pub struct InstantiateMsg { @@ -15,5 +17,14 @@ pub enum ExecuteMsg { RegisterStatsQueries { validators: Vec }, } +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + #[returns(Config)] + Config {}, + #[returns(Vec)] + State {}, +} + #[cw_serde] pub struct MigrateMsg {} diff --git a/packages/base/src/state/mod.rs b/packages/base/src/state/mod.rs index 9cc5ba8a..5e14be5d 100644 --- a/packages/base/src/state/mod.rs +++ b/packages/base/src/state/mod.rs @@ -1,4 +1,8 @@ pub mod core; +pub mod puppeteer; +pub mod strategy; pub mod token; +pub mod validatorset; +pub mod validatorsstats; pub mod withdrawal_manager; pub mod withdrawal_voucher; diff --git a/contracts/interchain-interceptor/src/state.rs b/packages/base/src/state/puppeteer.rs similarity index 95% rename from contracts/interchain-interceptor/src/state.rs rename to packages/base/src/state/puppeteer.rs index 546f9425..590b6578 100644 --- a/contracts/interchain-interceptor/src/state.rs +++ b/packages/base/src/state/puppeteer.rs @@ -6,7 +6,7 @@ use lido_interchain_interceptor_base::{ state::{BaseConfig, State, Transfer}, }; -use crate::msg::Transaction; +use crate::msg::puppeteer::Transaction; #[cw_serde] pub struct Config { diff --git a/packages/base/src/state/strategy.rs b/packages/base/src/state/strategy.rs new file mode 100644 index 00000000..5bb8aff9 --- /dev/null +++ b/packages/base/src/state/strategy.rs @@ -0,0 +1,8 @@ +use cosmwasm_std::Addr; +use cw_storage_plus::Item; + +pub const CORE_ADDRESS: Item = Item::new("core"); +pub const PUPPETEER_ADDRESS: Item = Item::new("puppeteer"); +pub const VALIDATOR_SET_ADDRESS: Item = Item::new("validator_set"); +pub const DISTRIBUTION_ADDRESS: Item = Item::new("distribution"); +pub const DENOM: Item = Item::new("denom"); diff --git a/contracts/validators-set/src/state.rs b/packages/base/src/state/validatorset.rs similarity index 100% rename from contracts/validators-set/src/state.rs rename to packages/base/src/state/validatorset.rs diff --git a/contracts/validators-stats/src/state.rs b/packages/base/src/state/validatorsstats.rs similarity index 88% rename from contracts/validators-stats/src/state.rs rename to packages/base/src/state/validatorsstats.rs index df861c4e..5b05d313 100644 --- a/contracts/validators-stats/src/state.rs +++ b/packages/base/src/state/validatorsstats.rs @@ -1,4 +1,4 @@ -use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_schema::cw_serde; use cosmwasm_std::{Addr, Decimal}; use cw_storage_plus::{Item, Map}; @@ -32,15 +32,6 @@ pub struct State { pub validators: Vec, } -#[cw_serde] -#[derive(QueryResponses)] -pub enum QueryMsg { - #[returns(Config)] - Config {}, - #[returns(Vec)] - State {}, -} - #[cw_serde] pub struct ValidatorMissedBlocksForPeriod { pub address: String, diff --git a/packages/interchain-interceptor-base/src/execute.rs b/packages/interchain-interceptor-base/src/execute.rs index 0741a483..9fa130aa 100644 --- a/packages/interchain-interceptor-base/src/execute.rs +++ b/packages/interchain-interceptor-base/src/execute.rs @@ -6,7 +6,6 @@ use neutron_sdk::{ }, interchain_queries::v045::new_register_transfers_query_msg, interchain_txs::helpers::get_port_id, - NeutronResult, }; use serde::{de::DeserializeOwned, Serialize}; @@ -21,7 +20,7 @@ where T: BaseConfig + Serialize + DeserializeOwned + Clone, C: std::fmt::Debug + Serialize + DeserializeOwned + Clone, { - pub fn instantiate(&self, deps: DepsMut, config: &T) -> NeutronResult { + pub fn instantiate(&self, deps: DepsMut, config: &T) -> ContractResult { deps.api.debug("WASMDEBUG: instantiate"); cw_ownable::initialize_owner(deps.storage, deps.api, Some(config.owner()))?; diff --git a/packages/interchain-interceptor-base/src/query.rs b/packages/interchain-interceptor-base/src/query.rs index e9095404..28df7b98 100644 --- a/packages/interchain-interceptor-base/src/query.rs +++ b/packages/interchain-interceptor-base/src/query.rs @@ -1,8 +1,9 @@ -use cosmwasm_std::{to_json_binary, Binary, Deps, Env, StdResult}; +use cosmwasm_std::{to_json_binary, Binary, Deps, Env}; use neutron_sdk::bindings::query::NeutronQuery; use serde::{de::DeserializeOwned, Serialize}; use crate::{ + error::ContractResult, msg::{DelegationsResponse, QueryMsg}, state::{BaseConfig, InterchainIntercaptorBase, State, Transfer}, }; @@ -12,7 +13,12 @@ where T: BaseConfig + Serialize + DeserializeOwned + Clone, C: std::fmt::Debug + Serialize + DeserializeOwned + Clone, { - pub fn query(&self, deps: Deps, env: Env, msg: QueryMsg) -> StdResult { + pub fn query( + &self, + deps: Deps, + env: Env, + msg: QueryMsg, + ) -> ContractResult { match msg { QueryMsg::State {} => self.query_state(deps, env), QueryMsg::Config {} => self.query_config(deps, env), @@ -22,33 +28,37 @@ where } } - fn query_delegations(&self, deps: Deps, _env: Env) -> StdResult { + fn query_delegations(&self, deps: Deps, _env: Env) -> ContractResult { let (delegations, last_updated_height) = self.delegations.load(deps.storage)?; let response = DelegationsResponse { delegations, last_updated_height, }; - to_json_binary(&response) + Ok(to_json_binary(&response)?) } - fn query_state(&self, deps: Deps, _env: Env) -> StdResult { + fn query_state(&self, deps: Deps, _env: Env) -> ContractResult { let state: State = self.state.load(deps.storage)?; - to_json_binary(&state) + Ok(to_json_binary(&state)?) } - fn query_done_transactions(&self, deps: Deps, _env: Env) -> StdResult { + fn query_done_transactions( + &self, + deps: Deps, + _env: Env, + ) -> ContractResult { deps.api.debug("WASMDEBUG: query_done_transactions"); let state: Vec = self.transactions.load(deps.storage)?; - to_json_binary(&state) + Ok(to_json_binary(&state)?) } - fn query_config(&self, deps: Deps, _env: Env) -> StdResult { + fn query_config(&self, deps: Deps, _env: Env) -> ContractResult { let config: T = self.config.load(deps.storage)?; - to_json_binary(&config) + Ok(to_json_binary(&config)?) } - fn query_transactions(&self, deps: Deps, _env: Env) -> StdResult { + fn query_transactions(&self, deps: Deps, _env: Env) -> ContractResult { let transactions: Vec = self.recipient_txs.load(deps.storage)?; - to_json_binary(&transactions) + Ok(to_json_binary(&transactions)?) } }