From c012cc4e17dab922efc9c8c46d00c7bbac2c3d11 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Thu, 12 Oct 2023 22:58:19 +0200 Subject: [PATCH 1/6] set up virtual-staking-mock --- Cargo.lock | 13 +++++ packages/virtual-staking-mock/Cargo.toml | 17 +++++++ packages/virtual-staking-mock/src/lib.rs | 61 ++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 packages/virtual-staking-mock/Cargo.toml create mode 100644 packages/virtual-staking-mock/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 61a112e1..77896244 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1172,6 +1172,19 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "virtual-staking-mock" +version = "0.7.0-alpha.2" +dependencies = [ + "anyhow", + "cosmwasm-std", + "cw-multi-test", + "cw-storage-plus", + "mesh-bindings", + "schemars", + "serde", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/packages/virtual-staking-mock/Cargo.toml b/packages/virtual-staking-mock/Cargo.toml new file mode 100644 index 00000000..a5118043 --- /dev/null +++ b/packages/virtual-staking-mock/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "virtual-staking-mock" +edition.workspace = true +version.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = { workspace = true } +cosmwasm-std = { workspace = true } +cw-multi-test = { workspace = true } +cw-storage-plus = { workspace = true } +mesh-bindings = { workspace = true } +schemars = { workspace = true } +serde = { workspace = true } diff --git a/packages/virtual-staking-mock/src/lib.rs b/packages/virtual-staking-mock/src/lib.rs new file mode 100644 index 00000000..d701519e --- /dev/null +++ b/packages/virtual-staking-mock/src/lib.rs @@ -0,0 +1,61 @@ +use anyhow::Result as AnyResult; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Empty, Querier, Storage, Uint128}; +use cw_multi_test::Module; +use cw_storage_plus::Map; +use mesh_bindings::{VirtualStakeCustomMsg, VirtualStakeCustomQuery}; +use schemars::JsonSchema; +use serde::de::DeserializeOwned; + +struct VirtualStakingModule<'a> { + delegated: Map<'a, String, Uint128>, +} + +impl Module for VirtualStakingModule<'_> { + type ExecT = VirtualStakeCustomMsg; + + type QueryT = VirtualStakeCustomQuery; + + type SudoT = Empty; + + fn execute( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn cw_multi_test::CosmosRouter, + block: &BlockInfo, + sender: Addr, + msg: Self::ExecT, + ) -> AnyResult + where + ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + todo!() + } + + fn sudo( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn cw_multi_test::CosmosRouter, + block: &BlockInfo, + msg: Self::SudoT, + ) -> AnyResult + where + ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + panic!("sudo not implemented for") + } + + fn query( + &self, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + request: Self::QueryT, + ) -> AnyResult { + todo!() + } +} From 493c68dffa72231e7bd4f239b3f7417609afc389 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 16 Oct 2023 11:31:54 +0200 Subject: [PATCH 2/6] implement virtual-staking-mock --- codecov.yml | 3 + packages/virtual-staking-mock/src/lib.rs | 129 +++++++++++++++++++++-- 2 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..d725e0ed --- /dev/null +++ b/codecov.yml @@ -0,0 +1,3 @@ +ignore: + # this is a mock for testing - worrying about it being tested itself is a bit much + - "packages/virtual-staking-mock" diff --git a/packages/virtual-staking-mock/src/lib.rs b/packages/virtual-staking-mock/src/lib.rs index d701519e..e1e8aefd 100644 --- a/packages/virtual-staking-mock/src/lib.rs +++ b/packages/virtual-staking-mock/src/lib.rs @@ -1,13 +1,59 @@ use anyhow::Result as AnyResult; -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Empty, Querier, Storage, Uint128}; -use cw_multi_test::Module; -use cw_storage_plus::Map; -use mesh_bindings::{VirtualStakeCustomMsg, VirtualStakeCustomQuery}; +use cosmwasm_std::{ + coin, to_binary, Addr, Api, Binary, BlockInfo, CustomQuery, Empty, Querier, QuerierWrapper, + Storage, Uint128, +}; +use cw_multi_test::{AppResponse, Module}; +use cw_storage_plus::{Item, Map}; +use mesh_bindings::{ + BondStatusResponse, SlashRatioResponse, VirtualStakeCustomMsg, VirtualStakeCustomQuery, +}; use schemars::JsonSchema; use serde::de::DeserializeOwned; -struct VirtualStakingModule<'a> { - delegated: Map<'a, String, Uint128>, +pub struct VirtualStakingModule<'a> { + /// virtual-staking contract -> max cap + caps: Map<'a, Addr, Uint128>, + /// (virtual-staking contract, validator) -> bonded amount + bonds: Map<'a, (Addr, Addr), Uint128>, + slash_ratio: Item<'a, SlashRatioResponse>, +} + +impl VirtualStakingModule<'_> { + pub fn new() -> Self { + Self { + caps: Map::new("virtual_staking_caps"), + bonds: Map::new("virtual_staking_bonds"), + slash_ratio: Item::new("virtual_staking_slash_ratios"), + } + } + + pub fn init_slash_ratios( + &self, + storage: &mut dyn Storage, + slash_for_downtime: impl Into, + slash_for_double_sign: impl Into, + ) -> AnyResult<()> { + self.slash_ratio.save( + storage, + &SlashRatioResponse { + slash_fraction_downtime: slash_for_downtime.into(), + slash_fraction_double_sign: slash_for_double_sign.into(), + }, + )?; + + Ok(()) + } + + fn bonded_for_contract(&self, storage: &dyn Storage, contract: Addr) -> AnyResult { + Ok(self + .bonds + .range(storage, None, None, cosmwasm_std::Order::Ascending) + .collect::, _>>()? + .into_iter() + .filter_map(|((c, _), amt)| if c == contract { Some(amt) } else { None }) + .sum()) + } } impl Module for VirtualStakingModule<'_> { @@ -30,7 +76,50 @@ impl Module for VirtualStakingModule<'_> { ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { - todo!() + let VirtualStakeCustomMsg::VirtualStake(msg) = msg; + + let cap = self.caps.load(storage, sender.clone())?; + + match msg { + mesh_bindings::VirtualStakeMsg::Bond { amount, validator } => { + let all_bonded = self.bonded_for_contract(storage, sender.clone())?; + + if all_bonded + amount.amount <= cap { + let current_bonded = self + .bonds + .may_load(storage, (sender.clone(), Addr::unchecked(&validator)))? + .unwrap_or(Uint128::zero()); + + self.bonds.save( + storage, + (sender, Addr::unchecked(validator)), + &(current_bonded + amount.amount), + )?; + + Ok(AppResponse::default()) + } else { + Err(anyhow::anyhow!("cap exceeded")) + } + } + mesh_bindings::VirtualStakeMsg::Unbond { amount, validator } => { + let current_bonded = self + .bonds + .may_load(storage, (sender.clone(), Addr::unchecked(&validator)))? + .unwrap_or(Uint128::zero()); + + if current_bonded - amount.amount >= Uint128::zero() { + self.bonds.save( + storage, + (sender, Addr::unchecked(validator)), + &(current_bonded - amount.amount), + )?; + + Ok(AppResponse::default()) + } else { + Err(anyhow::anyhow!("bonded amount exceeded")) + } + } + } } fn sudo( @@ -45,7 +134,9 @@ impl Module for VirtualStakingModule<'_> { ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { - panic!("sudo not implemented for") + Err(anyhow::anyhow!( + "sudo not implemented for the virtual staking module" + )) } fn query( @@ -56,6 +147,26 @@ impl Module for VirtualStakingModule<'_> { block: &BlockInfo, request: Self::QueryT, ) -> AnyResult { - todo!() + let VirtualStakeCustomQuery::VirtualStake(query) = request; + + let result = match query { + mesh_bindings::VirtualStakeQuery::BondStatus { contract } => { + let denom = + QuerierWrapper::::new(querier).query_bonded_denom()?; + + let cap = self.caps.load(storage, Addr::unchecked(&contract))?; + let bonded = self.bonded_for_contract(storage, Addr::unchecked(contract))?; + + to_binary(&BondStatusResponse { + cap: coin(cap.u128(), &denom), + delegated: coin(bonded.u128(), denom), + })? + } + mesh_bindings::VirtualStakeQuery::SlashRatio {} => { + to_binary(&self.slash_ratio.load(storage)?)? + } + }; + + Ok(to_binary(&result)?) } } From d8e5278fd05e64375b4b5d71921bb1bfe76bffb3 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 16 Oct 2023 20:20:35 +0200 Subject: [PATCH 3/6] fix CI --- .github/workflows/basic.yml | 1 + packages/bindings/Cargo.toml | 2 +- packages/virtual-staking-mock/Cargo.toml | 3 +-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 81ec1ff5..459073c7 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -48,6 +48,7 @@ jobs: with: toolchain: 1.70.0 command: wasm + args: --workspace --exclude virtual-staking-mock env: RUSTFLAGS: "-C link-arg=-s" diff --git a/packages/bindings/Cargo.toml b/packages/bindings/Cargo.toml index 16879fc1..83435fb4 100644 --- a/packages/bindings/Cargo.toml +++ b/packages/bindings/Cargo.toml @@ -2,7 +2,7 @@ name = "mesh-bindings" version = { workspace = true } edition = { workspace = true } -license = { workspace = true } +license = { workspace = true } [dependencies] cosmwasm-std = { workspace = true } diff --git a/packages/virtual-staking-mock/Cargo.toml b/packages/virtual-staking-mock/Cargo.toml index a5118043..2eca514e 100644 --- a/packages/virtual-staking-mock/Cargo.toml +++ b/packages/virtual-staking-mock/Cargo.toml @@ -4,8 +4,7 @@ edition.workspace = true version.workspace = true license.workspace = true repository.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +publish = false [dependencies] anyhow = { workspace = true } From 1d192a8a9cdd6bd17bd16b51d1b7c531821a3340 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 16 Oct 2023 20:23:13 +0200 Subject: [PATCH 4/6] lints --- packages/virtual-staking-mock/src/lib.rs | 26 +++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/virtual-staking-mock/src/lib.rs b/packages/virtual-staking-mock/src/lib.rs index e1e8aefd..8ff88c55 100644 --- a/packages/virtual-staking-mock/src/lib.rs +++ b/packages/virtual-staking-mock/src/lib.rs @@ -56,6 +56,12 @@ impl VirtualStakingModule<'_> { } } +impl Default for VirtualStakingModule<'_> { + fn default() -> Self { + Self::new() + } +} + impl Module for VirtualStakingModule<'_> { type ExecT = VirtualStakeCustomMsg; @@ -65,10 +71,10 @@ impl Module for VirtualStakingModule<'_> { fn execute( &self, - api: &dyn Api, + _api: &dyn Api, storage: &mut dyn Storage, - router: &dyn cw_multi_test::CosmosRouter, - block: &BlockInfo, + _router: &dyn cw_multi_test::CosmosRouter, + _block: &BlockInfo, sender: Addr, msg: Self::ExecT, ) -> AnyResult @@ -124,11 +130,11 @@ impl Module for VirtualStakingModule<'_> { fn sudo( &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn cw_multi_test::CosmosRouter, - block: &BlockInfo, - msg: Self::SudoT, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn cw_multi_test::CosmosRouter, + _block: &BlockInfo, + _msg: Self::SudoT, ) -> AnyResult where ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, @@ -141,10 +147,10 @@ impl Module for VirtualStakingModule<'_> { fn query( &self, - api: &dyn Api, + _api: &dyn Api, storage: &dyn Storage, querier: &dyn Querier, - block: &BlockInfo, + _block: &BlockInfo, request: Self::QueryT, ) -> AnyResult { let VirtualStakeCustomQuery::VirtualStake(query) = request; From 89582ca59caed7fa4647ed7cc0855cdea73bd602 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 17 Oct 2023 16:43:13 +0200 Subject: [PATCH 5/6] VirtualStakingMock ergonomics --- Cargo.lock | 26 ++++++++++---------- Cargo.toml | 1 + packages/virtual-staking-mock/Cargo.toml | 2 +- packages/virtual-staking-mock/src/lib.rs | 30 ++++++++++++++++-------- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77896244..1c1bed5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -745,6 +745,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "mesh-virtual-staking-mock" +version = "0.7.0-alpha.2" +dependencies = [ + "anyhow", + "cosmwasm-std", + "cw-multi-test", + "cw-storage-plus", + "mesh-bindings", + "schemars", + "serde", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -1172,19 +1185,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "virtual-staking-mock" -version = "0.7.0-alpha.2" -dependencies = [ - "anyhow", - "cosmwasm-std", - "cw-multi-test", - "cw-storage-plus", - "mesh-bindings", - "schemars", - "serde", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 6fae8e0c..be0b4ca6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/osmosis-labs/mesh-security" mesh-apis = { path = "./packages/apis" } mesh-bindings = { path = "./packages/bindings" } mesh-sync = { path = "./packages/sync" } +mesh-virtual-staking-mock = { path = "./packages/virtual-staking-mock" } mesh-vault = { path = "./contracts/provider/vault" } mesh-external-staking = { path = "./contracts/provider/external-staking" } diff --git a/packages/virtual-staking-mock/Cargo.toml b/packages/virtual-staking-mock/Cargo.toml index 2eca514e..5909adbd 100644 --- a/packages/virtual-staking-mock/Cargo.toml +++ b/packages/virtual-staking-mock/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "virtual-staking-mock" +name = "mesh-virtual-staking-mock" edition.workspace = true version.workspace = true license.workspace = true diff --git a/packages/virtual-staking-mock/src/lib.rs b/packages/virtual-staking-mock/src/lib.rs index 8ff88c55..49cb0390 100644 --- a/packages/virtual-staking-mock/src/lib.rs +++ b/packages/virtual-staking-mock/src/lib.rs @@ -1,9 +1,11 @@ use anyhow::Result as AnyResult; use cosmwasm_std::{ - coin, to_binary, Addr, Api, Binary, BlockInfo, CustomQuery, Empty, Querier, QuerierWrapper, - Storage, Uint128, + coin, + testing::{MockApi, MockStorage}, + to_binary, Addr, Api, Binary, BlockInfo, CustomQuery, Empty, Querier, QuerierWrapper, Storage, + Uint128, }; -use cw_multi_test::{AppResponse, Module}; +use cw_multi_test::{AppResponse, BankKeeper, Module, WasmKeeper}; use cw_storage_plus::{Item, Map}; use mesh_bindings::{ BondStatusResponse, SlashRatioResponse, VirtualStakeCustomMsg, VirtualStakeCustomQuery, @@ -11,15 +13,23 @@ use mesh_bindings::{ use schemars::JsonSchema; use serde::de::DeserializeOwned; -pub struct VirtualStakingModule<'a> { +pub type App = cw_multi_test::App< + BankKeeper, + MockApi, + MockStorage, + VirtualStakingModule, + WasmKeeper, +>; + +pub struct VirtualStakingModule { /// virtual-staking contract -> max cap - caps: Map<'a, Addr, Uint128>, + caps: Map<'static, Addr, Uint128>, /// (virtual-staking contract, validator) -> bonded amount - bonds: Map<'a, (Addr, Addr), Uint128>, - slash_ratio: Item<'a, SlashRatioResponse>, + bonds: Map<'static, (Addr, Addr), Uint128>, + slash_ratio: Item<'static, SlashRatioResponse>, } -impl VirtualStakingModule<'_> { +impl VirtualStakingModule { pub fn new() -> Self { Self { caps: Map::new("virtual_staking_caps"), @@ -56,13 +66,13 @@ impl VirtualStakingModule<'_> { } } -impl Default for VirtualStakingModule<'_> { +impl Default for VirtualStakingModule { fn default() -> Self { Self::new() } } -impl Module for VirtualStakingModule<'_> { +impl Module for VirtualStakingModule { type ExecT = VirtualStakeCustomMsg; type QueryT = VirtualStakeCustomQuery; From ae5ac0e88a054a3a90d2ddcaabdeee9d16497c89 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 17 Oct 2023 16:51:52 +0200 Subject: [PATCH 6/6] fix CI --- .github/workflows/basic.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 459073c7..7b5d3ef4 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -48,7 +48,7 @@ jobs: with: toolchain: 1.70.0 command: wasm - args: --workspace --exclude virtual-staking-mock + args: --workspace --exclude mesh-virtual-staking-mock env: RUSTFLAGS: "-C link-arg=-s"