From 6649fb16cb193eac42224b1dfe8fa19bdfcd5d90 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 27 Jun 2024 12:35:34 +0700 Subject: [PATCH 01/29] add config module addr --- contracts/provider/external-staking/src/multitest.rs | 3 ++- contracts/provider/native-staking-proxy/src/multitest.rs | 2 ++ contracts/provider/native-staking/src/multitest.rs | 2 ++ contracts/provider/vault/src/contract.rs | 3 ++- contracts/provider/vault/src/multitest.rs | 3 ++- contracts/provider/vault/src/state.rs | 2 ++ 6 files changed, 12 insertions(+), 3 deletions(-) diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index 6893cb49..a1d66291 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -32,6 +32,7 @@ use utils::{ const OSMO: &str = "osmo"; const STAR: &str = "star"; +const MODULE_ADDR: &str = "MESH_SECURORY_PROVIDER"; /// 10% slashing on the remote chain const SLASHING_PERCENTAGE: u64 = 10; @@ -70,7 +71,7 @@ fn setup<'app>( }; let vault = vault_code - .instantiate(OSMO.to_owned(), Some(LocalStakingInfo::New(staking_init))) + .instantiate(OSMO.to_owned(), MODULE_ADDR.to_owned(), Some(LocalStakingInfo::New(staking_init))) .call(owner)?; let remote_contact = AuthorizedEndpoint::new("connection-2", "wasm-osmo1foobarbaz"); diff --git a/contracts/provider/native-staking-proxy/src/multitest.rs b/contracts/provider/native-staking-proxy/src/multitest.rs index 9dc18b44..cf4f6d12 100644 --- a/contracts/provider/native-staking-proxy/src/multitest.rs +++ b/contracts/provider/native-staking-proxy/src/multitest.rs @@ -17,6 +17,7 @@ use crate::contract::NativeStakingProxyContract; use crate::msg::ConfigResponse; const OSMO: &str = "uosmo"; +const MODULE_ADDR: &str = "MESH_SECURORY_PROVIDER"; const UNBONDING_PERIOD: u64 = 17 * 24 * 60 * 60; // 7 days fn init_app(owner: &str, validators: &[&str]) -> App { @@ -83,6 +84,7 @@ fn setup<'app>( let vault = vault_code .instantiate( OSMO.to_owned(), + MODULE_ADDR.to_owned(), Some(LocalStakingInfo::New(staking_init_info)), ) .with_label("Vault") diff --git a/contracts/provider/native-staking/src/multitest.rs b/contracts/provider/native-staking/src/multitest.rs index 375b1201..71868463 100644 --- a/contracts/provider/native-staking/src/multitest.rs +++ b/contracts/provider/native-staking/src/multitest.rs @@ -21,6 +21,7 @@ use crate::msg; use crate::msg::{OwnerByProxyResponse, ProxyByOwnerResponse}; const OSMO: &str = "OSMO"; +const MODULE_ADDR: &str = "MESH_SECURORY_PROVIDER"; const SLASHING_PERCENTAGE_DSIGN: u64 = 15; const SLASHING_PERCENTAGE_OFFLINE: u64 = 10; @@ -278,6 +279,7 @@ fn releasing_proxy_stake() { let vault = vault_code .instantiate( OSMO.to_owned(), + MODULE_ADDR.to_owned(), Some(LocalStakingInfo::New(staking_init_info)), ) .with_label("Vault") diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 04a0d0e6..accea950 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -90,11 +90,12 @@ impl VaultContract<'_> { &self, ctx: InstantiateCtx, denom: String, + module_addr: String, local_staking: Option, ) -> Result { nonpayable(&ctx.info)?; - let config = Config { denom }; + let config = Config { denom, module_addr }; self.config.save(ctx.deps.storage, &config)?; set_contract_version(ctx.deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index 73e3c33e..dcc1ade6 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -28,6 +28,7 @@ use crate::msg::{ const OSMO: &str = "OSMO"; const STAR: &str = "star"; +const MODULE_ADDR: &str = "MESH_SECURORY_PROVIDER"; /// 10% slashing on the remote chain const SLASHING_PERCENTAGE: u64 = 10; @@ -148,7 +149,7 @@ fn setup_inner<'app>( }; let vault = vault_code - .instantiate(OSMO.to_owned(), staking_init_info) + .instantiate(OSMO.to_owned(), MODULE_ADDR.to_owned(), staking_init_info) .with_label("Vault") .call(owner) .unwrap(); diff --git a/contracts/provider/vault/src/state.rs b/contracts/provider/vault/src/state.rs index c231f3a2..ffe368a4 100644 --- a/contracts/provider/vault/src/state.rs +++ b/contracts/provider/vault/src/state.rs @@ -7,6 +7,8 @@ use mesh_sync::{max_range, ValueRange}; pub struct Config { /// The denom we accept for staking (only native tokens) pub denom: String, + /// Mesh security provider module address + pub module_addr: String, } #[cw_serde] From c967bf0deace5d9808d9132fda6310551f512d07 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 27 Jun 2024 13:42:51 +0700 Subject: [PATCH 02/29] add sender param to bond func and modify tests --- .../external-staking/src/multitest.rs | 34 +++++++++---------- .../native-staking-proxy/src/multitest.rs | 2 +- .../provider/native-staking/src/multitest.rs | 2 +- contracts/provider/vault/src/contract.rs | 14 +++++--- contracts/provider/vault/src/multitest.rs | 2 +- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index a1d66291..2a38ab10 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -126,13 +126,13 @@ fn staking() { // Bond tokens vault - .bond() + .bond(users[0].to_owned()) .with_funds(&coins(300, OSMO)) .call(users[0]) .unwrap(); vault - .bond() + .bond(users[1].to_owned()) .with_funds(&coins(300, OSMO)) .call(users[1]) .unwrap(); @@ -233,13 +233,13 @@ fn unstaking() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond() + .bond(users[0].to_owned()) .with_funds(&coins(300, OSMO)) .call(users[0]) .unwrap(); vault - .bond() + .bond(users[1].to_owned()) .with_funds(&coins(300, OSMO)) .call(users[1]) .unwrap(); @@ -475,7 +475,7 @@ fn immediate_unstake_if_unbonded_validator() { let validators = contract.activate_validators(["validator1"]); vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); @@ -514,7 +514,7 @@ fn immediate_unstake_if_tombstoned_validator() { let validators = contract.activate_validators(["validator1"]); vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); @@ -561,13 +561,13 @@ fn distribution() { // 3/5 of validators[0] to users[1] // all of validators[1] to users[1] vault - .bond() + .bond(users[0].to_owned()) .with_funds(&coins(600, OSMO)) .call(users[0]) .unwrap(); vault - .bond() + .bond(users[1].to_owned()) .with_funds(&coins(600, OSMO)) .call(users[1]) .unwrap(); @@ -1165,12 +1165,12 @@ fn batch_distribution() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond() + .bond(users[0].to_owned()) .with_funds(&coins(600, OSMO)) .call(users[0]) .unwrap(); vault - .bond() + .bond(users[1].to_owned()) .with_funds(&coins(600, OSMO)) .call(users[1]) .unwrap(); @@ -1210,7 +1210,7 @@ fn batch_distribution_invalid_token() { let validator = contract.activate_validators(["validator1"])[0]; vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(600, OSMO)) .call(user) .unwrap(); @@ -1236,7 +1236,7 @@ fn slashing() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(300, OSMO)) .call(user) .unwrap(); @@ -1381,7 +1381,7 @@ fn slashing_pending_tx_partial_unbond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(300, OSMO)) .call(user) .unwrap(); @@ -1468,7 +1468,7 @@ fn slashing_pending_tx_full_unbond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); @@ -1551,7 +1551,7 @@ fn slashing_pending_tx_full_unbond_rolled_back() { let validators = contract.activate_validators(["validator1"]); vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); @@ -1632,7 +1632,7 @@ fn slashing_pending_tx_bond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(300, OSMO)) .call(user) .unwrap(); @@ -1717,7 +1717,7 @@ fn slashing_pending_tx_bond_rolled_back() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(300, OSMO)) .call(user) .unwrap(); diff --git a/contracts/provider/native-staking-proxy/src/multitest.rs b/contracts/provider/native-staking-proxy/src/multitest.rs index cf4f6d12..139cdc85 100644 --- a/contracts/provider/native-staking-proxy/src/multitest.rs +++ b/contracts/provider/native-staking-proxy/src/multitest.rs @@ -93,7 +93,7 @@ fn setup<'app>( // Bond some funds to the vault vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); diff --git a/contracts/provider/native-staking/src/multitest.rs b/contracts/provider/native-staking/src/multitest.rs index 71868463..d8b6f6b3 100644 --- a/contracts/provider/native-staking/src/multitest.rs +++ b/contracts/provider/native-staking/src/multitest.rs @@ -298,7 +298,7 @@ fn releasing_proxy_stake() { // User bonds some funds to the vault vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index accea950..46913128 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -141,20 +141,24 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx) -> Result { - let denom = self.config.load(ctx.deps.storage)?.denom; + fn bond(&self, ctx: ExecCtx, sender: String) -> Result { + let denom = self.config.load(ctx.deps.storage)?.denom; + let ctx_sender = ctx.info.sender.clone(); + + let sender_addr = ctx.deps.api.addr_validate(&sender)?; + ensure!(sender_addr == ctx_sender || self.config.load(ctx.deps.storage)?.module_addr == ctx_sender, ContractError::UnexpectedDenom(denom)); let amount = must_pay(&ctx.info, &denom)?; let mut user = self .users - .may_load(ctx.deps.storage, &ctx.info.sender)? + .may_load(ctx.deps.storage, &sender_addr)? .unwrap_or_default(); user.collateral += amount; - self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; + self.users.save(ctx.deps.storage, &sender_addr, &user)?; let resp = Response::new() .add_attribute("action", "bond") - .add_attribute("sender", ctx.info.sender) + .add_attribute("sender", &sender_addr) .add_attribute("amount", amount.to_string()); Ok(resp) diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index dcc1ade6..78705bb5 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -210,7 +210,7 @@ fn set_active_validators( /// Bond some tokens fn bond(vault: &Proxy<'_, MtApp, VaultContract<'_>>, user: &str, amount: u128) { vault - .bond() + .bond(user.to_owned()) .with_funds(&coins(amount, OSMO)) .call(user) .unwrap(); From 62087946c74e9176099116c4a03c9642d550c438 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Mon, 1 Jul 2024 10:54:11 +0700 Subject: [PATCH 03/29] handle unbond message from sdk --- contracts/provider/vault/src/contract.rs | 51 +++++++++++++---------- contracts/provider/vault/src/multitest.rs | 14 +++---- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 46913128..505dfc23 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - coin, ensure, Addr, BankMsg, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, - StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg, + coin, ensure, ensure_eq, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, + Response, StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg, }; use cw2::set_contract_version; use cw_storage_plus::{Bounder, Item, Map}; @@ -141,40 +141,53 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, sender: String) -> Result { - let denom = self.config.load(ctx.deps.storage)?.denom; - let ctx_sender = ctx.info.sender.clone(); - - let sender_addr = ctx.deps.api.addr_validate(&sender)?; - ensure!(sender_addr == ctx_sender || self.config.load(ctx.deps.storage)?.module_addr == ctx_sender, ContractError::UnexpectedDenom(denom)); + fn bond(&self, ctx: ExecCtx, delegator: String) -> Result { + let denom = self.config.load(ctx.deps.storage)?.denom; + let module_addr = self.config.load(ctx.deps.storage)?.module_addr; + + let delegator_addr = ctx.deps.api.addr_validate(&delegator)?; + ensure_eq!( + module_addr, + ctx.info.sender.to_string(), + ContractError::Unauthorized{} + ); + let amount = must_pay(&ctx.info, &denom)?; let mut user = self .users - .may_load(ctx.deps.storage, &sender_addr)? + .may_load(ctx.deps.storage, &delegator_addr)? .unwrap_or_default(); user.collateral += amount; - self.users.save(ctx.deps.storage, &sender_addr, &user)?; + self.users.save(ctx.deps.storage, &delegator_addr, &user)?; let resp = Response::new() .add_attribute("action", "bond") - .add_attribute("sender", &sender_addr) + .add_attribute("sender", &delegator_addr) .add_attribute("amount", amount.to_string()); Ok(resp) } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn unbond(&self, ctx: ExecCtx, delegator: String, amount: Coin) -> Result { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; - ensure!(denom == amount.denom, ContractError::UnexpectedDenom(denom)); + let module_addr = self.config.load(ctx.deps.storage)?.module_addr; + ensure_eq!( + module_addr, + ctx.info.sender.to_string(), + ContractError::Unauthorized{} + ); + + let delegator_addr = ctx.deps.api.addr_validate(&delegator)?; + let mut user = self .users - .may_load(ctx.deps.storage, &ctx.info.sender)? + .may_load(ctx.deps.storage, &delegator_addr)? .unwrap_or_default(); let free_collateral = user.free_collateral(); @@ -184,17 +197,11 @@ impl VaultContract<'_> { ); user.collateral -= amount.amount; - self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; - - let msg = BankMsg::Send { - to_address: ctx.info.sender.to_string(), - amount: vec![amount.clone()], - }; + self.users.save(ctx.deps.storage, &delegator_addr, &user)?; let resp = Response::new() - .add_message(msg) .add_attribute("action", "unbond") - .add_attribute("sender", ctx.info.sender) + .add_attribute("delegator_address", delegator_addr) .add_attribute("amount", amount.to_string()); Ok(resp) diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index 78705bb5..2d63fbbf 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -394,7 +394,7 @@ fn bonding() { // Unbond some tokens - vault.unbond(coin(200, OSMO)).call(user).unwrap(); + vault.unbond(user.to_owned(), coin(200, OSMO)).call(user).unwrap(); assert_eq!( vault.account(user.to_owned()).unwrap(), AccountResponse { @@ -417,7 +417,7 @@ fn bonding() { coin(50, OSMO) ); - vault.unbond(coin(20, OSMO)).call(user).unwrap(); + vault.unbond(user.to_owned(), coin(20, OSMO)).call(user).unwrap(); assert_eq!( vault.account(user.to_owned()).unwrap(), AccountResponse { @@ -442,7 +442,7 @@ fn bonding() { // Unbonding over bounded fails - let err = vault.unbond(coin(100, OSMO)).call(user).unwrap_err(); + let err = vault.unbond(user.to_owned(), coin(100, OSMO)).call(user).unwrap_err(); assert_eq!( err, ContractError::ClaimsLocked(ValueRange::new_val(Uint128::new(30))) @@ -594,7 +594,7 @@ fn stake_local() { // Cannot unbond used collateral - let err = vault.unbond(coin(100, OSMO)).call(user).unwrap_err(); + let err = vault.unbond(user.to_owned(), coin(100, OSMO)).call(user).unwrap_err(); assert_eq!( err, ContractError::ClaimsLocked(ValueRange::new_val(Uint128::new(50))) @@ -888,7 +888,7 @@ fn stake_cross() { // Cannot unbond used collateral - let err = vault.unbond(coin(100, OSMO)).call(user).unwrap_err(); + let err = vault.unbond(user.to_owned(), coin(100, OSMO)).call(user).unwrap_err(); assert_eq!( err, ContractError::ClaimsLocked(ValueRange::new_val(Uint128::new(50))) @@ -1592,7 +1592,7 @@ fn all_users_fetching() { // After unbonding some, but not all collateral, user shall still be visible - vault.unbond(coin(50, OSMO)).call(users[0]).unwrap(); + vault.unbond(users[0].to_owned(), coin(50, OSMO)).call(users[0]).unwrap(); let accounts = vault.all_accounts(false, None, None).unwrap(); assert_eq!( @@ -1641,7 +1641,7 @@ fn all_users_fetching() { ); // Unbonding all the collateral hides the user when the collateral flag is set - vault.unbond(coin(200, OSMO)).call(users[1]).unwrap(); + vault.unbond(users[1].to_owned(),coin(200, OSMO)).call(users[1]).unwrap(); let accounts = vault.all_accounts(false, None, None).unwrap(); assert_eq!( From 37641412e94a1c2358b008ad2fb3f919b77e7bb7 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Wed, 3 Jul 2024 12:08:23 +0700 Subject: [PATCH 04/29] revert adding config and func params --- .../external-staking/src/multitest.rs | 54 +++++++------------ .../native-staking-proxy/src/multitest.rs | 5 +- .../provider/native-staking/src/multitest.rs | 5 +- contracts/provider/vault/src/contract.rs | 45 +++++----------- contracts/provider/vault/src/multitest.rs | 22 ++++---- contracts/provider/vault/src/state.rs | 2 - 6 files changed, 44 insertions(+), 89 deletions(-) diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index 2a38ab10..ff249fe9 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -32,7 +32,6 @@ use utils::{ const OSMO: &str = "osmo"; const STAR: &str = "star"; -const MODULE_ADDR: &str = "MESH_SECURORY_PROVIDER"; /// 10% slashing on the remote chain const SLASHING_PERCENTAGE: u64 = 10; @@ -71,7 +70,7 @@ fn setup<'app>( }; let vault = vault_code - .instantiate(OSMO.to_owned(), MODULE_ADDR.to_owned(), Some(LocalStakingInfo::New(staking_init))) + .instantiate(OSMO.to_owned(), Some(LocalStakingInfo::New(staking_init))) .call(owner)?; let remote_contact = AuthorizedEndpoint::new("connection-2", "wasm-osmo1foobarbaz"); @@ -126,14 +125,12 @@ fn staking() { // Bond tokens vault - .bond(users[0].to_owned()) - .with_funds(&coins(300, OSMO)) + .bond(coin(300, OSMO)) .call(users[0]) .unwrap(); vault - .bond(users[1].to_owned()) - .with_funds(&coins(300, OSMO)) + .bond(coin(300, OSMO)) .call(users[1]) .unwrap(); @@ -233,14 +230,12 @@ fn unstaking() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(users[0].to_owned()) - .with_funds(&coins(300, OSMO)) + .bond(coin(300, OSMO)) .call(users[0]) .unwrap(); vault - .bond(users[1].to_owned()) - .with_funds(&coins(300, OSMO)) + .bond(coin(300, OSMO)) .call(users[1]) .unwrap(); @@ -475,8 +470,7 @@ fn immediate_unstake_if_unbonded_validator() { let validators = contract.activate_validators(["validator1"]); vault - .bond(user.to_owned()) - .with_funds(&coins(200, OSMO)) + .bond(coin(200, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -514,8 +508,7 @@ fn immediate_unstake_if_tombstoned_validator() { let validators = contract.activate_validators(["validator1"]); vault - .bond(user.to_owned()) - .with_funds(&coins(200, OSMO)) + .bond(coin(200, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -561,14 +554,12 @@ fn distribution() { // 3/5 of validators[0] to users[1] // all of validators[1] to users[1] vault - .bond(users[0].to_owned()) - .with_funds(&coins(600, OSMO)) + .bond(coin(600, OSMO)) .call(users[0]) .unwrap(); vault - .bond(users[1].to_owned()) - .with_funds(&coins(600, OSMO)) + .bond(coin(600, OSMO)) .call(users[1]) .unwrap(); @@ -1165,13 +1156,11 @@ fn batch_distribution() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(users[0].to_owned()) - .with_funds(&coins(600, OSMO)) + .bond(coin(600, OSMO)) .call(users[0]) .unwrap(); vault - .bond(users[1].to_owned()) - .with_funds(&coins(600, OSMO)) + .bond(coin(600, OSMO)) .call(users[1]) .unwrap(); @@ -1210,8 +1199,7 @@ fn batch_distribution_invalid_token() { let validator = contract.activate_validators(["validator1"])[0]; vault - .bond(user.to_owned()) - .with_funds(&coins(600, OSMO)) + .bond(coin(600, OSMO)) .call(user) .unwrap(); @@ -1236,8 +1224,7 @@ fn slashing() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(user.to_owned()) - .with_funds(&coins(300, OSMO)) + .bond(coin(300, OSMO)) .call(user) .unwrap(); @@ -1381,8 +1368,7 @@ fn slashing_pending_tx_partial_unbond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(user.to_owned()) - .with_funds(&coins(300, OSMO)) + .bond(coin(300, OSMO)) .call(user) .unwrap(); @@ -1468,8 +1454,7 @@ fn slashing_pending_tx_full_unbond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(user.to_owned()) - .with_funds(&coins(200, OSMO)) + .bond(coin(200, OSMO)) .call(user) .unwrap(); @@ -1551,8 +1536,7 @@ fn slashing_pending_tx_full_unbond_rolled_back() { let validators = contract.activate_validators(["validator1"]); vault - .bond(user.to_owned()) - .with_funds(&coins(200, OSMO)) + .bond(coin(200, OSMO)) .call(user) .unwrap(); @@ -1632,8 +1616,7 @@ fn slashing_pending_tx_bond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(user.to_owned()) - .with_funds(&coins(300, OSMO)) + .bond(coin(300, OSMO)) .call(user) .unwrap(); @@ -1717,8 +1700,7 @@ fn slashing_pending_tx_bond_rolled_back() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(user.to_owned()) - .with_funds(&coins(300, OSMO)) + .bond(coin(300, OSMO)) .call(user) .unwrap(); diff --git a/contracts/provider/native-staking-proxy/src/multitest.rs b/contracts/provider/native-staking-proxy/src/multitest.rs index 139cdc85..1982fa21 100644 --- a/contracts/provider/native-staking-proxy/src/multitest.rs +++ b/contracts/provider/native-staking-proxy/src/multitest.rs @@ -17,7 +17,6 @@ use crate::contract::NativeStakingProxyContract; use crate::msg::ConfigResponse; const OSMO: &str = "uosmo"; -const MODULE_ADDR: &str = "MESH_SECURORY_PROVIDER"; const UNBONDING_PERIOD: u64 = 17 * 24 * 60 * 60; // 7 days fn init_app(owner: &str, validators: &[&str]) -> App { @@ -84,7 +83,6 @@ fn setup<'app>( let vault = vault_code .instantiate( OSMO.to_owned(), - MODULE_ADDR.to_owned(), Some(LocalStakingInfo::New(staking_init_info)), ) .with_label("Vault") @@ -93,8 +91,7 @@ fn setup<'app>( // Bond some funds to the vault vault - .bond(user.to_owned()) - .with_funds(&coins(200, OSMO)) + .bond(coin(200, OSMO)) .call(user) .unwrap(); diff --git a/contracts/provider/native-staking/src/multitest.rs b/contracts/provider/native-staking/src/multitest.rs index d8b6f6b3..6e088c43 100644 --- a/contracts/provider/native-staking/src/multitest.rs +++ b/contracts/provider/native-staking/src/multitest.rs @@ -21,7 +21,6 @@ use crate::msg; use crate::msg::{OwnerByProxyResponse, ProxyByOwnerResponse}; const OSMO: &str = "OSMO"; -const MODULE_ADDR: &str = "MESH_SECURORY_PROVIDER"; const SLASHING_PERCENTAGE_DSIGN: u64 = 15; const SLASHING_PERCENTAGE_OFFLINE: u64 = 10; @@ -279,7 +278,6 @@ fn releasing_proxy_stake() { let vault = vault_code .instantiate( OSMO.to_owned(), - MODULE_ADDR.to_owned(), Some(LocalStakingInfo::New(staking_init_info)), ) .with_label("Vault") @@ -298,8 +296,7 @@ fn releasing_proxy_stake() { // User bonds some funds to the vault vault - .bond(user.to_owned()) - .with_funds(&coins(200, OSMO)) + .bond(coin(200, OSMO)) .call(user) .unwrap(); diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 505dfc23..ae3097bb 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - coin, ensure, ensure_eq, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, + coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg, }; use cw2::set_contract_version; @@ -90,12 +90,11 @@ impl VaultContract<'_> { &self, ctx: InstantiateCtx, denom: String, - module_addr: String, local_staking: Option, ) -> Result { nonpayable(&ctx.info)?; - let config = Config { denom, module_addr }; + let config = Config { denom }; self.config.save(ctx.deps.storage, &config)?; set_contract_version(ctx.deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; @@ -141,53 +140,37 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, delegator: String) -> Result { - let denom = self.config.load(ctx.deps.storage)?.denom; - let module_addr = self.config.load(ctx.deps.storage)?.module_addr; - - let delegator_addr = ctx.deps.api.addr_validate(&delegator)?; - ensure_eq!( - module_addr, - ctx.info.sender.to_string(), - ContractError::Unauthorized{} - ); + fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result { + nonpayable(&ctx.info)?; - let amount = must_pay(&ctx.info, &denom)?; + let denom = self.config.load(ctx.deps.storage)?.denom; + ensure!(denom == amount.denom, ContractError::UnexpectedDenom(denom)); let mut user = self .users - .may_load(ctx.deps.storage, &delegator_addr)? + .may_load(ctx.deps.storage, &ctx.info.sender)? .unwrap_or_default(); - user.collateral += amount; - self.users.save(ctx.deps.storage, &delegator_addr, &user)?; + user.collateral += amount.amount; + self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let resp = Response::new() .add_attribute("action", "bond") - .add_attribute("sender", &delegator_addr) + .add_attribute("sender", &ctx.info.sender) .add_attribute("amount", amount.to_string()); Ok(resp) } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, delegator: String, amount: Coin) -> Result { + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; ensure!(denom == amount.denom, ContractError::UnexpectedDenom(denom)); - let module_addr = self.config.load(ctx.deps.storage)?.module_addr; - ensure_eq!( - module_addr, - ctx.info.sender.to_string(), - ContractError::Unauthorized{} - ); - - let delegator_addr = ctx.deps.api.addr_validate(&delegator)?; - let mut user = self .users - .may_load(ctx.deps.storage, &delegator_addr)? + .may_load(ctx.deps.storage, &ctx.info.sender)? .unwrap_or_default(); let free_collateral = user.free_collateral(); @@ -197,11 +180,11 @@ impl VaultContract<'_> { ); user.collateral -= amount.amount; - self.users.save(ctx.deps.storage, &delegator_addr, &user)?; + self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let resp = Response::new() .add_attribute("action", "unbond") - .add_attribute("delegator_address", delegator_addr) + .add_attribute("delegator_address", &ctx.info.sender) .add_attribute("amount", amount.to_string()); Ok(resp) diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index 2d63fbbf..0166b9d3 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -28,7 +28,6 @@ use crate::msg::{ const OSMO: &str = "OSMO"; const STAR: &str = "star"; -const MODULE_ADDR: &str = "MESH_SECURORY_PROVIDER"; /// 10% slashing on the remote chain const SLASHING_PERCENTAGE: u64 = 10; @@ -149,7 +148,7 @@ fn setup_inner<'app>( }; let vault = vault_code - .instantiate(OSMO.to_owned(), MODULE_ADDR.to_owned(), staking_init_info) + .instantiate(OSMO.to_owned(), staking_init_info) .with_label("Vault") .call(owner) .unwrap(); @@ -210,12 +209,11 @@ fn set_active_validators( /// Bond some tokens fn bond(vault: &Proxy<'_, MtApp, VaultContract<'_>>, user: &str, amount: u128) { vault - .bond(user.to_owned()) - .with_funds(&coins(amount, OSMO)) + .bond(coin(amount, OSMO)) .call(user) .unwrap(); } - + fn stake_locally( vault: &Proxy<'_, MtApp, VaultContract<'_>>, user: &str, @@ -394,7 +392,7 @@ fn bonding() { // Unbond some tokens - vault.unbond(user.to_owned(), coin(200, OSMO)).call(user).unwrap(); + vault.unbond(coin(200, OSMO)).call(user).unwrap(); assert_eq!( vault.account(user.to_owned()).unwrap(), AccountResponse { @@ -417,7 +415,7 @@ fn bonding() { coin(50, OSMO) ); - vault.unbond(user.to_owned(), coin(20, OSMO)).call(user).unwrap(); + vault.unbond(coin(20, OSMO)).call(user).unwrap(); assert_eq!( vault.account(user.to_owned()).unwrap(), AccountResponse { @@ -442,7 +440,7 @@ fn bonding() { // Unbonding over bounded fails - let err = vault.unbond(user.to_owned(), coin(100, OSMO)).call(user).unwrap_err(); + let err = vault.unbond(coin(100, OSMO)).call(user).unwrap_err(); assert_eq!( err, ContractError::ClaimsLocked(ValueRange::new_val(Uint128::new(30))) @@ -594,7 +592,7 @@ fn stake_local() { // Cannot unbond used collateral - let err = vault.unbond(user.to_owned(), coin(100, OSMO)).call(user).unwrap_err(); + let err = vault.unbond(coin(100, OSMO)).call(user).unwrap_err(); assert_eq!( err, ContractError::ClaimsLocked(ValueRange::new_val(Uint128::new(50))) @@ -888,7 +886,7 @@ fn stake_cross() { // Cannot unbond used collateral - let err = vault.unbond(user.to_owned(), coin(100, OSMO)).call(user).unwrap_err(); + let err = vault.unbond(coin(100, OSMO)).call(user).unwrap_err(); assert_eq!( err, ContractError::ClaimsLocked(ValueRange::new_val(Uint128::new(50))) @@ -1592,7 +1590,7 @@ fn all_users_fetching() { // After unbonding some, but not all collateral, user shall still be visible - vault.unbond(users[0].to_owned(), coin(50, OSMO)).call(users[0]).unwrap(); + vault.unbond(coin(50, OSMO)).call(users[0]).unwrap(); let accounts = vault.all_accounts(false, None, None).unwrap(); assert_eq!( @@ -1641,7 +1639,7 @@ fn all_users_fetching() { ); // Unbonding all the collateral hides the user when the collateral flag is set - vault.unbond(users[1].to_owned(),coin(200, OSMO)).call(users[1]).unwrap(); + vault.unbond(coin(200, OSMO)).call(users[1]).unwrap(); let accounts = vault.all_accounts(false, None, None).unwrap(); assert_eq!( diff --git a/contracts/provider/vault/src/state.rs b/contracts/provider/vault/src/state.rs index ffe368a4..c231f3a2 100644 --- a/contracts/provider/vault/src/state.rs +++ b/contracts/provider/vault/src/state.rs @@ -7,8 +7,6 @@ use mesh_sync::{max_range, ValueRange}; pub struct Config { /// The denom we accept for staking (only native tokens) pub denom: String, - /// Mesh security provider module address - pub module_addr: String, } #[cw_serde] From 0e37ad1d4d9222b4f27fca575161010cc7fafc61 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Wed, 3 Jul 2024 12:10:15 +0700 Subject: [PATCH 05/29] revert unused --- contracts/provider/vault/src/contract.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index ae3097bb..9bbdf2da 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, - Response, StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg, + coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, + StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg, }; use cw2::set_contract_version; use cw_storage_plus::{Bounder, Item, Map}; @@ -155,7 +155,7 @@ impl VaultContract<'_> { let resp = Response::new() .add_attribute("action", "bond") - .add_attribute("sender", &ctx.info.sender) + .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amount.to_string()); Ok(resp) @@ -180,11 +180,11 @@ impl VaultContract<'_> { ); user.collateral -= amount.amount; - self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; + self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let resp = Response::new() .add_attribute("action", "unbond") - .add_attribute("delegator_address", &ctx.info.sender) + .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amount.to_string()); Ok(resp) From a9b50dd9ad01a2e42886dbe5c3e30091d91d32d8 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Wed, 3 Jul 2024 12:11:26 +0700 Subject: [PATCH 06/29] remove tab spacing --- contracts/provider/vault/src/multitest.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index 0166b9d3..dcca7d37 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -208,12 +208,9 @@ fn set_active_validators( /// Bond some tokens fn bond(vault: &Proxy<'_, MtApp, VaultContract<'_>>, user: &str, amount: u128) { - vault - .bond(coin(amount, OSMO)) - .call(user) - .unwrap(); + vault.bond(coin(amount, OSMO)).call(user).unwrap(); } - + fn stake_locally( vault: &Proxy<'_, MtApp, VaultContract<'_>>, user: &str, From 3c31f0c9bc68935452ec2c26456e7b002d5da52d Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 4 Jul 2024 10:36:45 +0700 Subject: [PATCH 07/29] add provider binding msg --- contracts/provider/vault/Cargo.toml | 1 + contracts/provider/vault/src/contract.rs | 6 +++ packages/bindings/src/msg.rs | 57 ++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/contracts/provider/vault/Cargo.toml b/contracts/provider/vault/Cargo.toml index e5fafea8..aa3c44f0 100644 --- a/contracts/provider/vault/Cargo.toml +++ b/contracts/provider/vault/Cargo.toml @@ -21,6 +21,7 @@ mt = ["library", "sylvia/mt"] [dependencies] mesh-apis = { workspace = true } mesh-sync = { workspace = true } +mesh_bindings = { workspace = true } sylvia = { workspace = true } cosmwasm-schema = { workspace = true } diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 9bbdf2da..a1d1acbd 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -12,8 +12,12 @@ use mesh_apis::local_staking_api::{ sv::LocalStakingApiQueryMsg, LocalStakingApiHelper, SlashRatioResponse, }; use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; +use mesh_bindings::{ + VaultCustomMsg, VaultMsg, +}; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; + use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, ReplyCtx}; use sylvia::{contract, schemars}; @@ -154,6 +158,7 @@ impl VaultContract<'_> { self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let resp = Response::new() + .add_message(VaultMsg::Bond { delegator: ctx.info.sender, amount}) .add_attribute("action", "bond") .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amount.to_string()); @@ -183,6 +188,7 @@ impl VaultContract<'_> { self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let resp = Response::new() + .add_message(VaultMsg::Unbond { delegator: ctx.info.sender, amount}) .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amount.to_string()); diff --git a/packages/bindings/src/msg.rs b/packages/bindings/src/msg.rs index 4ecce123..9aec8654 100644 --- a/packages/bindings/src/msg.rs +++ b/packages/bindings/src/msg.rs @@ -63,3 +63,60 @@ impl From for CosmosMsg { } impl CustomMsg for VirtualStakeCustomMsg {} + +/// A top-level Custom message for the meshsecurityprovider module. +/// It is embedded like this to easily allow adding other variants that are custom +/// to your chain, or other "standardized" extensions along side it. +#[cw_serde] +pub enum VaultCustomMsg { + Vault(VaultMsg), +} + +/// Special messages to be supported by any chain that supports meshsecurityprovider +#[cw_serde] +pub enum VaultMsg { + /// Bond will enforce the calling contract is the vault contract. + /// It ensures amount.denom is the native staking denom. + /// + /// If these conditions are met, it will bond amount.amount tokens + /// to the vault. + Bond { delegator: String, amount: Coin }, + /// Unbond ensures that amount.denom is the native staking denom and + /// the calling contract is the vault contract. + /// + /// If these conditions are met, it will instantly unbond + /// amount.amount tokens from the vault contract. + Unbond { delegator: String, amount: Coin }, +} + +impl VaultMsg { + pub fn bond(denom: &str, delegator: &str, amount: impl Into) -> VaultMsg { + let coin = Coin { + amount: amount.into(), + denom: denom.into(), + }; + VaultMsg::Bond { + delegator: delegator.to_string(), + amount: coin, + } + } + + pub fn unbond(denom: &str, delegator: &str, amount: impl Into) -> VaultMsg { + let coin = Coin { + amount: amount.into(), + denom: denom.into(), + }; + VaultMsg::Unbond { + delegator: delegator.to_string(), + amount: coin, + } + } +} + +impl From for CosmosMsg { + fn from(msg: VaultMsg) -> CosmosMsg { + CosmosMsg::Custom(VaultCustomMsg::Vault(msg)) + } +} + +impl CustomMsg for VaultCustomMsg {} From ae41e935233c524fa32cb33ef80193a1b744753a Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 4 Jul 2024 12:13:09 +0700 Subject: [PATCH 08/29] add dependencies --- Cargo.lock | 1 + contracts/provider/vault/Cargo.toml | 2 +- packages/bindings/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0df67f14..b2f0dab3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -771,6 +771,7 @@ dependencies = [ "cw2", "derivative", "mesh-apis", + "mesh-bindings", "mesh-external-staking", "mesh-native-staking", "mesh-native-staking-proxy", diff --git a/contracts/provider/vault/Cargo.toml b/contracts/provider/vault/Cargo.toml index aa3c44f0..9969f529 100644 --- a/contracts/provider/vault/Cargo.toml +++ b/contracts/provider/vault/Cargo.toml @@ -21,7 +21,7 @@ mt = ["library", "sylvia/mt"] [dependencies] mesh-apis = { workspace = true } mesh-sync = { workspace = true } -mesh_bindings = { workspace = true } +mesh-bindings = { workspace = true } sylvia = { workspace = true } cosmwasm-schema = { workspace = true } diff --git a/packages/bindings/src/lib.rs b/packages/bindings/src/lib.rs index 15d8f55e..4005a29c 100644 --- a/packages/bindings/src/lib.rs +++ b/packages/bindings/src/lib.rs @@ -1,7 +1,7 @@ mod msg; mod query; -pub use msg::{VirtualStakeCustomMsg, VirtualStakeMsg}; +pub use msg::{VirtualStakeCustomMsg, VirtualStakeMsg, VaultCustomMsg, VaultMsg}; pub use query::{ BondStatusResponse, SlashRatioResponse, TokenQuerier, VirtualStakeCustomQuery, VirtualStakeQuery, From de9759aefaf444dde1348eb746c75651b9dfd216 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 4 Jul 2024 13:56:34 +0700 Subject: [PATCH 09/29] impl custom response for vault messgae --- contracts/provider/vault/Cargo.toml | 2 + contracts/provider/vault/src/contract.rs | 44 ++++++++++++------- .../provider/vault/src/contract/custom.rs | 2 + packages/apis/src/vault_api.rs | 15 ++++--- packages/bindings/src/msg.rs | 2 +- 5 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 contracts/provider/vault/src/contract/custom.rs diff --git a/contracts/provider/vault/Cargo.toml b/contracts/provider/vault/Cargo.toml index 9969f529..31a3ac95 100644 --- a/contracts/provider/vault/Cargo.toml +++ b/contracts/provider/vault/Cargo.toml @@ -17,6 +17,8 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] +# enable this for multi-tests where you need custom messages for compatibility with virtual staking +fake-custom = [] [dependencies] mesh-apis = { workspace = true } diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index a1d1acbd..f4fb676e 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -1,6 +1,5 @@ use cosmwasm_std::{ - coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, - StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg, + coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg }; use cw2::set_contract_version; use cw_storage_plus::{Bounder, Item, Map}; @@ -48,6 +47,16 @@ fn def_false() -> bool { false } +#[cfg(not(feature = "fake-custom"))] +pub mod custom { + pub type VaultContractMsg = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} +#[cfg(feature = "fake-custom")] +pub mod custom { + pub type VaultContractMsg = mesh_bindings::VaultCustomMsg; + pub type Response = cosmwasm_std::Response; +} pub struct VaultContract<'a> { /// General contract configuration pub config: Item<'a, Config>, @@ -70,6 +79,8 @@ pub struct VaultContract<'a> { #[contract] #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] +/// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. +#[sv::custom(msg=custom::VaultContractMsg)] impl VaultContract<'_> { pub fn new() -> Self { Self { @@ -95,7 +106,7 @@ impl VaultContract<'_> { ctx: InstantiateCtx, denom: String, local_staking: Option, - ) -> Result { + ) -> Result { nonpayable(&ctx.info)?; let config = Config { denom }; @@ -144,7 +155,7 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -156,9 +167,8 @@ impl VaultContract<'_> { .unwrap_or_default(); user.collateral += amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; - + // let msg = VaultMsg::Bond { delegator: ctx.info.sender.into_string(), amount}; let resp = Response::new() - .add_message(VaultMsg::Bond { delegator: ctx.info.sender, amount}) .add_attribute("action", "bond") .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amount.to_string()); @@ -167,7 +177,7 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -187,8 +197,7 @@ impl VaultContract<'_> { user.collateral -= amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; - let resp = Response::new() - .add_message(VaultMsg::Unbond { delegator: ctx.info.sender, amount}) + let resp = custom::Response::new() .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amount.to_string()); @@ -207,7 +216,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result { + ) -> Result { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -254,7 +263,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result { + ) -> Result { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -982,6 +991,7 @@ impl Default for VaultContract<'_> { impl VaultApi for VaultContract<'_> { type Error = ContractError; + type ExecC = custom::VaultContractMsg; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( @@ -991,7 +1001,7 @@ impl VaultApi for VaultContract<'_> { owner: String, // amount to unstake on that contract amount: Coin, - ) -> Result { + ) -> Result { nonpayable(&ctx.info)?; self.unstake(&mut ctx, owner.clone(), amount.clone())?; @@ -1012,7 +1022,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, // address of the user who originally called stake_remote owner: String, - ) -> Result { + ) -> Result { let denom = self.config.load(ctx.deps.storage)?.denom; let amount = must_pay(&ctx.info, &denom)?; @@ -1033,7 +1043,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, slashes: Vec, validator: String, - ) -> Result { + ) -> Result { nonpayable(&ctx.info)?; let msgs = self.slash(&mut ctx, &slashes, &validator)?; @@ -1061,7 +1071,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, slashes: Vec, validator: String, - ) -> Result { + ) -> Result { nonpayable(&ctx.info)?; let msgs = self.slash(&mut ctx, &slashes, &validator)?; @@ -1083,7 +1093,7 @@ impl VaultApi for VaultContract<'_> { Ok(resp) } - fn commit_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result { + fn commit_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result { self.commit_stake(&mut ctx, tx_id)?; let resp = Response::new() @@ -1094,7 +1104,7 @@ impl VaultApi for VaultContract<'_> { Ok(resp) } - fn rollback_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result { + fn rollback_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result { self.rollback_stake(&mut ctx, tx_id)?; let resp = Response::new() diff --git a/contracts/provider/vault/src/contract/custom.rs b/contracts/provider/vault/src/contract/custom.rs new file mode 100644 index 00000000..7da9ffe4 --- /dev/null +++ b/contracts/provider/vault/src/contract/custom.rs @@ -0,0 +1,2 @@ +pub type VaultContractMsg = mesh_bindings::VaultCustomMsg; +pub type Response = cosmwasm_std::Response; diff --git a/packages/apis/src/vault_api.rs b/packages/apis/src/vault_api.rs index 9d051627..8e2a4d08 100644 --- a/packages/apis/src/vault_api.rs +++ b/packages/apis/src/vault_api.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{to_json_binary, Addr, Coin, Response, StdError, Uint128, WasmMsg}; +use cosmwasm_std::{to_json_binary, Addr, Coin, Response, StdError, Uint128, CustomMsg, WasmMsg}; use sylvia::types::ExecCtx; use sylvia::{interface, schemars}; @@ -8,6 +8,7 @@ use sylvia::{interface, schemars}; #[interface] pub trait VaultApi { type Error: From; + type ExecC: CustomMsg; /// This must be called by the remote staking contract to release this claim #[sv::msg(exec)] @@ -18,7 +19,7 @@ pub trait VaultApi { owner: String, // amount to unstake on that contract amount: Coin, - ) -> Result; + ) -> Result, Self::Error>; /// This must be called by the local staking contract to release this claim /// Amount of tokens unstaked are those included in ctx.info.funds @@ -28,17 +29,17 @@ pub trait VaultApi { ctx: ExecCtx, // address of the user who originally called stake_remote owner: String, - ) -> Result; + ) -> Result, Self::Error>; /// This must be called by the remote staking contract to commit the remote staking call on success. /// Transaction ID is used to identify the original (vault contract originated) transaction. #[sv::msg(exec)] - fn commit_tx(&self, ctx: ExecCtx, tx_id: u64) -> Result; + fn commit_tx(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; /// This must be called by the remote staking contract to rollback the remote staking call on failure. /// Transaction ID is used to identify the original (vault contract originated) transaction. #[sv::msg(exec)] - fn rollback_tx(&self, ctx: ExecCtx, tx_id: u64) -> Result; + fn rollback_tx(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; /// This must be called by the native staking contract to process a slashing event /// because of a misbehaviour on the Provider chain. @@ -50,7 +51,7 @@ pub trait VaultApi { ctx: ExecCtx, slashes: Vec, validator: String, - ) -> Result; + ) -> Result, Self::Error>; /// This must be called by the external staking contract to process a slashing event /// because of a misbehaviour on the Consumer chain. @@ -62,7 +63,7 @@ pub trait VaultApi { ctx: ExecCtx, slashes: Vec, validator: String, - ) -> Result; + ) -> Result, Self::Error>; } #[cw_serde] diff --git a/packages/bindings/src/msg.rs b/packages/bindings/src/msg.rs index 9aec8654..e4d3b8ba 100644 --- a/packages/bindings/src/msg.rs +++ b/packages/bindings/src/msg.rs @@ -81,7 +81,7 @@ pub enum VaultMsg { /// If these conditions are met, it will bond amount.amount tokens /// to the vault. Bond { delegator: String, amount: Coin }, - /// Unbond ensures that amount.denom is the native staking denom and + /// Unbond ensures that amount.denom is the native staking denom and /// the calling contract is the vault contract. /// /// If these conditions are met, it will instantly unbond From 00db35db8ea165a3a3acf7aabd48ec76138be851 Mon Sep 17 00:00:00 2001 From: Trinity Date: Thu, 4 Jul 2024 14:08:57 +0700 Subject: [PATCH 10/29] Add fake custom to all workspace using mesh-vault --- contracts/consumer/converter/Cargo.toml | 2 +- contracts/provider/external-staking/Cargo.toml | 3 ++- contracts/provider/native-staking-proxy/Cargo.toml | 3 ++- contracts/provider/native-staking/Cargo.toml | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/contracts/consumer/converter/Cargo.toml b/contracts/consumer/converter/Cargo.toml index a152fbeb..bddd93fe 100644 --- a/contracts/consumer/converter/Cargo.toml +++ b/contracts/consumer/converter/Cargo.toml @@ -37,7 +37,7 @@ thiserror = { workspace = true } [dev-dependencies] mesh-burn = { workspace = true } -mesh-simple-price-feed = { workspace = true, features = ["mt"] } +mesh-simple-price-feed = { workspace = true, features = ["mt", "fake-custom"] } cw-multi-test = { workspace = true } test-case = { workspace = true } diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index 1056ac3c..6e7015ce 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -16,6 +16,7 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] +fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } @@ -37,7 +38,7 @@ thiserror = { workspace = true } sylvia = { workspace = true, features = ["mt"] } cw-multi-test = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt"] } +mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } mesh-native-staking-proxy = { workspace = true, features = ["mt"] } mesh-native-staking = { workspace = true, features = ["mt"] } mesh-sync = { workspace = true } diff --git a/contracts/provider/native-staking-proxy/Cargo.toml b/contracts/provider/native-staking-proxy/Cargo.toml index a8210310..a6f349d0 100644 --- a/contracts/provider/native-staking-proxy/Cargo.toml +++ b/contracts/provider/native-staking-proxy/Cargo.toml @@ -17,6 +17,7 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] +fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } @@ -40,7 +41,7 @@ test-case = { workspace = true } derivative = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt"] } +mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } mesh-native-staking = { workspace = true, features = ["mt"] } [[bin]] diff --git a/contracts/provider/native-staking/Cargo.toml b/contracts/provider/native-staking/Cargo.toml index 1b508ffd..63ed6c76 100644 --- a/contracts/provider/native-staking/Cargo.toml +++ b/contracts/provider/native-staking/Cargo.toml @@ -17,6 +17,7 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] +fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } @@ -41,7 +42,7 @@ test-case = { workspace = true } derivative = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt"] } +mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } [[bin]] name = "schema" From 180d28737f871481961045ef2dd60d2f4e48b64e Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 4 Jul 2024 14:38:05 +0700 Subject: [PATCH 11/29] fix error --- contracts/consumer/converter/Cargo.toml | 2 +- .../provider/external-staking/Cargo.toml | 1 - .../provider/native-staking-proxy/Cargo.toml | 1 - contracts/provider/native-staking/Cargo.toml | 1 - contracts/provider/vault/src/contract.rs | 26 +++++++++---------- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/contracts/consumer/converter/Cargo.toml b/contracts/consumer/converter/Cargo.toml index bddd93fe..a152fbeb 100644 --- a/contracts/consumer/converter/Cargo.toml +++ b/contracts/consumer/converter/Cargo.toml @@ -37,7 +37,7 @@ thiserror = { workspace = true } [dev-dependencies] mesh-burn = { workspace = true } -mesh-simple-price-feed = { workspace = true, features = ["mt", "fake-custom"] } +mesh-simple-price-feed = { workspace = true, features = ["mt"] } cw-multi-test = { workspace = true } test-case = { workspace = true } diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index 6e7015ce..4d510833 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -16,7 +16,6 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] -fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } diff --git a/contracts/provider/native-staking-proxy/Cargo.toml b/contracts/provider/native-staking-proxy/Cargo.toml index a6f349d0..8616409c 100644 --- a/contracts/provider/native-staking-proxy/Cargo.toml +++ b/contracts/provider/native-staking-proxy/Cargo.toml @@ -17,7 +17,6 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] -fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } diff --git a/contracts/provider/native-staking/Cargo.toml b/contracts/provider/native-staking/Cargo.toml index 63ed6c76..d7f9270b 100644 --- a/contracts/provider/native-staking/Cargo.toml +++ b/contracts/provider/native-staking/Cargo.toml @@ -17,7 +17,6 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] -fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index f4fb676e..054aba2a 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -11,9 +11,7 @@ use mesh_apis::local_staking_api::{ sv::LocalStakingApiQueryMsg, LocalStakingApiHelper, SlashRatioResponse, }; use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; -use mesh_bindings::{ - VaultCustomMsg, VaultMsg, -}; +use mesh_bindings::{VaultCustomMsg, VaultMsg}; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; @@ -155,7 +153,7 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -167,17 +165,18 @@ impl VaultContract<'_> { .unwrap_or_default(); user.collateral += amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; - // let msg = VaultMsg::Bond { delegator: ctx.info.sender.into_string(), amount}; - let resp = Response::new() - .add_attribute("action", "bond") + let amt = amount.amount; + let resp = custom::Response::new() + .add_message(VaultMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}) + .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) - .add_attribute("amount", amount.to_string()); + .add_attribute("amount", amt.to_string()); Ok(resp) } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -196,11 +195,12 @@ impl VaultContract<'_> { user.collateral -= amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; - + let amt = amount.amount; let resp = custom::Response::new() + .add_message(VaultMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}) .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) - .add_attribute("amount", amount.to_string()); + .add_attribute("amount", amt.to_string()); Ok(resp) } @@ -500,7 +500,7 @@ impl VaultContract<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -511,7 +511,7 @@ impl VaultContract<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result { + ) -> Result { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; let local_staking = Addr::unchecked(init_data.contract_address); From e723970de982ddd8e96483c1e0265dec3019af5c Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 4 Jul 2024 14:53:52 +0700 Subject: [PATCH 12/29] remove unused file --- contracts/provider/vault/src/contract/custom.rs | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 contracts/provider/vault/src/contract/custom.rs diff --git a/contracts/provider/vault/src/contract/custom.rs b/contracts/provider/vault/src/contract/custom.rs deleted file mode 100644 index 7da9ffe4..00000000 --- a/contracts/provider/vault/src/contract/custom.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub type VaultContractMsg = mesh_bindings::VaultCustomMsg; -pub type Response = cosmwasm_std::Response; From b50d126e779f7ed975781dd883c031fbd7aac247 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 4 Jul 2024 16:23:31 +0700 Subject: [PATCH 13/29] update dependencies --- contracts/provider/external-staking/Cargo.toml | 2 +- contracts/provider/native-staking-proxy/Cargo.toml | 2 +- contracts/provider/native-staking/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index 4d510833..1056ac3c 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -37,7 +37,7 @@ thiserror = { workspace = true } sylvia = { workspace = true, features = ["mt"] } cw-multi-test = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } +mesh-vault = { workspace = true, features = ["mt"] } mesh-native-staking-proxy = { workspace = true, features = ["mt"] } mesh-native-staking = { workspace = true, features = ["mt"] } mesh-sync = { workspace = true } diff --git a/contracts/provider/native-staking-proxy/Cargo.toml b/contracts/provider/native-staking-proxy/Cargo.toml index 8616409c..a8210310 100644 --- a/contracts/provider/native-staking-proxy/Cargo.toml +++ b/contracts/provider/native-staking-proxy/Cargo.toml @@ -40,7 +40,7 @@ test-case = { workspace = true } derivative = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } +mesh-vault = { workspace = true, features = ["mt"] } mesh-native-staking = { workspace = true, features = ["mt"] } [[bin]] diff --git a/contracts/provider/native-staking/Cargo.toml b/contracts/provider/native-staking/Cargo.toml index d7f9270b..1b508ffd 100644 --- a/contracts/provider/native-staking/Cargo.toml +++ b/contracts/provider/native-staking/Cargo.toml @@ -41,7 +41,7 @@ test-case = { workspace = true } derivative = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } +mesh-vault = { workspace = true, features = ["mt"] } [[bin]] name = "schema" From d03c9cc853ce858e0842d2dcca40532d567712f3 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Fri, 5 Jul 2024 11:08:40 +0700 Subject: [PATCH 14/29] remove unused config --- contracts/provider/vault/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/provider/vault/Cargo.toml b/contracts/provider/vault/Cargo.toml index 31a3ac95..9969f529 100644 --- a/contracts/provider/vault/Cargo.toml +++ b/contracts/provider/vault/Cargo.toml @@ -17,8 +17,6 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] -# enable this for multi-tests where you need custom messages for compatibility with virtual staking -fake-custom = [] [dependencies] mesh-apis = { workspace = true } From 7d981de329aed74cd8a78bbedfa4f983bc11661f Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Fri, 5 Jul 2024 17:01:13 +0700 Subject: [PATCH 15/29] fix vault contract error --- contracts/provider/vault/src/contract.rs | 40 +++++++++--------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 054aba2a..c6852164 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -45,16 +45,6 @@ fn def_false() -> bool { false } -#[cfg(not(feature = "fake-custom"))] -pub mod custom { - pub type VaultContractMsg = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; -} -#[cfg(feature = "fake-custom")] -pub mod custom { - pub type VaultContractMsg = mesh_bindings::VaultCustomMsg; - pub type Response = cosmwasm_std::Response; -} pub struct VaultContract<'a> { /// General contract configuration pub config: Item<'a, Config>, @@ -78,7 +68,7 @@ pub struct VaultContract<'a> { #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] /// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::VaultContractMsg)] +#[sv::custom(msg=VaultCustomMsg)] impl VaultContract<'_> { pub fn new() -> Self { Self { @@ -104,7 +94,7 @@ impl VaultContract<'_> { ctx: InstantiateCtx, denom: String, local_staking: Option, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = Config { denom }; @@ -166,7 +156,7 @@ impl VaultContract<'_> { user.collateral += amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let resp = custom::Response::new() + let resp = Response::new() .add_message(VaultMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}) .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) @@ -196,7 +186,7 @@ impl VaultContract<'_> { user.collateral -= amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let resp = custom::Response::new() + let resp = Response::new() .add_message(VaultMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}) .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) @@ -216,7 +206,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -263,7 +253,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -500,7 +490,7 @@ impl VaultContract<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result, ContractError> { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -511,7 +501,7 @@ impl VaultContract<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result { + ) -> Result, ContractError> { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; let local_staking = Addr::unchecked(init_data.contract_address); @@ -991,7 +981,7 @@ impl Default for VaultContract<'_> { impl VaultApi for VaultContract<'_> { type Error = ContractError; - type ExecC = custom::VaultContractMsg; + type ExecC = VaultCustomMsg; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( @@ -1001,7 +991,7 @@ impl VaultApi for VaultContract<'_> { owner: String, // amount to unstake on that contract amount: Coin, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; self.unstake(&mut ctx, owner.clone(), amount.clone())?; @@ -1022,7 +1012,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, // address of the user who originally called stake_remote owner: String, - ) -> Result { + ) -> Result, ContractError> { let denom = self.config.load(ctx.deps.storage)?.denom; let amount = must_pay(&ctx.info, &denom)?; @@ -1043,7 +1033,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, slashes: Vec, validator: String, - ) -> Result { + ) -> Result, Self::Error> { nonpayable(&ctx.info)?; let msgs = self.slash(&mut ctx, &slashes, &validator)?; @@ -1071,7 +1061,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, slashes: Vec, validator: String, - ) -> Result { + ) -> Result, Self::Error> { nonpayable(&ctx.info)?; let msgs = self.slash(&mut ctx, &slashes, &validator)?; @@ -1093,7 +1083,7 @@ impl VaultApi for VaultContract<'_> { Ok(resp) } - fn commit_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result { + fn commit_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result, ContractError> { self.commit_stake(&mut ctx, tx_id)?; let resp = Response::new() @@ -1104,7 +1094,7 @@ impl VaultApi for VaultContract<'_> { Ok(resp) } - fn rollback_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result { + fn rollback_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result, ContractError> { self.rollback_stake(&mut ctx, tx_id)?; let resp = Response::new() From a7c170fd775f75ffea340ea35b582f4d64a7b8a1 Mon Sep 17 00:00:00 2001 From: Trinity Date: Sun, 7 Jul 2024 22:47:55 +0700 Subject: [PATCH 16/29] Add fake custom to all provider contract --- Cargo.lock | 3 ++ .../provider/external-staking/Cargo.toml | 9 +++-- .../provider/external-staking/src/contract.rs | 29 ++++++++++++---- .../provider/external-staking/src/ibc.rs | 4 +-- .../external-staking/src/multitest.rs | 9 +++-- .../external-staking/src/test_methods.rs | 27 +++++++-------- .../external-staking/src/test_methods_impl.rs | 27 +++++++-------- .../provider/native-staking-proxy/Cargo.toml | 3 ++ .../native-staking-proxy/src/contract.rs | 33 ++++++++++++++----- .../src/native_staking_callback.rs | 7 ++-- contracts/provider/native-staking/Cargo.toml | 5 ++- .../provider/native-staking/src/contract.rs | 30 +++++++++++++---- .../native-staking/src/local_staking_api.rs | 7 ++-- .../src/native_staking_callback.rs | 7 ++-- contracts/provider/vault/Cargo.toml | 4 ++- contracts/provider/vault/src/contract.rs | 29 +++++++++++----- contracts/provider/vault/src/multitest.rs | 10 ++++-- packages/apis/src/cross_staking_api.rs | 7 ++-- packages/apis/src/local_staking_api.rs | 7 ++-- 19 files changed, 175 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2f0dab3..278c0118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -629,6 +629,7 @@ dependencies = [ "cw-utils", "cw2", "mesh-apis", + "mesh-bindings", "mesh-burn", "mesh-native-staking", "mesh-native-staking-proxy", @@ -653,6 +654,7 @@ dependencies = [ "cw2", "derivative", "mesh-apis", + "mesh-bindings", "mesh-native-staking-proxy", "mesh-sync", "mesh-vault", @@ -676,6 +678,7 @@ dependencies = [ "cw2", "derivative", "mesh-apis", + "mesh-bindings", "mesh-burn", "mesh-native-staking", "mesh-vault", diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index 1056ac3c..75f517d7 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -16,9 +16,12 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] +# enable this for multi-tests where you need custom messages for compatibility with vault +fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } +mesh-bindings = { workspace = true } mesh-burn = { workspace = true } mesh-sync = { workspace = true } @@ -37,9 +40,9 @@ thiserror = { workspace = true } sylvia = { workspace = true, features = ["mt"] } cw-multi-test = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt"] } -mesh-native-staking-proxy = { workspace = true, features = ["mt"] } -mesh-native-staking = { workspace = true, features = ["mt"] } +mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } +mesh-native-staking-proxy = { workspace = true, features = ["mt", "fake-custom"] } +mesh-native-staking = { workspace = true, features = ["mt", "fake-custom"] } mesh-sync = { workspace = true } [[bin]] diff --git a/contracts/provider/external-staking/src/contract.rs b/contracts/provider/external-staking/src/contract.rs index 25293bc3..824e2ca7 100644 --- a/contracts/provider/external-staking/src/contract.rs +++ b/contracts/provider/external-staking/src/contract.rs @@ -41,6 +41,19 @@ fn clamp_page_limit(limit: Option) -> usize { limit.unwrap_or(DEFAULT_PAGE_LIMIT).max(MAX_PAGE_LIMIT) as usize } +#[cfg(not(feature = "fake-custom"))] +pub mod custom { + pub type VaultMsg = cosmwasm_std::Empty; + pub type VaultQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} +#[cfg(feature = "fake-custom")] +pub mod custom { + pub type VaultMsg = mesh_bindings::VaultCustomMsg; + pub type VaultQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} + pub struct ExternalStakingContract<'a> { pub config: Item<'a, Config>, /// Stakes indexed by `(owner, validator)` pair @@ -65,6 +78,8 @@ impl Default for ExternalStakingContract<'_> { #[sv::error(ContractError)] #[sv::messages(cross_staking_api as CrossStakingApi)] #[sv::messages(crate::test_methods as TestMethods)] +/// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. +#[sv::custom(msg=custom::VaultMsg)] impl ExternalStakingContract<'_> { pub fn new() -> Self { Self { @@ -96,7 +111,7 @@ impl ExternalStakingContract<'_> { unbonding_period: u64, remote_contact: crate::msg::AuthorizedEndpoint, slash_ratio: SlashRatio, - ) -> Result { + ) -> Result { let vault = ctx.deps.api.addr_validate(&vault)?; let vault = VaultApiHelper(vault); @@ -251,7 +266,7 @@ impl ExternalStakingContract<'_> { ctx: ExecCtx, validator: String, amount: Coin, - ) -> Result { + ) -> Result { let ExecCtx { info, deps, env } = ctx; nonpayable(&info)?; @@ -601,7 +616,7 @@ impl ExternalStakingContract<'_> { /// Tokens to be claimed have to be unbond before by calling the `unbond` message, and /// their unbonding period must have passed. #[sv::msg(exec)] - pub fn withdraw_unbonded(&self, ctx: ExecCtx) -> Result { + pub fn withdraw_unbonded(&self, ctx: ExecCtx) -> Result { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -734,7 +749,7 @@ impl ExternalStakingContract<'_> { validator: String, /// Address on the consumer side to receive the rewards remote_recipient: String, - ) -> Result { + ) -> Result { nonpayable(&ctx.info)?; let stake = self @@ -1205,6 +1220,7 @@ impl ExternalStakingContract<'_> { pub mod cross_staking { use crate::msg::ReceiveVirtualStake; + use super::custom; use super::*; use cosmwasm_std::{from_json, Binary}; @@ -1214,6 +1230,7 @@ pub mod cross_staking { #[sv::messages(mesh_apis::cross_staking_api as CrossStakingApi)] impl CrossStakingApi for ExternalStakingContract<'_> { type Error = ContractError; + type ExecC = custom::VaultMsg; #[sv::msg(exec)] fn receive_virtual_stake( @@ -1223,7 +1240,7 @@ pub mod cross_staking { amount: Coin, tx_id: u64, msg: Binary, - ) -> Result { + ) -> Result { let config = self.config.load(ctx.deps.storage)?; ensure_eq!(ctx.info.sender, config.vault.0, ContractError::Unauthorized); @@ -1306,7 +1323,7 @@ pub mod cross_staking { owner: String, amount: Coin, validator: Option, - ) -> Result { + ) -> Result { let config = self.config.load(ctx.deps.storage)?; ensure_eq!(ctx.info.sender, config.vault.0, ContractError::Unauthorized); diff --git a/contracts/provider/external-staking/src/ibc.rs b/contracts/provider/external-staking/src/ibc.rs index 69127f2d..b5503e2e 100644 --- a/contracts/provider/external-staking/src/ibc.rs +++ b/contracts/provider/external-staking/src/ibc.rs @@ -12,7 +12,7 @@ use mesh_apis::ibc::{ ProtocolVersion, ProviderPacket, ValsetUpdateAck, }; -use crate::contract::ExternalStakingContract; +use crate::contract::{custom, ExternalStakingContract}; use crate::error::ContractError; use crate::msg::AuthorizedEndpoint; @@ -117,7 +117,7 @@ pub fn ibc_packet_receive( deps: DepsMut, env: Env, msg: IbcPacketReceiveMsg, -) -> Result { +) -> Result, ContractError> { // There is only one channel, so we don't need to switch. // We also don't care about packet sequence as this is being ordered by height. // If a validator is in more than one of the events, the end result will depend on the diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index ff249fe9..f5f170b8 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -2,7 +2,7 @@ mod utils; use anyhow::Result as AnyResult; -use cosmwasm_std::{coin, coins, to_json_binary, Decimal, Uint128}; +use cosmwasm_std::{coin, coins, to_json_binary, Decimal, Empty, Uint128}; use mesh_native_staking::contract::sv::mt::CodeId as NativeStakingCodeId; use mesh_native_staking::contract::sv::InstantiateMsg as NativeStakingInstantiateMsg; use mesh_native_staking_proxy::contract::sv::mt::CodeId as NativeStakingProxyCodeId; @@ -12,7 +12,6 @@ use mesh_vault::msg::{LocalStakingInfo, StakingInitInfo}; use mesh_sync::ValueRange; -use cw_multi_test::App as MtApp; use sylvia::multitest::{App, Proxy}; use crate::contract::sv::mt::ExternalStakingContractProxy; @@ -39,6 +38,12 @@ const SLASHING_PERCENTAGE: u64 = 10; const LOCAL_SLASHING_PERCENTAGE_DSIGN: u64 = 5; const LOCAL_SLASHING_PERCENTAGE_OFFLINE: u64 = 5; +// Trying to figure out how to work with the generic types +type MtApp = cw_multi_test::BasicApp< + mesh_bindings::VaultCustomMsg, + Empty, +>; + // Shortcut setuping all needed contracts // // Returns vault and external staking proxies diff --git a/contracts/provider/external-staking/src/test_methods.rs b/contracts/provider/external-staking/src/test_methods.rs index 98deae7e..3c3d3b83 100644 --- a/contracts/provider/external-staking/src/test_methods.rs +++ b/contracts/provider/external-staking/src/test_methods.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Coin, Response, StdError, Uint128}; +use cosmwasm_std::{Coin, CustomMsg, Response, StdError, Uint128}; use mesh_apis::converter_api::RewardInfo; use mesh_apis::ibc::AddValidator; use sylvia::interface; @@ -9,14 +9,15 @@ use sylvia::types::ExecCtx; #[interface] pub trait TestMethods { type Error: From; + type ExecC: CustomMsg; /// Commits a pending stake. #[sv::msg(exec)] - fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result; + fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; /// Rollbacks a pending stake. #[sv::msg(exec)] - fn test_rollback_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result; + fn test_rollback_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; /// Updates the active validator set. #[sv::msg(exec)] @@ -26,7 +27,7 @@ pub trait TestMethods { validator: AddValidator, height: u64, time: u64, - ) -> Result; + ) -> Result, Self::Error>; /// Sets validator as `unbonded`. #[sv::msg(exec)] @@ -36,7 +37,7 @@ pub trait TestMethods { valoper: String, height: u64, time: u64, - ) -> Result; + ) -> Result, Self::Error>; #[sv::msg(exec)] fn test_tombstone_validator( @@ -45,15 +46,15 @@ pub trait TestMethods { valoper: String, height: u64, time: u64, - ) -> Result; + ) -> Result, Self::Error>; /// Commits a pending unstake. #[sv::msg(exec)] - fn test_commit_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result; + fn test_commit_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; /// Rollbacks a pending unstake. #[sv::msg(exec)] - fn test_rollback_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result; + fn test_rollback_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; /// Distribute rewards. #[sv::msg(exec)] @@ -62,7 +63,7 @@ pub trait TestMethods { ctx: ExecCtx, validator: String, rewards: Coin, - ) -> Result; + ) -> Result, Self::Error>; /// Batch distribute rewards. #[sv::msg(exec)] @@ -71,7 +72,7 @@ pub trait TestMethods { ctx: ExecCtx, denom: String, rewards: Vec, - ) -> Result; + ) -> Result, Self::Error>; /// Commits a withdraw rewards transaction. #[sv::msg(exec)] @@ -79,7 +80,7 @@ pub trait TestMethods { &self, ctx: ExecCtx, tx_id: u64, - ) -> Result; + ) -> Result, Self::Error>; /// Rollbacks a withdraw rewards transaction. #[sv::msg(exec)] @@ -87,7 +88,7 @@ pub trait TestMethods { &self, ctx: ExecCtx, tx_id: u64, - ) -> Result; + ) -> Result, Self::Error>; /// Slashes a validator. /// This will not perform any check on the validator's state in the validator set, which should @@ -98,5 +99,5 @@ pub trait TestMethods { ctx: ExecCtx, validator: String, slash_amount: Uint128, - ) -> Result; + ) -> Result, Self::Error>; } diff --git a/contracts/provider/external-staking/src/test_methods_impl.rs b/contracts/provider/external-staking/src/test_methods_impl.rs index c63927c1..17fde166 100644 --- a/contracts/provider/external-staking/src/test_methods_impl.rs +++ b/contracts/provider/external-staking/src/test_methods_impl.rs @@ -1,4 +1,4 @@ -use crate::contract::ExternalStakingContract; +use crate::contract::{custom, ExternalStakingContract}; use crate::error::ContractError; use crate::test_methods::TestMethods; @@ -13,10 +13,11 @@ use sylvia::types::ExecCtx; #[sv::messages(crate::test_methods as TestMethods)] impl TestMethods for ExternalStakingContract<'_> { type Error = ContractError; + type ExecC = custom::VaultMsg; /// Commits a pending stake. #[sv::msg(exec)] - fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { + fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(feature = "mt", test))] { let msg = self.commit_stake(ctx.deps, tx_id)?; @@ -31,7 +32,7 @@ impl TestMethods for ExternalStakingContract<'_> { /// Rollbacks a pending stake. #[sv::msg(exec)] - fn test_rollback_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { + fn test_rollback_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(test, feature = "mt"))] { let msg = self.rollback_stake(ctx.deps, tx_id)?; @@ -52,7 +53,7 @@ impl TestMethods for ExternalStakingContract<'_> { validator: AddValidator, height: u64, time: u64, - ) -> Result { + ) -> Result { #[cfg(any(feature = "mt", test))] { let AddValidator { valoper, pub_key } = validator; @@ -75,7 +76,7 @@ impl TestMethods for ExternalStakingContract<'_> { valoper: String, height: u64, time: u64, - ) -> Result { + ) -> Result { #[cfg(any(feature = "mt", test))] { self.val_set @@ -97,7 +98,7 @@ impl TestMethods for ExternalStakingContract<'_> { valoper: String, height: u64, time: u64, - ) -> Result { + ) -> Result { #[cfg(any(feature = "mt", test))] { self.val_set @@ -113,7 +114,7 @@ impl TestMethods for ExternalStakingContract<'_> { /// Commits a pending unstake. #[sv::msg(exec)] - fn test_commit_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result { + fn test_commit_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(test, feature = "mt"))] { self.commit_unstake(ctx.deps, ctx.env, tx_id)?; @@ -128,7 +129,7 @@ impl TestMethods for ExternalStakingContract<'_> { /// Rollbacks a pending unstake. #[sv::msg(exec)] - fn test_rollback_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result { + fn test_rollback_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(test, feature = "mt"))] { self.rollback_unstake(ctx.deps, tx_id)?; @@ -148,7 +149,7 @@ impl TestMethods for ExternalStakingContract<'_> { ctx: ExecCtx, validator: String, rewards: Coin, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { let event = self.distribute_rewards(ctx.deps, &validator, rewards)?; @@ -168,7 +169,7 @@ impl TestMethods for ExternalStakingContract<'_> { ctx: ExecCtx, denom: String, rewards: Vec, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { let events = self.distribute_rewards_batch(ctx.deps, &rewards, &denom)?; @@ -187,7 +188,7 @@ impl TestMethods for ExternalStakingContract<'_> { &self, ctx: ExecCtx, tx_id: u64, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { self.commit_withdraw_rewards(ctx.deps, tx_id)?; @@ -206,7 +207,7 @@ impl TestMethods for ExternalStakingContract<'_> { &self, ctx: ExecCtx, tx_id: u64, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { self.rollback_withdraw_rewards(ctx.deps, tx_id)?; @@ -226,7 +227,7 @@ impl TestMethods for ExternalStakingContract<'_> { ctx: ExecCtx, validator: String, slash_amount: Uint128, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { let cfg = self.config.load(ctx.deps.storage)?; diff --git a/contracts/provider/native-staking-proxy/Cargo.toml b/contracts/provider/native-staking-proxy/Cargo.toml index a8210310..a1883209 100644 --- a/contracts/provider/native-staking-proxy/Cargo.toml +++ b/contracts/provider/native-staking-proxy/Cargo.toml @@ -17,9 +17,12 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] +# enable this for multi-tests where you need custom messages for compatibility with vault +fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } +mesh-bindings = { workspace = true } mesh-burn = { workspace = true } sylvia = { workspace = true } diff --git a/contracts/provider/native-staking-proxy/src/contract.rs b/contracts/provider/native-staking-proxy/src/contract.rs index 89aa6240..bc78780c 100644 --- a/contracts/provider/native-staking-proxy/src/contract.rs +++ b/contracts/provider/native-staking-proxy/src/contract.rs @@ -23,9 +23,24 @@ pub struct NativeStakingProxyContract<'a> { burned: Item<'a, u128>, } +#[cfg(not(feature = "fake-custom"))] +pub mod custom { + pub type VaultMsg = cosmwasm_std::Empty; + pub type VaultQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} +#[cfg(feature = "fake-custom")] +pub mod custom { + pub type VaultMsg = mesh_bindings::VaultCustomMsg; + pub type VaultQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} + #[cfg_attr(not(feature = "library"), sylvia::entry_points)] #[contract] #[sv::error(ContractError)] +/// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. +#[sv::custom(msg=custom::VaultMsg)] impl NativeStakingProxyContract<'_> { pub const fn new() -> Self { Self { @@ -43,7 +58,7 @@ impl NativeStakingProxyContract<'_> { denom: String, owner: String, validator: String, - ) -> Result { + ) -> Result { let config = Config { denom, parent: ctx.info.sender.clone(), @@ -76,7 +91,7 @@ impl NativeStakingProxyContract<'_> { /// Stakes the tokens from `info.funds` to the given validator. /// Can only be called by the parent contract #[sv::msg(exec)] - fn stake(&self, ctx: ExecCtx, validator: String) -> Result { + fn stake(&self, ctx: ExecCtx, validator: String) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.parent, ctx.info.sender, ContractError::Unauthorized {}); @@ -97,7 +112,7 @@ impl NativeStakingProxyContract<'_> { ctx: ExecCtx, validator: Option, amount: Coin, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.parent, ctx.info.sender, ContractError::Unauthorized {}); @@ -186,7 +201,7 @@ impl NativeStakingProxyContract<'_> { src_validator: String, dst_validator: String, amount: Coin, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -213,7 +228,7 @@ impl NativeStakingProxyContract<'_> { ctx: ExecCtx, proposal_id: u64, vote: VoteOption, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -230,7 +245,7 @@ impl NativeStakingProxyContract<'_> { ctx: ExecCtx, proposal_id: u64, vote: Vec, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -247,7 +262,7 @@ impl NativeStakingProxyContract<'_> { /// send the tokens to the caller. /// NOTE: must make sure not to release unbonded tokens #[sv::msg(exec)] - fn withdraw_rewards(&self, ctx: ExecCtx) -> Result { + fn withdraw_rewards(&self, ctx: ExecCtx) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -276,7 +291,7 @@ impl NativeStakingProxyContract<'_> { ctx: ExecCtx, validator: String, amount: Coin, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -296,7 +311,7 @@ impl NativeStakingProxyContract<'_> { /// This will go back to the parent via `release_proxy_stake`. /// Errors if the proxy doesn't have any liquid tokens #[sv::msg(exec)] - fn release_unbonded(&self, ctx: ExecCtx) -> Result { + fn release_unbonded(&self, ctx: ExecCtx) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); diff --git a/contracts/provider/native-staking-proxy/src/native_staking_callback.rs b/contracts/provider/native-staking-proxy/src/native_staking_callback.rs index 53dc0241..eba66596 100644 --- a/contracts/provider/native-staking-proxy/src/native_staking_callback.rs +++ b/contracts/provider/native-staking-proxy/src/native_staking_callback.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Response, StdError}; +use cosmwasm_std::{CustomMsg, Response, StdError}; use sylvia::types::ExecCtx; use sylvia::{interface, schemars}; @@ -6,10 +6,11 @@ use sylvia::{interface, schemars}; #[interface] pub trait NativeStakingCallback { type Error: From; - + type ExecC: CustomMsg; + /// This sends tokens back from the proxy to native-staking. (See info.funds) /// The native-staking contract can determine which user it belongs to via an internal Map. /// The native-staking contract will then send those tokens back to vault and release the claim. #[sv::msg(exec)] - fn release_proxy_stake(&self, _ctx: ExecCtx) -> Result; + fn release_proxy_stake(&self, _ctx: ExecCtx) -> Result, Self::Error>; } diff --git a/contracts/provider/native-staking/Cargo.toml b/contracts/provider/native-staking/Cargo.toml index 1b508ffd..b50c6a77 100644 --- a/contracts/provider/native-staking/Cargo.toml +++ b/contracts/provider/native-staking/Cargo.toml @@ -17,9 +17,12 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] +# enable this for multi-tests where you need custom messages for compatibility with vault +fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } +mesh-bindings = { workspace = true } mesh-sync = { workspace = true } mesh-native-staking-proxy = { workspace = true, features = ["library"] } @@ -41,7 +44,7 @@ test-case = { workspace = true } derivative = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt"] } +mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } [[bin]] name = "schema" diff --git a/contracts/provider/native-staking/src/contract.rs b/contracts/provider/native-staking/src/contract.rs index 08ac3d95..43d521ea 100644 --- a/contracts/provider/native-staking/src/contract.rs +++ b/contracts/provider/native-staking/src/contract.rs @@ -1,6 +1,7 @@ use cosmwasm_std::Order::Ascending; use cosmwasm_std::{ - from_json, Addr, Decimal, DepsMut, Event, Reply, Response, StdResult, SubMsgResponse, WasmMsg, + from_json, Addr, Decimal, DepsMut, Event, Reply, Response, + StdResult, SubMsgResponse, WasmMsg, }; use cw2::set_contract_version; use cw_storage_plus::{Item, Map}; @@ -22,6 +23,19 @@ pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const REPLY_ID_INSTANTIATE: u64 = 2; +#[cfg(not(feature = "fake-custom"))] +pub mod custom { + pub type VaultMsg = cosmwasm_std::Empty; + pub type VaultQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} +#[cfg(feature = "fake-custom")] +pub mod custom { + pub type VaultMsg = mesh_bindings::VaultCustomMsg; + pub type VaultQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} + pub struct NativeStakingContract<'a> { pub config: Item<'a, Config>, /// Map of proxy contract address by owner address @@ -43,6 +57,8 @@ pub(crate) enum SlashingReason { #[sv::error(ContractError)] #[sv::messages(local_staking_api as LocalStakingApi)] #[sv::messages(native_staking_callback as NativeStakingCallback)] +/// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. +#[sv::custom(msg=custom::VaultMsg)] impl NativeStakingContract<'_> { pub const fn new() -> Self { Self { @@ -62,7 +78,7 @@ impl NativeStakingContract<'_> { proxy_code_id: u64, slash_ratio_dsign: Decimal, slash_ratio_offline: Decimal, - ) -> Result { + ) -> Result { if slash_ratio_dsign > Decimal::one() || slash_ratio_offline > Decimal::one() { return Err(ContractError::InvalidSlashRatio); } @@ -87,7 +103,7 @@ impl NativeStakingContract<'_> { mut deps: DepsMut, jailed: Option>, tombstoned: Option>, - ) -> Result { + ) -> Result { let jailed = &jailed.unwrap_or_default(); let tombstoned = &tombstoned.unwrap_or_default(); @@ -181,7 +197,7 @@ impl NativeStakingContract<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -192,7 +208,7 @@ impl NativeStakingContract<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result { + ) -> Result { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; // Associate staking proxy with owner address @@ -242,7 +258,7 @@ impl NativeStakingContract<'_> { ctx: ExecCtx, jailed: Vec, tombstoned: Vec, - ) -> Result { + ) -> Result { #[cfg(any(feature = "mt", test))] { let jailed = if jailed.is_empty() { @@ -274,7 +290,7 @@ impl NativeStakingContract<'_> { ctx: SudoCtx, jailed: Option>, tombstoned: Option>, - ) -> Result { + ) -> Result { self.handle_jailing(ctx.deps, jailed, tombstoned) } } diff --git a/contracts/provider/native-staking/src/local_staking_api.rs b/contracts/provider/native-staking/src/local_staking_api.rs index 292f68a0..8ec0592b 100644 --- a/contracts/provider/native-staking/src/local_staking_api.rs +++ b/contracts/provider/native-staking/src/local_staking_api.rs @@ -5,7 +5,7 @@ use sylvia::types::{ExecCtx, QueryCtx}; #[allow(unused_imports)] use mesh_apis::local_staking_api::{self, LocalStakingApi, SlashRatioResponse}; -use crate::contract::{NativeStakingContract, REPLY_ID_INSTANTIATE}; +use crate::contract::{custom, NativeStakingContract, REPLY_ID_INSTANTIATE}; use crate::error::ContractError; use crate::msg::StakeMsg; @@ -13,6 +13,7 @@ use crate::state::Config; impl LocalStakingApi for NativeStakingContract<'_> { type Error = ContractError; + type ExecC = custom::VaultMsg; /// Receives stake (info.funds) from vault contract on behalf of owner and performs the action /// specified in msg with it. @@ -22,7 +23,7 @@ impl LocalStakingApi for NativeStakingContract<'_> { ctx: ExecCtx, owner: String, msg: Binary, - ) -> Result { + ) -> Result { // Can only be called by the vault let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.vault.0, ctx.info.sender, ContractError::Unauthorized {}); @@ -88,7 +89,7 @@ impl LocalStakingApi for NativeStakingContract<'_> { owner: String, amount: Coin, validator: Option, - ) -> Result { + ) -> Result { // Can only be called by the vault let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.vault.0, ctx.info.sender, ContractError::Unauthorized {}); diff --git a/contracts/provider/native-staking/src/native_staking_callback.rs b/contracts/provider/native-staking/src/native_staking_callback.rs index 4996296f..85473460 100644 --- a/contracts/provider/native-staking/src/native_staking_callback.rs +++ b/contracts/provider/native-staking/src/native_staking_callback.rs @@ -5,16 +5,17 @@ use sylvia::types::ExecCtx; #[allow(unused_imports)] use mesh_native_staking_proxy::native_staking_callback::{self, NativeStakingCallback}; -use crate::contract::NativeStakingContract; +use crate::contract::{custom, NativeStakingContract}; use crate::error::ContractError; impl NativeStakingCallback for NativeStakingContract<'_> { type Error = ContractError; + type ExecC = custom::VaultMsg; /// This sends tokens back from the proxy to native-staking. (See info.funds) /// The native-staking contract can determine which user it belongs to via an internal Map. /// The native-staking contract will then send those tokens back to vault and release the claim. - fn release_proxy_stake(&self, ctx: ExecCtx) -> Result { + fn release_proxy_stake(&self, ctx: ExecCtx) -> Result { let cfg = self.config.load(ctx.deps.storage)?; // Assert funds are passed in @@ -33,4 +34,4 @@ impl NativeStakingCallback for NativeStakingContract<'_> { Ok(Response::new().add_message(msg)) } -} +} \ No newline at end of file diff --git a/contracts/provider/vault/Cargo.toml b/contracts/provider/vault/Cargo.toml index 9969f529..64d7dd61 100644 --- a/contracts/provider/vault/Cargo.toml +++ b/contracts/provider/vault/Cargo.toml @@ -17,6 +17,8 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] +# enable this for multi-tests where you need custom messages for compatibility with virtual staking +fake-custom = [] [dependencies] mesh-apis = { workspace = true } @@ -40,7 +42,7 @@ cw-multi-test = { workspace = true } test-case = { workspace = true } derivative = { workspace = true } anyhow = { workspace = true } -mesh-external-staking = { workspace = true, features = ["mt"] } +mesh-external-staking = { workspace = true, features = ["mt", "fake-custom"] } mesh-native-staking = { workspace = true, features = ["mt"] } mesh-native-staking-proxy = { workspace = true, features = ["mt"] } diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index c6852164..9e0724a7 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -45,6 +45,19 @@ fn def_false() -> bool { false } +#[cfg(not(feature = "fake-custom"))] +pub mod custom { + pub type VaultMsg = cosmwasm_std::Empty; + pub type VaultQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} +#[cfg(feature = "fake-custom")] +pub mod custom { + pub type VaultMsg = mesh_bindings::VaultCustomMsg; + pub type VaultQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; +} + pub struct VaultContract<'a> { /// General contract configuration pub config: Item<'a, Config>, @@ -68,7 +81,7 @@ pub struct VaultContract<'a> { #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] /// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=VaultCustomMsg)] +#[sv::custom(msg=custom::VaultMsg)] impl VaultContract<'_> { pub fn new() -> Self { Self { @@ -94,7 +107,7 @@ impl VaultContract<'_> { ctx: InstantiateCtx, denom: String, local_staking: Option, - ) -> Result, ContractError> { + ) -> Result { nonpayable(&ctx.info)?; let config = Config { denom }; @@ -143,7 +156,7 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { + fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -166,7 +179,7 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -206,7 +219,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result, ContractError> { + ) -> Result { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -253,7 +266,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result, ContractError> { + ) -> Result { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -490,7 +503,7 @@ impl VaultContract<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result, ContractError> { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -501,7 +514,7 @@ impl VaultContract<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result, ContractError> { + ) -> Result { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; let local_staking = Addr::unchecked(init_data.contract_address); diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index dcca7d37..92c95f1e 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -1,5 +1,5 @@ -use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Uint128, Validator}; -use cw_multi_test::{App as MtApp, StakingInfo}; +use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Empty, Uint128, Validator}; +use cw_multi_test::StakingInfo; use mesh_apis::ibc::AddValidator; use mesh_external_staking::contract::sv::mt::ExternalStakingContractProxy; use mesh_external_staking::contract::ExternalStakingContract; @@ -32,6 +32,12 @@ const STAR: &str = "star"; /// 10% slashing on the remote chain const SLASHING_PERCENTAGE: u64 = 10; +// Trying to figure out how to work with the generic types +type MtApp = cw_multi_test::BasicApp< + mesh_bindings::VaultCustomMsg, + Empty, +>; + /// Test utils /// App initialization diff --git a/packages/apis/src/cross_staking_api.rs b/packages/apis/src/cross_staking_api.rs index f83e0dac..84b6b1d7 100644 --- a/packages/apis/src/cross_staking_api.rs +++ b/packages/apis/src/cross_staking_api.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, Deps, Response, StdError, WasmMsg}; +use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, CustomMsg, Deps, Response, StdError, WasmMsg}; use sylvia::types::{ExecCtx, QueryCtx}; use sylvia::{interface, schemars}; @@ -14,6 +14,7 @@ pub use crate::local_staking_api::SlashRatioResponse; #[interface] pub trait CrossStakingApi { type Error: From; + type ExecC: CustomMsg; /// Receives stake from vault contract on behalf of owner and performs the action /// specified in msg with it. @@ -26,7 +27,7 @@ pub trait CrossStakingApi { amount: Coin, tx_id: u64, msg: Binary, - ) -> Result; + ) -> Result, Self::Error>; /// Burns stake. This is called when the user's collateral is slashed and, as part of slashing /// propagation, the virtual staking contract needs to burn / discount the indicated slashing amount. @@ -41,7 +42,7 @@ pub trait CrossStakingApi { owner: String, amount: Coin, validator: Option, - ) -> Result; + ) -> Result, Self::Error>; /// Returns the maximum percentage that can be slashed #[sv::msg(query)] diff --git a/packages/apis/src/local_staking_api.rs b/packages/apis/src/local_staking_api.rs index c319d894..6edb27bc 100644 --- a/packages/apis/src/local_staking_api.rs +++ b/packages/apis/src/local_staking_api.rs @@ -1,6 +1,6 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - to_json_binary, Addr, Binary, Coin, Decimal, Deps, Response, StdError, WasmMsg, + to_json_binary, Addr, Binary, Coin, CustomMsg, Decimal, Deps, Response, StdError, WasmMsg, }; use sylvia::types::{ExecCtx, QueryCtx}; use sylvia::{interface, schemars}; @@ -16,6 +16,7 @@ pub struct SlashRatioResponse { #[interface] pub trait LocalStakingApi { type Error: From; + type ExecC: CustomMsg; /// Receives stake (info.funds) from vault contract on behalf of owner and performs the action /// specified in msg with it. @@ -31,7 +32,7 @@ pub trait LocalStakingApi { // // Basically, it allows iterations on various staking designs without touching Vault msg: Binary, - ) -> Result; + ) -> Result, Self::Error>; /// Burns stake. This is called when the user's collateral is slashed and, as part of slashing /// propagation, the native staking contract needs to burn / discount the indicated slashing amount. @@ -44,7 +45,7 @@ pub trait LocalStakingApi { owner: String, amount: Coin, validator: Option, - ) -> Result; + ) -> Result, Self::Error>; /// Returns the maximum percentage that can be slashed #[sv::msg(query)] From 28ae4ccfddeee6e05911208481462d0f1c301e86 Mon Sep 17 00:00:00 2001 From: Trinity Date: Mon, 8 Jul 2024 11:31:11 +0700 Subject: [PATCH 17/29] Custom MtApp for multitests --- .../provider/external-staking/src/multitest.rs | 3 ++- .../external-staking/src/multitest/utils.rs | 13 ++++++++++--- .../external-staking/src/test_methods_impl.rs | 2 +- .../provider/native-staking-proxy/src/multitest.rs | 12 +++++++++--- contracts/provider/native-staking/src/multitest.rs | 12 +++++++++--- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index f5f170b8..de5e3ac2 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -3,6 +3,7 @@ mod utils; use anyhow::Result as AnyResult; use cosmwasm_std::{coin, coins, to_json_binary, Decimal, Empty, Uint128}; +use cw_multi_test::{no_init, AppBuilder}; use mesh_native_staking::contract::sv::mt::CodeId as NativeStakingCodeId; use mesh_native_staking::contract::sv::InstantiateMsg as NativeStakingInstantiateMsg; use mesh_native_staking_proxy::contract::sv::mt::CodeId as NativeStakingProxyCodeId; @@ -99,7 +100,7 @@ fn setup<'app>( #[test] fn instantiate() { - let app = App::default(); + let app = App::new(AppBuilder::new_custom().build(no_init)); let owner = "owner"; let users = ["user1"]; diff --git a/contracts/provider/external-staking/src/multitest/utils.rs b/contracts/provider/external-staking/src/multitest/utils.rs index 038c1455..e2a3ed1e 100644 --- a/contracts/provider/external-staking/src/multitest/utils.rs +++ b/contracts/provider/external-staking/src/multitest/utils.rs @@ -1,5 +1,5 @@ -use cosmwasm_std::{to_json_binary, Addr, Coin}; -use cw_multi_test::{App as MtApp, AppResponse}; +use cosmwasm_std::{to_json_binary, Addr, Coin, Empty}; +use cw_multi_test::{AppBuilder, AppResponse}; use mesh_apis::{converter_api::RewardInfo, ibc::AddValidator}; use mesh_sync::Tx; use mesh_vault::contract::{sv::mt::VaultContractProxy, VaultContract}; @@ -14,6 +14,12 @@ use crate::{ //test_methods_impl::test_utils::TestMethods as _, }; +// Trying to figure out how to work with the generic types +type MtApp = cw_multi_test::BasicApp< + mesh_bindings::VaultCustomMsg, + Empty, +>; + macro_rules! assert_rewards { ($contract:expr, $user:expr, $validator:expr, $expected:expr) => { let rewards = $contract @@ -47,7 +53,8 @@ pub(crate) trait AppExt { impl AppExt for App { #[track_caller] fn new_with_balances(balances: &[(&str, &[Coin])]) -> Self { - let app = MtApp::new(|router, _api, storage| { + + let app =AppBuilder::new_custom().build(|router, _api, storage| { for (addr, coins) in balances { router .bank diff --git a/contracts/provider/external-staking/src/test_methods_impl.rs b/contracts/provider/external-staking/src/test_methods_impl.rs index 17fde166..3381d7d7 100644 --- a/contracts/provider/external-staking/src/test_methods_impl.rs +++ b/contracts/provider/external-staking/src/test_methods_impl.rs @@ -20,7 +20,7 @@ impl TestMethods for ExternalStakingContract<'_> { fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(feature = "mt", test))] { - let msg = self.commit_stake(ctx.deps, tx_id)?; + let msg: cosmwasm_std::WasmMsg = self.commit_stake(ctx.deps, tx_id)?; Ok(Response::new().add_message(msg)) } #[cfg(not(any(feature = "mt", test)))] diff --git a/contracts/provider/native-staking-proxy/src/multitest.rs b/contracts/provider/native-staking-proxy/src/multitest.rs index 1982fa21..90f5c6b2 100644 --- a/contracts/provider/native-staking-proxy/src/multitest.rs +++ b/contracts/provider/native-staking-proxy/src/multitest.rs @@ -1,9 +1,9 @@ use anyhow::Result as AnyResult; use cosmwasm_std::testing::mock_env; -use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Validator}; +use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Empty, Validator}; -use cw_multi_test::{App as MtApp, StakingInfo}; +use cw_multi_test::{AppBuilder, StakingInfo}; use sylvia::multitest::{App, Proxy}; @@ -19,10 +19,16 @@ use crate::msg::ConfigResponse; const OSMO: &str = "uosmo"; const UNBONDING_PERIOD: u64 = 17 * 24 * 60 * 60; // 7 days +// Trying to figure out how to work with the generic types +type MtApp = cw_multi_test::BasicApp< + mesh_bindings::VaultCustomMsg, + Empty, +>; + fn init_app(owner: &str, validators: &[&str]) -> App { // Fund the staking contract, and add validators to staking keeper let block = mock_env().block; - let app = MtApp::new(|router, api, storage| { + let app = AppBuilder::new_custom().build(|router, api, storage| { router .bank .init_balance(storage, &Addr::unchecked(owner), coins(1000, OSMO)) diff --git a/contracts/provider/native-staking/src/multitest.rs b/contracts/provider/native-staking/src/multitest.rs index 6e088c43..cb4fd5ef 100644 --- a/contracts/provider/native-staking/src/multitest.rs +++ b/contracts/provider/native-staking/src/multitest.rs @@ -1,8 +1,8 @@ use cosmwasm_std::{ - coin, coins, to_json_binary, Addr, Decimal, Delegation, StdError, Uint128, Validator, + coin, coins, to_json_binary, Addr, Decimal, Delegation, Empty, StdError, Uint128, Validator }; -use cw_multi_test::{App as MtApp, StakingInfo}; +use cw_multi_test::{no_init, AppBuilder, StakingInfo}; use sylvia::multitest::{App, Proxy}; use mesh_apis::local_staking_api::sv::mt::LocalStakingApiProxy; @@ -25,6 +25,12 @@ const OSMO: &str = "OSMO"; const SLASHING_PERCENTAGE_DSIGN: u64 = 15; const SLASHING_PERCENTAGE_OFFLINE: u64 = 10; +// Trying to figure out how to work with the generic types +type MtApp = cw_multi_test::BasicApp< + mesh_bindings::VaultCustomMsg, + Empty, +>; + fn slashing_rate_dsign() -> Decimal { Decimal::percent(SLASHING_PERCENTAGE_DSIGN) } @@ -34,7 +40,7 @@ fn slashing_rate_offline() -> Decimal { } fn app(balances: &[(&str, (u128, &str))], validators: &[&str]) -> App { - let mut mt_app = MtApp::default(); + let mut mt_app = AppBuilder::new_custom().build(no_init); let block_info = mt_app.block_info(); mt_app.init_modules(|router, api, storage| { From 7a560ceef8d1ffda7038137a37730d95fc304fa4 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Mon, 8 Jul 2024 11:44:32 +0700 Subject: [PATCH 18/29] Fix message name for fitting workspace name --- .../provider/external-staking/src/contract.rs | 16 ++++++++-------- .../external-staking/src/test_methods_impl.rs | 2 +- .../native-staking-proxy/src/contract.rs | 14 +++++++------- .../provider/native-staking/src/contract.rs | 14 +++++++------- .../native-staking/src/local_staking_api.rs | 2 +- .../src/native_staking_callback.rs | 2 +- contracts/provider/vault/src/contract.rs | 14 +++++++------- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/contracts/provider/external-staking/src/contract.rs b/contracts/provider/external-staking/src/contract.rs index 824e2ca7..49b14b8b 100644 --- a/contracts/provider/external-staking/src/contract.rs +++ b/contracts/provider/external-staking/src/contract.rs @@ -43,15 +43,15 @@ fn clamp_page_limit(limit: Option) -> usize { #[cfg(not(feature = "fake-custom"))] pub mod custom { - pub type VaultMsg = cosmwasm_std::Empty; - pub type VaultQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; + pub type ExternalStakingMsg = cosmwasm_std::Empty; + pub type ExternalStakingQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; } #[cfg(feature = "fake-custom")] pub mod custom { - pub type VaultMsg = mesh_bindings::VaultCustomMsg; - pub type VaultQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; + pub type ExternalStakingMsg = mesh_bindings::VaultCustomMsg; + pub type ExternalStakingQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; } pub struct ExternalStakingContract<'a> { @@ -79,7 +79,7 @@ impl Default for ExternalStakingContract<'_> { #[sv::messages(cross_staking_api as CrossStakingApi)] #[sv::messages(crate::test_methods as TestMethods)] /// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::VaultMsg)] +#[sv::custom(msg=custom::ExternalStakingMsg)] impl ExternalStakingContract<'_> { pub fn new() -> Self { Self { @@ -1230,7 +1230,7 @@ pub mod cross_staking { #[sv::messages(mesh_apis::cross_staking_api as CrossStakingApi)] impl CrossStakingApi for ExternalStakingContract<'_> { type Error = ContractError; - type ExecC = custom::VaultMsg; + type ExecC = custom::ExternalStakingMsg; #[sv::msg(exec)] fn receive_virtual_stake( diff --git a/contracts/provider/external-staking/src/test_methods_impl.rs b/contracts/provider/external-staking/src/test_methods_impl.rs index 3381d7d7..4c92ab1a 100644 --- a/contracts/provider/external-staking/src/test_methods_impl.rs +++ b/contracts/provider/external-staking/src/test_methods_impl.rs @@ -13,7 +13,7 @@ use sylvia::types::ExecCtx; #[sv::messages(crate::test_methods as TestMethods)] impl TestMethods for ExternalStakingContract<'_> { type Error = ContractError; - type ExecC = custom::VaultMsg; + type ExecC = custom::ExternalStakingMsg; /// Commits a pending stake. #[sv::msg(exec)] diff --git a/contracts/provider/native-staking-proxy/src/contract.rs b/contracts/provider/native-staking-proxy/src/contract.rs index bc78780c..8b4be2ee 100644 --- a/contracts/provider/native-staking-proxy/src/contract.rs +++ b/contracts/provider/native-staking-proxy/src/contract.rs @@ -25,22 +25,22 @@ pub struct NativeStakingProxyContract<'a> { #[cfg(not(feature = "fake-custom"))] pub mod custom { - pub type VaultMsg = cosmwasm_std::Empty; - pub type VaultQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; + pub type NativeStakingProxyMsg = cosmwasm_std::Empty; + pub type NativeStakingProxyQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; } #[cfg(feature = "fake-custom")] pub mod custom { - pub type VaultMsg = mesh_bindings::VaultCustomMsg; - pub type VaultQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; + pub type NativeStakingProxyMsg = mesh_bindings::VaultCustomMsg; + pub type NativeStakingProxyQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; } #[cfg_attr(not(feature = "library"), sylvia::entry_points)] #[contract] #[sv::error(ContractError)] /// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::VaultMsg)] +#[sv::custom(msg=custom::NativeStakingProxyMsg)] impl NativeStakingProxyContract<'_> { pub const fn new() -> Self { Self { diff --git a/contracts/provider/native-staking/src/contract.rs b/contracts/provider/native-staking/src/contract.rs index 43d521ea..f11ea225 100644 --- a/contracts/provider/native-staking/src/contract.rs +++ b/contracts/provider/native-staking/src/contract.rs @@ -25,15 +25,15 @@ pub const REPLY_ID_INSTANTIATE: u64 = 2; #[cfg(not(feature = "fake-custom"))] pub mod custom { - pub type VaultMsg = cosmwasm_std::Empty; - pub type VaultQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; + pub type NativeStakingMsg = cosmwasm_std::Empty; + pub type NativeStakingQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; } #[cfg(feature = "fake-custom")] pub mod custom { - pub type VaultMsg = mesh_bindings::VaultCustomMsg; - pub type VaultQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; + pub type NativeStakingMsg = mesh_bindings::VaultCustomMsg; + pub type NativeStakingQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; } pub struct NativeStakingContract<'a> { @@ -58,7 +58,7 @@ pub(crate) enum SlashingReason { #[sv::messages(local_staking_api as LocalStakingApi)] #[sv::messages(native_staking_callback as NativeStakingCallback)] /// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::VaultMsg)] +#[sv::custom(msg=custom::NativeStakingMsg)] impl NativeStakingContract<'_> { pub const fn new() -> Self { Self { diff --git a/contracts/provider/native-staking/src/local_staking_api.rs b/contracts/provider/native-staking/src/local_staking_api.rs index 8ec0592b..f0288d22 100644 --- a/contracts/provider/native-staking/src/local_staking_api.rs +++ b/contracts/provider/native-staking/src/local_staking_api.rs @@ -13,7 +13,7 @@ use crate::state::Config; impl LocalStakingApi for NativeStakingContract<'_> { type Error = ContractError; - type ExecC = custom::VaultMsg; + type ExecC = custom::NativeStakingMsg; /// Receives stake (info.funds) from vault contract on behalf of owner and performs the action /// specified in msg with it. diff --git a/contracts/provider/native-staking/src/native_staking_callback.rs b/contracts/provider/native-staking/src/native_staking_callback.rs index 85473460..d2540f91 100644 --- a/contracts/provider/native-staking/src/native_staking_callback.rs +++ b/contracts/provider/native-staking/src/native_staking_callback.rs @@ -10,7 +10,7 @@ use crate::error::ContractError; impl NativeStakingCallback for NativeStakingContract<'_> { type Error = ContractError; - type ExecC = custom::VaultMsg; + type ExecC = custom::NativeStakingMsg; /// This sends tokens back from the proxy to native-staking. (See info.funds) /// The native-staking contract can determine which user it belongs to via an internal Map. diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 9e0724a7..c167d8ad 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -47,15 +47,15 @@ fn def_false() -> bool { #[cfg(not(feature = "fake-custom"))] pub mod custom { - pub type VaultMsg = cosmwasm_std::Empty; - pub type VaultQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; + pub type VaultContractMsg = cosmwasm_std::Empty; + pub type VaultContractQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; } #[cfg(feature = "fake-custom")] pub mod custom { - pub type VaultMsg = mesh_bindings::VaultCustomMsg; - pub type VaultQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; + pub type VaultContractMsg = mesh_bindings::VaultCustomMsg; + pub type VaultContractQuery = cosmwasm_std::Empty; + pub type Response = cosmwasm_std::Response; } pub struct VaultContract<'a> { @@ -81,7 +81,7 @@ pub struct VaultContract<'a> { #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] /// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::VaultMsg)] +#[sv::custom(msg=custom::VaultContractMsg)] impl VaultContract<'_> { pub fn new() -> Self { Self { From 63dabbcce50a1642cf1cd56436f840eae980cdec Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Mon, 8 Jul 2024 17:17:30 +0700 Subject: [PATCH 19/29] add vault mock contract --- contracts/provider/vault/src/contract.rs | 12 +- contracts/provider/vault/src/lib.rs | 2 +- contracts/provider/vault/src/multitest.rs | 27 +- .../vault/src/multitest/vault_mock.rs | 1048 +++++++++++++++++ 4 files changed, 1069 insertions(+), 20 deletions(-) create mode 100644 contracts/provider/vault/src/multitest/vault_mock.rs diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index c167d8ad..c8172a5b 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -1004,7 +1004,7 @@ impl VaultApi for VaultContract<'_> { owner: String, // amount to unstake on that contract amount: Coin, - ) -> Result, ContractError> { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; self.unstake(&mut ctx, owner.clone(), amount.clone())?; @@ -1025,7 +1025,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, // address of the user who originally called stake_remote owner: String, - ) -> Result, ContractError> { + ) -> Result, ContractError> { let denom = self.config.load(ctx.deps.storage)?.denom; let amount = must_pay(&ctx.info, &denom)?; @@ -1046,7 +1046,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, slashes: Vec, validator: String, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { nonpayable(&ctx.info)?; let msgs = self.slash(&mut ctx, &slashes, &validator)?; @@ -1074,7 +1074,7 @@ impl VaultApi for VaultContract<'_> { mut ctx: ExecCtx, slashes: Vec, validator: String, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { nonpayable(&ctx.info)?; let msgs = self.slash(&mut ctx, &slashes, &validator)?; @@ -1096,7 +1096,7 @@ impl VaultApi for VaultContract<'_> { Ok(resp) } - fn commit_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result, ContractError> { + fn commit_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result, ContractError> { self.commit_stake(&mut ctx, tx_id)?; let resp = Response::new() @@ -1107,7 +1107,7 @@ impl VaultApi for VaultContract<'_> { Ok(resp) } - fn rollback_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result, ContractError> { + fn rollback_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result, ContractError> { self.rollback_stake(&mut ctx, tx_id)?; let resp = Response::new() diff --git a/contracts/provider/vault/src/lib.rs b/contracts/provider/vault/src/lib.rs index 77d7a460..c97bc6e5 100644 --- a/contracts/provider/vault/src/lib.rs +++ b/contracts/provider/vault/src/lib.rs @@ -2,6 +2,6 @@ pub mod contract; pub mod error; pub mod msg; #[cfg(test)] -mod multitest; +pub mod multitest; mod state; pub mod txs; diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index 92c95f1e..0f9e76a2 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -1,3 +1,5 @@ +mod vault_mock; + use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Empty, Uint128, Validator}; use cw_multi_test::StakingInfo; use mesh_apis::ibc::AddValidator; @@ -17,14 +19,14 @@ use sylvia::multitest::{App, Proxy}; use mesh_apis::vault_api::sv::mt::VaultApiProxy; use mesh_external_staking::test_methods::sv::mt::TestMethodsProxy; -use crate::contract; -use crate::contract::sv::mt::VaultContractProxy; -use crate::contract::VaultContract; use crate::error::ContractError; use crate::msg::{ AccountResponse, AllAccountsResponseItem, AllActiveExternalStakingResponse, LienResponse, LocalStakingInfo, StakingInitInfo, }; +use vault_mock::VaultMock; +use crate::multitest::vault_mock::sv::mt::VaultMockProxy; +use vault_mock::sv::mt::CodeId as VaultCodeId; const OSMO: &str = "OSMO"; const STAR: &str = "star"; @@ -95,7 +97,7 @@ fn setup<'app>( slash_percent: u64, unbond_period: u64, ) -> ( - Proxy<'app, MtApp, VaultContract<'app>>, + Proxy<'app, MtApp, VaultMock<'app>>, Proxy<'app, MtApp, NativeStakingContract<'app>>, Proxy<'app, MtApp, ExternalStakingContract<'app>>, ) { @@ -110,7 +112,7 @@ fn setup_without_local_staking<'app>( slash_percent: u64, unbond_period: u64, ) -> ( - Proxy<'app, MtApp, VaultContract<'app>>, + Proxy<'app, MtApp, VaultMock<'app>>, Proxy<'app, MtApp, ExternalStakingContract<'app>>, ) { let (vault, _, external) = setup_inner(app, owner, slash_percent, unbond_period, false); @@ -125,11 +127,11 @@ fn setup_inner<'app>( unbond_period: u64, local_staking: bool, ) -> ( - Proxy<'app, MtApp, VaultContract<'app>>, + Proxy<'app, MtApp, VaultMock<'app>>, Option>>, Proxy<'app, MtApp, ExternalStakingContract<'app>>, ) { - let vault_code = contract::sv::mt::CodeId::store_code(app); + let vault_code = VaultCodeId::store_code(app); let staking_init_info = if local_staking { let native_staking_code = mesh_native_staking::contract::sv::mt::CodeId::store_code(app); @@ -158,7 +160,6 @@ fn setup_inner<'app>( .with_label("Vault") .call(owner) .unwrap(); - let native_staking_addr = vault.config().unwrap().local_staking.map(Addr::unchecked); let native_staking = native_staking_addr.map(|addr| Proxy::new(addr, app)); @@ -169,7 +170,7 @@ fn setup_inner<'app>( fn setup_cross_stake<'app>( app: &'app App, owner: &'app str, - vault: &Proxy<'app, MtApp, VaultContract<'app>>, + vault: &Proxy<'app, MtApp, VaultMock<'app>>, slash_percent: u64, unbond_period: u64, ) -> Proxy<'app, MtApp, ExternalStakingContract<'app>> { @@ -213,12 +214,12 @@ fn set_active_validators( } /// Bond some tokens -fn bond(vault: &Proxy<'_, MtApp, VaultContract<'_>>, user: &str, amount: u128) { +fn bond(vault: &Proxy<'_, MtApp, VaultMock<'_>>, user: &str, amount: u128) { vault.bond(coin(amount, OSMO)).call(user).unwrap(); } fn stake_locally( - vault: &Proxy<'_, MtApp, VaultContract<'_>>, + vault: &Proxy<'_, MtApp, VaultMock<'_>>, user: &str, stake: u128, validator: &str, @@ -233,7 +234,7 @@ fn stake_locally( } fn stake_remotely( - vault: &Proxy<'_, MtApp, VaultContract<'_>>, + vault: &Proxy<'_, MtApp, VaultMock<'_>>, cross_staking: &Proxy<'_, MtApp, ExternalStakingContract<'_>>, user: &str, validators: &[&str], @@ -290,7 +291,7 @@ fn process_staking_unbondings(app: &App) { } #[track_caller] -fn get_last_vault_pending_tx_id(contract: &Proxy<'_, MtApp, VaultContract<'_>>) -> Option { +fn get_last_vault_pending_tx_id(contract: &Proxy<'_, MtApp, VaultMock<'_>>) -> Option { let txs = contract.all_pending_txs_desc(None, None).unwrap().txs; txs.first().map(Tx::id) } diff --git a/contracts/provider/vault/src/multitest/vault_mock.rs b/contracts/provider/vault/src/multitest/vault_mock.rs new file mode 100644 index 00000000..cd823e1d --- /dev/null +++ b/contracts/provider/vault/src/multitest/vault_mock.rs @@ -0,0 +1,1048 @@ +use cosmwasm_std::{ + coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, StdResult, Storage, SubMsgResponse, Uint128, WasmMsg +}; +use cw2::set_contract_version; +use cw_storage_plus::{Bounder, Item, Map}; +use cw_utils::{must_pay, nonpayable, parse_instantiate_response_data}; +use std::cmp::min; + +use mesh_apis::cross_staking_api::CrossStakingApiHelper; +use mesh_apis::local_staking_api::{ + sv::LocalStakingApiQueryMsg, LocalStakingApiHelper, SlashRatioResponse, +}; +use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; +use mesh_bindings::VaultCustomMsg; +use mesh_sync::Tx::InFlightStaking; +use mesh_sync::{max_range, ValueRange}; + +use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, ReplyCtx}; +use sylvia::{contract, schemars}; + +use crate::error::ContractError; +use crate::msg::{ + AccountClaimsResponse, AccountDetailsResponse, AccountResponse, AllAccountsResponse, + AllAccountsResponseItem, AllActiveExternalStakingResponse, AllTxsResponse, AllTxsResponseItem, + ConfigResponse, LienResponse, LocalStakingInfo, TxResponse, +}; +use crate::state::{Config, Lien, LocalStaking, UserInfo}; +use crate::txs::Txs; +use crate::contract::{custom, CONTRACT_NAME, CONTRACT_VERSION, REPLY_ID_INSTANTIATE, DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT}; + +fn clamp_page_limit(limit: Option) -> usize { + limit.unwrap_or(DEFAULT_PAGE_LIMIT).max(MAX_PAGE_LIMIT) as usize +} + +fn def_false() -> bool { + false +} + +/// This is a stub implementation of the virtual staking contract, for test purposes only. +pub struct VaultMock<'a> { + pub config: Item<'a, Config>, + pub local_staking: Item<'a, Option>, + pub liens: Map<'a, (&'a Addr, &'a Addr), Lien>, + pub users: Map<'a, &'a Addr, UserInfo>, + pub active_external: Map<'a, &'a Addr, ()>, + pub tx_count: Item<'a, u64>, + pub pending: Txs<'a>, +} + +#[cfg_attr(not(feature = "library"), sylvia::entry_points)] +#[contract] +#[sv::error(ContractError)] +#[sv::messages(vault_api as VaultApi)] +#[sv::custom(msg=custom::VaultContractMsg)] +impl VaultMock<'_> { + pub fn new() -> Self { + Self { + config: Item::new("config"), + local_staking: Item::new("local_staking"), + liens: Map::new("liens"), + users: Map::new("users"), + pending: Txs::new("pending_txs", "users"), + tx_count: Item::new("tx_count"), + active_external: Map::new("active_external"), + } + } + + pub fn next_tx_id(&self, store: &mut dyn Storage) -> StdResult { + let id: u64 = self.tx_count.may_load(store)?.unwrap_or_default() + 1; + self.tx_count.save(store, &id)?; + Ok(id) + } + + #[sv::msg(instantiate)] + pub fn instantiate( + &self, + ctx: InstantiateCtx, + denom: String, + local_staking: Option, + ) -> Result { + nonpayable(&ctx.info)?; + + let config = Config { denom }; + self.config.save(ctx.deps.storage, &config)?; + set_contract_version(ctx.deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + + if let Some(local_staking) = local_staking { + match local_staking { + LocalStakingInfo::Existing(exist) => { + let addr = exist.existing; + + let local_staking = LocalStaking { + contract: LocalStakingApiHelper(ctx.deps.api.addr_validate(&addr)?), + max_slash: Decimal::percent(10), + }; + + self.local_staking + .save(ctx.deps.storage, &Some(local_staking))?; + Ok(Response::new()) + } + LocalStakingInfo::New(_) => { + Ok(Response::new()) + } + } + } else { + self.local_staking.save(ctx.deps.storage, &None)?; + Ok(Response::new()) + } + } + + #[sv::msg(exec)] + fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result { + nonpayable(&ctx.info)?; + + let denom = self.config.load(ctx.deps.storage)?.denom; + ensure!(denom == amount.denom, ContractError::UnexpectedDenom(denom)); + + let mut user = self + .users + .may_load(ctx.deps.storage, &ctx.info.sender)? + .unwrap_or_default(); + user.collateral += amount.amount; + self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; + + Ok(Response::new()) + } + + #[sv::msg(exec)] + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { + nonpayable(&ctx.info)?; + + let denom = self.config.load(ctx.deps.storage)?.denom; + ensure!(denom == amount.denom, ContractError::UnexpectedDenom(denom)); + + let mut user = self + .users + .may_load(ctx.deps.storage, &ctx.info.sender)? + .unwrap_or_default(); + + let free_collateral = user.free_collateral(); + ensure!( + free_collateral.low() >= amount.amount, + ContractError::ClaimsLocked(free_collateral) + ); + + user.collateral -= amount.amount; + self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; + + Ok(Response::new()) + } + + #[sv::msg(exec)] + fn stake_remote( + &self, + mut ctx: ExecCtx, + // address of the contract to virtually stake on + contract: String, + // amount to stake on that contract + amount: Coin, + // action to take with that stake + msg: Binary, + ) -> Result { + nonpayable(&ctx.info)?; + + let config = self.config.load(ctx.deps.storage)?; + let contract = ctx.deps.api.addr_validate(&contract)?; + let contract = CrossStakingApiHelper(contract); + let slashable = contract.max_slash(ctx.deps.as_ref())?; + + let tx_id = self.stake( + &mut ctx, + &config, + &contract.0, + slashable.slash_ratio_dsign, + amount.clone(), + true, + )?; + + let stake_msg = contract.receive_virtual_stake( + ctx.info.sender.to_string(), + amount.clone(), + tx_id, + msg, + vec![], + )?; + + self.active_external + .save(ctx.deps.storage, &contract.0, &())?; + + let resp = Response::new() + .add_message(stake_msg) + .add_attribute("action", "stake_remote") + .add_attribute("sender", ctx.info.sender) + .add_attribute("amount", amount.amount.to_string()) + .add_attribute("tx_id", tx_id.to_string()); + + Ok(resp) + } + + /// This sends actual tokens to the local staking contract + #[sv::msg(exec)] + fn stake_local( + &self, + mut ctx: ExecCtx, + // amount to stake on that contract + amount: Coin, + // action to take with that stake + msg: Binary, + ) -> Result { + nonpayable(&ctx.info)?; + + let config = self.config.load(ctx.deps.storage)?; + if let Some(local_staking) = self.local_staking.load(ctx.deps.storage)? { + self.stake( + &mut ctx, + &config, + &local_staking.contract.0, + local_staking.max_slash, + amount.clone(), + false, + )?; + + let stake_msg = local_staking.contract.receive_stake( + ctx.info.sender.to_string(), + msg, + vec![amount.clone()], + )?; + + let resp = Response::new() + .add_message(stake_msg) + .add_attribute("action", "stake_local") + .add_attribute("sender", ctx.info.sender) + .add_attribute("amount", amount.amount.to_string()); + + Ok(resp) + } else { + Err(ContractError::NoLocalStaking) + } + } + + #[sv::msg(query)] + fn account(&self, ctx: QueryCtx, account: String) -> Result { + let denom = self.config.load(ctx.deps.storage)?.denom; + let account = ctx.deps.api.addr_validate(&account)?; + + let user = self + .users + .may_load(ctx.deps.storage, &account)? + .unwrap_or_default(); + Ok(AccountResponse { + denom, + bonded: user.collateral, + free: user.free_collateral(), + }) + } + + #[sv::msg(query)] + fn account_details( + &self, + ctx: QueryCtx, + account: String, + ) -> Result { + let denom = self.config.load(ctx.deps.storage)?.denom; + let account = ctx.deps.api.addr_validate(&account)?; + + let user = self + .users + .may_load(ctx.deps.storage, &account)? + .unwrap_or_default(); + Ok(AccountDetailsResponse { + denom, + bonded: user.collateral, + free: user.free_collateral(), + max_lien: user.max_lien, + total_slashable: user.total_slashable, + }) + } + + #[sv::msg(query)] + fn config(&self, ctx: QueryCtx) -> Result { + let config = self.config.load(ctx.deps.storage)?; + let local_staking = self.local_staking.load(ctx.deps.storage)?; + + let resp = ConfigResponse { + denom: config.denom, + local_staking: local_staking.map(|ls| ls.contract.0.into()), + }; + + Ok(resp) + } + + #[sv::msg(query)] + fn active_external_staking( + &self, + ctx: QueryCtx, + ) -> Result { + let active = self + .active_external + .keys(ctx.deps.storage, None, None, Order::Ascending) + .collect::>>()?; + + let resp = AllActiveExternalStakingResponse { + contracts: active.into_iter().map(|addr| addr.to_string()).collect(), + }; + + Ok(resp) + } + + /// Returns a single claim between the user and lienholder + #[sv::msg(query)] + fn claim( + &self, + ctx: QueryCtx, + account: String, + lienholder: String, + ) -> Result { + let account = ctx.deps.api.addr_validate(&account)?; + let lienholder = ctx.deps.api.addr_validate(&lienholder)?; + + self.liens + .may_load(ctx.deps.storage, (&account, &lienholder))? + .ok_or(ContractError::NoClaim) + } + + /// Returns paginated claims list for an user + /// + /// `start_after` is a last lienholder of the previous page, and it will not be included + #[sv::msg(query)] + fn account_claims( + &self, + ctx: QueryCtx, + account: String, + start_after: Option, + limit: Option, + ) -> Result { + let limit = clamp_page_limit(limit); + let start_after = start_after.map(Addr::unchecked); + let bound = start_after.as_ref().and_then(Bounder::exclusive_bound); + + let account = Addr::unchecked(account); + let claims = self + .liens + .prefix(&account) + .range(ctx.deps.storage, bound, None, Order::Ascending) + .map(|item| { + let (lienholder, lien) = item?; + Ok::<_, ContractError>(LienResponse { + lienholder: lienholder.to_string(), + amount: lien.amount, + }) + }) + .take(limit) + .collect::>()?; + + let resp = AccountClaimsResponse { claims }; + + Ok(resp) + } + + /// Queries for all users ever performing action in the system, paginating over + /// them. + /// + /// `start_after` is the last account included in previous page + /// + /// `with_collateral` flag filters out users with no collateral, defaulted to false + #[sv::msg(query)] + fn all_accounts( + &self, + ctx: QueryCtx, + #[serde(default = "def_false")] with_collateral: bool, + start_after: Option, + limit: Option, + ) -> Result { + let limit = clamp_page_limit(limit); + let start_after = start_after.map(Addr::unchecked); + let bound = start_after.as_ref().and_then(Bounder::exclusive_bound); + + let denom = self.config.load(ctx.deps.storage)?.denom; + + let accounts: Vec<_> = self + .users + .range(ctx.deps.storage, bound, None, Order::Ascending) + .filter(|account| { + account + .as_ref() + .map(|(_, account)| { + !with_collateral || !account.collateral.is_zero() // Skip zero collateral + }) + .unwrap_or(false) // Skip other errors + }) + .map(|account| { + account.map(|(addr, account)| AllAccountsResponseItem { + user: addr.to_string(), + account: AccountResponse { + denom: denom.clone(), + bonded: account.collateral, + free: account.free_collateral(), + }, + }) + }) + .take(limit) + .collect::>()?; + + let resp = AllAccountsResponse { accounts }; + + Ok(resp) + } + + /// Queries a pending tx. + #[sv::msg(query)] + fn pending_tx(&self, ctx: QueryCtx, tx_id: u64) -> Result { + let resp = self.pending.txs.load(ctx.deps.storage, tx_id)?; + Ok(resp) + } + + #[sv::msg(query)] + fn all_pending_txs_desc( + &self, + ctx: QueryCtx, + start_after: Option, + limit: Option, + ) -> Result { + let limit = clamp_page_limit(limit); + let bound = start_after.and_then(Bounder::exclusive_bound); + + let txs = self + .pending + .txs + .range(ctx.deps.storage, None, bound, Order::Descending) + .map(|item| { + let (_id, tx) = item?; + Ok::(tx) + }) + .take(limit) + .collect::>()?; + + let resp = AllTxsResponse { txs }; + + Ok(resp) + } + + #[sv::msg(reply)] + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { + match reply.id { + REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), + _ => Err(ContractError::InvalidReplyId(reply.id)), + } + } + + fn reply_init_callback( + &self, + deps: DepsMut, + reply: SubMsgResponse, + ) -> Result { + let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; + let local_staking = Addr::unchecked(init_data.contract_address); + + // As we control the local staking contract it might be better to just raw-query it + // on demand instead of duplicating the data. + let query = LocalStakingApiQueryMsg::MaxSlash {}; + let SlashRatioResponse { + slash_ratio_dsign, .. + } = deps.querier.query_wasm_smart(&local_staking, &query)?; + + let local_staking = LocalStaking { + contract: LocalStakingApiHelper(local_staking), + max_slash: slash_ratio_dsign, + }; + + self.local_staking + .save(deps.storage, &Some(local_staking))?; + + Ok(Response::new()) + } + + fn stake( + &self, + ctx: &mut ExecCtx, + config: &Config, + lienholder: &Addr, + slashable: Decimal, + amount: Coin, + remote: bool, + ) -> Result { + ensure!( + amount.denom == config.denom, + ContractError::UnexpectedDenom(config.denom.clone()) + ); + + let amount = amount.amount; + let mut lien = self + .liens + .may_load(ctx.deps.storage, (&ctx.info.sender, lienholder))? + .unwrap_or_else(|| Lien { + amount: ValueRange::new_val(Uint128::zero()), + slashable, + }); + let mut user = self + .users + .may_load(ctx.deps.storage, &ctx.info.sender)? + .unwrap_or_default(); + if remote { + lien.amount + .prepare_add(amount, user.collateral) + .map_err(|_| ContractError::InsufficentBalance)?; + // Tentative value + user.max_lien = max_range(user.max_lien, lien.amount); + user.total_slashable + .prepare_add(amount * lien.slashable, user.collateral) + .map_err(|_| ContractError::InsufficentBalance)?; + } else { + // Update lien immediately + lien.amount + .add(amount, user.collateral) + .map_err(|_| ContractError::InsufficentBalance)?; + // Update max lien and total slashable immediately + user.max_lien = max_range(user.max_lien, lien.amount); + user.total_slashable + .add(amount * lien.slashable, user.collateral) + .map_err(|_| ContractError::InsufficentBalance)?; + } + + ensure!(user.verify_collateral(), ContractError::InsufficentBalance); + + self.liens + .save(ctx.deps.storage, (&ctx.info.sender, lienholder), &lien)?; + self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; + let tx_id = if remote { + // Create new tx + let tx_id = self.next_tx_id(ctx.deps.storage)?; + + let new_tx = InFlightStaking { + id: tx_id, + amount, + slashable, + user: ctx.info.sender.clone(), + lienholder: lienholder.clone(), + }; + self.pending.txs.save(ctx.deps.storage, tx_id, &new_tx)?; + tx_id + } else { + 0 + }; + Ok(tx_id) + } + + /// Commits a pending stake + fn commit_stake(&self, ctx: &mut ExecCtx, tx_id: u64) -> Result<(), ContractError> { + // Load tx + let tx = self.pending.txs.load(ctx.deps.storage, tx_id)?; + + // Verify tx comes from the right contract, and is of the right type + ensure!( + match tx.clone() { + InFlightStaking { lienholder, .. } => { + ensure!( + lienholder == ctx.info.sender, + ContractError::WrongContractTx(tx_id, ctx.info.sender.clone()) + ); + true + } + _ => false, + }, + ContractError::WrongTypeTx(tx_id, tx) + ); + + let (tx_amount, tx_user, tx_lienholder) = match tx { + InFlightStaking { + amount, + user, + lienholder, + .. + } => (amount, user, lienholder), + _ => unreachable!(), + }; + + // Load lien + let mut lien = self + .liens + .load(ctx.deps.storage, (&tx_user, &tx_lienholder))?; + // Commit it + lien.amount.commit_add(tx_amount); + // Save it + self.liens + .save(ctx.deps.storage, (&tx_user, &tx_lienholder), &lien)?; + // Load user + let mut user = self.users.load(ctx.deps.storage, &tx_user)?; + // Update max lien definitive value (it depends on the lien's value range) + user.max_lien = max_range(user.max_lien, lien.amount); + // Commit total slashable + user.total_slashable.commit_add(tx_amount * lien.slashable); + // Save it + self.users.save(ctx.deps.storage, &tx_user, &user)?; + + // Remove tx + self.pending.txs.remove(ctx.deps.storage, tx_id)?; + + Ok(()) + } + + /// Rollbacks a pending tx + fn rollback_stake(&self, ctx: &mut ExecCtx, tx_id: u64) -> Result<(), ContractError> { + // Load tx + let tx = self.pending.txs.load(ctx.deps.storage, tx_id)?; + + // Verify tx comes from the right contract, and is of the right type + ensure!( + match tx.clone() { + InFlightStaking { lienholder, .. } => { + ensure!( + lienholder == ctx.info.sender, + ContractError::WrongContractTx(tx_id, ctx.info.sender.clone()) + ); + true + } + _ => false, + }, + ContractError::WrongTypeTx(tx_id, tx) + ); + + let (tx_amount, tx_slashable, tx_user, tx_lienholder) = match tx { + InFlightStaking { + amount, + slashable, + user, + lienholder, + .. + } => (amount, slashable, user, lienholder), + _ => unreachable!(), + }; + + // Load lien + let mut lien = self + .liens + .load(ctx.deps.storage, (&tx_user, &tx_lienholder))?; + // Rollback amount + lien.amount.rollback_add(tx_amount); + if lien.amount.high().u128() == 0 { + // Remove lien if it's empty + self.liens + .remove(ctx.deps.storage, (&tx_user, &tx_lienholder)); + } else { + // Save lien + self.liens + .save(ctx.deps.storage, (&tx_user, &tx_lienholder), &lien)?; + } + + // Load user + let mut user = self.users.load(ctx.deps.storage, &tx_user)?; + // Rollback user's max_lien + + // Max lien has to be recalculated from scratch; the just rolled back lien + // is already written to storage + self.recalculate_max_lien(ctx.deps.storage, &tx_user, &mut user)?; + + user.total_slashable.rollback_add(tx_amount * tx_slashable); + self.users.save(ctx.deps.storage, &tx_user, &user)?; + + // Remove tx + self.pending.txs.remove(ctx.deps.storage, tx_id)?; + Ok(()) + } + + /// Recalculates the max lien for the user + fn recalculate_max_lien( + &self, + storage: &mut dyn Storage, + user: &Addr, + user_info: &mut UserInfo, + ) -> Result<(), ContractError> { + user_info.max_lien = self + .liens + .prefix(user) + .range(storage, None, None, Order::Ascending) + .try_fold(ValueRange::new_val(Uint128::zero()), |max_lien, item| { + let (_, lien) = item?; + Ok::<_, ContractError>(max_range(max_lien, lien.amount)) + })?; + Ok(()) + } + + /// Updates the local stake for unstaking from any contract + /// + /// The unstake (both local and remote) is always called by the staking contract + /// (aka lien_holder), so the `sender` address is used for that. + fn unstake(&self, ctx: &mut ExecCtx, owner: String, amount: Coin) -> Result<(), ContractError> { + let denom = self.config.load(ctx.deps.storage)?.denom; + ensure!(amount.denom == denom, ContractError::UnexpectedDenom(denom)); + let amount = amount.amount; + + let owner = Addr::unchecked(owner); + let mut lien = self + .liens + .may_load(ctx.deps.storage, (&owner, &ctx.info.sender))? + .ok_or(ContractError::UnknownLienholder)?; + + let slashable = lien.slashable; + lien.amount + .sub(amount, Uint128::zero()) + .map_err(|_| ContractError::InsufficientLien)?; + + if lien.amount.high().u128() == 0 { + // Remove lien if it's empty + self.liens + .remove(ctx.deps.storage, (&owner, &ctx.info.sender)); + } else { + // Save lien + self.liens + .save(ctx.deps.storage, (&owner, &ctx.info.sender), &lien)?; + } + + let mut user = self.users.load(ctx.deps.storage, &owner)?; + + // Max lien has to be recalculated from scratch; the just saved lien + // is already written to storage + self.recalculate_max_lien(ctx.deps.storage, &owner, &mut user)?; + + user.total_slashable + .sub(amount * slashable, Uint128::zero())?; + self.users.save(ctx.deps.storage, &owner, &user)?; + + Ok(()) + } + + /// Processes a (remote or local) slashing event. + /// + /// This slashes the users that have funds delegated to the validator involved in the + /// misbehaviour. + /// It also checks that the mesh security invariants are not violated after slashing, + /// i.e. performs slashing propagation across lien holders, for all of the slashed users. + fn slash( + &self, + ctx: &mut ExecCtx, + slashes: &[SlashInfo], + validator: &str, + ) -> Result, ContractError> { + // Process users that belong to lien_holder + let lien_holder = ctx.info.sender.clone(); + let mut msgs = vec![]; + for slash in slashes { + let slash_user = Addr::unchecked(slash.user.clone()); + // User must have a lien with this lien holder + let mut lien = self + .liens + .load(ctx.deps.storage, (&slash_user, &lien_holder))?; + let slash_amount = slash.slash; + let mut user_info = self.users.load(ctx.deps.storage, &slash_user)?; + let new_collateral = user_info.collateral - slash_amount; + + // Slash user + lien.amount.sub(slash_amount, Uint128::zero())?; + // Save lien + self.liens + .save(ctx.deps.storage, (&slash_user, &lien_holder), &lien)?; + // Adjust total slashable and max lien + user_info + .total_slashable + .sub(slash_amount * lien.slashable, Uint128::zero())?; + self.recalculate_max_lien(ctx.deps.storage, &slash_user, &mut user_info)?; + // Get free collateral before adjusting collateral, but after slashing + let free_collateral = user_info.free_collateral().low(); // For simplicity + if free_collateral < slash_amount { + // Check / adjust mesh security invariants according to the new collateral + let burn_msgs = self.propagate_slash( + ctx.deps.storage, + &slash_user, + &mut user_info, + new_collateral, + slash_amount - free_collateral, + &lien_holder, + validator, + )?; + msgs.extend_from_slice(&burn_msgs); + } + // Adjust collateral + user_info.collateral = new_collateral; + // Recompute max lien + self.recalculate_max_lien(ctx.deps.storage, &slash_user, &mut user_info)?; + // Save user info + self.users.save(ctx.deps.storage, &slash_user, &user_info)?; + } + Ok(msgs) + } + + #[allow(clippy::too_many_arguments)] + fn propagate_slash( + &self, + storage: &mut dyn Storage, + user: &Addr, + user_info: &mut UserInfo, + new_collateral: Uint128, + claimed_collateral: Uint128, + slashed_lien_holder: &Addr, + slashed_validator: &str, + ) -> Result, ContractError> { + let denom = self.config.load(storage)?.denom; + let native_staking = self.local_staking.load(storage)?; + let mut msgs = vec![]; + if user_info.max_lien.high() >= user_info.total_slashable.high() { + // Liens adjustment + let broken_liens = self + .liens + .prefix(user) + .range(storage, None, None, Order::Ascending) + .filter(|item| { + item.as_ref() + .map(|(_, lien)| lien.amount.high() > new_collateral) // Skip in range liens + .unwrap_or(false) // Skip other errors + }) + .collect::>>()?; + for (lien_holder, mut lien) in broken_liens { + let new_low_amount = min(lien.amount.low(), new_collateral); + let new_high_amount = min(lien.amount.high(), new_collateral); + // Adjust the user's total slashable amount + let adjust_amount_low = lien.amount.low() - new_low_amount; + let adjust_amount_high = lien.amount.high() - new_high_amount; + user_info.total_slashable = ValueRange::new( + user_info.total_slashable.low() - adjust_amount_low * lien.slashable, + user_info.total_slashable.high() - adjust_amount_high * lien.slashable, + ); + // Keep the invariant over the lien + lien.amount = ValueRange::new(new_low_amount, new_high_amount); + self.liens.save(storage, (user, &lien_holder), &lien)?; + // Remove the required amount from the user's stake + let validator = if lien_holder == slashed_lien_holder { + Some(slashed_validator.to_string()) + } else { + None + }; + let burn_msg = self.burn_stake( + user, + &denom, + &native_staking, + &lien_holder, + adjust_amount_high, // High amount for simplicity + validator, + )?; + msgs.push(burn_msg); + } + } else { + // Total slashable adjustment + let slash_ratio_sum = self + .liens + .prefix(user) + .range(storage, None, None, Order::Ascending) + .try_fold(Decimal::zero(), |sum, item| { + let (_, lien) = item?; + Ok::<_, ContractError>(sum + lien.slashable) + })?; + let round_up = if (claimed_collateral * slash_ratio_sum.inv().unwrap()) + * slash_ratio_sum + != claimed_collateral + { + Uint128::one() + } else { + Uint128::zero() + }; + let sub_amount = claimed_collateral * slash_ratio_sum.inv().unwrap() + round_up; + let all_liens = self + .liens + .prefix(user) + .range(storage, None, None, Order::Ascending) + .collect::>>()?; + for (lien_holder, mut lien) in all_liens { + // Adjust the user's total slashable amount + user_info + .total_slashable + .sub(sub_amount * lien.slashable, Uint128::zero())?; + // Keep the invariant over the lien + lien.amount.sub(sub_amount, Uint128::zero())?; + self.liens.save(storage, (user, &lien_holder), &lien)?; + // Remove the required amount from the user's stake + let validator = if lien_holder == slashed_lien_holder { + Some(slashed_validator.to_string()) + } else { + None + }; + let burn_msg = self.burn_stake( + user, + &denom, + &native_staking, + &lien_holder, + sub_amount, + validator, + )?; + msgs.push(burn_msg); + } + } + Ok(msgs) + } + + fn burn_stake( + &self, + user: &Addr, + denom: &String, + native_staking: &Option, + lien_holder: &Addr, + amount: Uint128, + validator: Option, + ) -> Result { + // Native vs cross staking + let msg = match &native_staking { + Some(local_staking) if local_staking.contract.0 == lien_holder => { + let contract = local_staking.contract.clone(); + contract.burn_stake(user, coin(amount.u128(), denom), validator)? + } + _ => { + let contract = CrossStakingApiHelper(lien_holder.clone()); + contract.burn_virtual_stake(user, coin(amount.u128(), denom), validator)? + } + }; + Ok(msg) + } +} + +impl VaultApi for VaultMock<'_> { + type Error = ContractError; + type ExecC = VaultCustomMsg; + + /// This must be called by the remote staking contract to release this claim + fn release_cross_stake( + &self, + mut ctx: ExecCtx, + // address of the user who originally called stake_remote + owner: String, + // amount to unstake on that contract + amount: Coin, + ) -> Result, ContractError> { + nonpayable(&ctx.info)?; + + self.unstake(&mut ctx, owner.clone(), amount.clone())?; + + let resp = Response::new() + .add_attribute("action", "release_cross_stake") + .add_attribute("sender", ctx.info.sender) + .add_attribute("owner", owner) + .add_attribute("amount", amount.amount.to_string()); + + Ok(resp) + } + + /// This must be called by the local staking contract to release this claim + /// Amount of tokens unstaked are those included in ctx.info.funds + fn release_local_stake( + &self, + mut ctx: ExecCtx, + // address of the user who originally called stake_remote + owner: String, + ) -> Result, ContractError> { + let denom = self.config.load(ctx.deps.storage)?.denom; + let amount = must_pay(&ctx.info, &denom)?; + + self.unstake(&mut ctx, owner.clone(), coin(amount.u128(), denom))?; + + let resp = Response::new() + .add_attribute("action", "release_cross_stake") + .add_attribute("sender", ctx.info.sender) + .add_attribute("owner", owner) + .add_attribute("amount", amount.to_string()); + + Ok(resp) + } + + /// This must be called by the native staking contract to process a misbehaviour + fn local_slash( + &self, + mut ctx: ExecCtx, + slashes: Vec, + validator: String, + ) -> Result, Self::Error> { + nonpayable(&ctx.info)?; + + let msgs = self.slash(&mut ctx, &slashes, &validator)?; + + let resp = Response::new() + .add_messages(msgs) + .add_attribute("action", "local_slash") + .add_attribute("lien_holder", ctx.info.sender) + .add_attribute("validator", validator.to_string()) + .add_attribute( + "users", + slashes + .iter() + .map(|s| s.user.clone()) + .collect::>() + .join(", "), + ); + + Ok(resp) + } + + /// This must be called by the external staking contract to process a misbehaviour + fn cross_slash( + &self, + mut ctx: ExecCtx, + slashes: Vec, + validator: String, + ) -> Result, Self::Error> { + nonpayable(&ctx.info)?; + + let msgs = self.slash(&mut ctx, &slashes, &validator)?; + + let resp = Response::new() + .add_messages(msgs) + .add_attribute("action", "cross_slash") + .add_attribute("lien_holder", ctx.info.sender) + .add_attribute("validator", validator.to_string()) + .add_attribute( + "users", + slashes + .iter() + .map(|s| s.user.clone()) + .collect::>() + .join(", "), + ); + + Ok(resp) + } + + fn commit_tx( + &self, + mut ctx: ExecCtx, + tx_id: u64, + ) -> Result, ContractError> { + self.commit_stake(&mut ctx, tx_id)?; + + let resp = Response::new() + .add_attribute("action", "commit_tx") + .add_attribute("sender", ctx.info.sender) + .add_attribute("tx_id", tx_id.to_string()); + + Ok(resp) + } + + fn rollback_tx( + &self, + mut ctx: ExecCtx, + tx_id: u64, + ) -> Result, ContractError> { + self.rollback_stake(&mut ctx, tx_id)?; + + let resp = Response::new() + .add_attribute("action", "rollback_tx") + .add_attribute("sender", ctx.info.sender) + .add_attribute("tx_id", tx_id.to_string()); + Ok(resp) + } +} From 245169b9ddaabe53960f652f4f8d9390d4924937 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Mon, 8 Jul 2024 20:06:23 +0700 Subject: [PATCH 20/29] add mock for multitest --- contracts/provider/external-staking/src/multitest.rs | 8 ++++---- .../provider/external-staking/src/multitest/utils.rs | 4 ++-- contracts/provider/vault/src/lib.rs | 1 + .../vault/src/{multitest/vault_mock.rs => mock.rs} | 5 +++-- contracts/provider/vault/src/multitest.rs | 8 +++----- 5 files changed, 13 insertions(+), 13 deletions(-) rename contracts/provider/vault/src/{multitest/vault_mock.rs => mock.rs} (99%) diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index de5e3ac2..1c78ba1c 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -7,8 +7,8 @@ use cw_multi_test::{no_init, AppBuilder}; use mesh_native_staking::contract::sv::mt::CodeId as NativeStakingCodeId; use mesh_native_staking::contract::sv::InstantiateMsg as NativeStakingInstantiateMsg; use mesh_native_staking_proxy::contract::sv::mt::CodeId as NativeStakingProxyCodeId; -use mesh_vault::contract::sv::mt::CodeId as VaultCodeId; -use mesh_vault::contract::VaultContract; +use mesh_vault::mock::sv::mt::CodeId as VaultCodeId; +use mesh_vault::mock::VaultMock; use mesh_vault::msg::{LocalStakingInfo, StakingInitInfo}; use mesh_sync::ValueRange; @@ -18,7 +18,7 @@ use sylvia::multitest::{App, Proxy}; use crate::contract::sv::mt::ExternalStakingContractProxy; use crate::test_methods::sv::mt::TestMethodsProxy; use mesh_apis::cross_staking_api::sv::mt::CrossStakingApiProxy; -use mesh_vault::contract::sv::mt::VaultContractProxy; +use mesh_vault::mock::sv::mt::VaultMockProxy; use crate::contract::sv::mt::CodeId; use crate::contract::ExternalStakingContract; @@ -53,7 +53,7 @@ fn setup<'app>( owner: &'app str, unbond_period: u64, ) -> AnyResult<( - Proxy<'app, MtApp, VaultContract<'app>>, + Proxy<'app, MtApp, VaultMock<'app>>, Proxy<'app, MtApp, ExternalStakingContract<'app>>, )> { let native_staking_proxy_code = NativeStakingProxyCodeId::store_code(app); diff --git a/contracts/provider/external-staking/src/multitest/utils.rs b/contracts/provider/external-staking/src/multitest/utils.rs index e2a3ed1e..3303a513 100644 --- a/contracts/provider/external-staking/src/multitest/utils.rs +++ b/contracts/provider/external-staking/src/multitest/utils.rs @@ -2,7 +2,7 @@ use cosmwasm_std::{to_json_binary, Addr, Coin, Empty}; use cw_multi_test::{AppBuilder, AppResponse}; use mesh_apis::{converter_api::RewardInfo, ibc::AddValidator}; use mesh_sync::Tx; -use mesh_vault::contract::{sv::mt::VaultContractProxy, VaultContract}; +use mesh_vault::mock::{sv::mt::VaultMockProxy, VaultMock}; use sylvia::multitest::{App, Proxy}; use crate::{ @@ -66,7 +66,7 @@ impl AppExt for App { } } -type Vault<'app> = Proxy<'app, MtApp, VaultContract<'app>>; +type Vault<'app> = Proxy<'app, MtApp, VaultMock<'app>>; type Contract<'app> = Proxy<'app, MtApp, ExternalStakingContract<'app>>; pub(crate) trait ContractExt { diff --git a/contracts/provider/vault/src/lib.rs b/contracts/provider/vault/src/lib.rs index c97bc6e5..1876926d 100644 --- a/contracts/provider/vault/src/lib.rs +++ b/contracts/provider/vault/src/lib.rs @@ -3,5 +3,6 @@ pub mod error; pub mod msg; #[cfg(test)] pub mod multitest; +pub mod mock; mod state; pub mod txs; diff --git a/contracts/provider/vault/src/multitest/vault_mock.rs b/contracts/provider/vault/src/mock.rs similarity index 99% rename from contracts/provider/vault/src/multitest/vault_mock.rs rename to contracts/provider/vault/src/mock.rs index cd823e1d..8d0c826b 100644 --- a/contracts/provider/vault/src/multitest/vault_mock.rs +++ b/contracts/provider/vault/src/mock.rs @@ -18,6 +18,7 @@ use mesh_sync::{max_range, ValueRange}; use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, ReplyCtx}; use sylvia::{contract, schemars}; +use crate::contract::custom::VaultContractMsg; use crate::error::ContractError; use crate::msg::{ AccountClaimsResponse, AccountDetailsResponse, AccountResponse, AllAccountsResponse, @@ -473,7 +474,7 @@ impl VaultMock<'_> { Ok(Response::new()) } - fn stake( + pub fn stake( &self, ctx: &mut ExecCtx, config: &Config, @@ -915,7 +916,7 @@ impl VaultMock<'_> { impl VaultApi for VaultMock<'_> { type Error = ContractError; - type ExecC = VaultCustomMsg; + type ExecC = VaultContractMsg; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index 0f9e76a2..fee3af88 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -1,5 +1,3 @@ -mod vault_mock; - use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Empty, Uint128, Validator}; use cw_multi_test::StakingInfo; use mesh_apis::ibc::AddValidator; @@ -24,9 +22,9 @@ use crate::msg::{ AccountResponse, AllAccountsResponseItem, AllActiveExternalStakingResponse, LienResponse, LocalStakingInfo, StakingInitInfo, }; -use vault_mock::VaultMock; -use crate::multitest::vault_mock::sv::mt::VaultMockProxy; -use vault_mock::sv::mt::CodeId as VaultCodeId; +use crate::mock::VaultMock; +use crate::mock::sv::mt::VaultMockProxy; +use crate::mock::sv::mt::CodeId as VaultCodeId; const OSMO: &str = "OSMO"; const STAR: &str = "star"; From 41f0f7da41333685942d0e4d21b570392f575cc0 Mon Sep 17 00:00:00 2001 From: Trinity Date: Mon, 8 Jul 2024 22:44:31 +0700 Subject: [PATCH 21/29] Make the code compile --- .../provider/external-staking/Cargo.toml | 1 + .../provider/external-staking/src/ibc.rs | 2 +- .../external-staking/src/multitest.rs | 3 +- contracts/provider/vault/src/contract.rs | 33 +++++++++++++++---- contracts/provider/vault/src/mock.rs | 5 +-- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index 75f517d7..2451a2ed 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -23,6 +23,7 @@ fake-custom = [ "mesh-vault/fake-custom" ] mesh-apis = { workspace = true } mesh-bindings = { workspace = true } mesh-burn = { workspace = true } +mesh-vault = { workspace = true, features = ["library"] } mesh-sync = { workspace = true } sylvia = { workspace = true } diff --git a/contracts/provider/external-staking/src/ibc.rs b/contracts/provider/external-staking/src/ibc.rs index b5503e2e..4499f349 100644 --- a/contracts/provider/external-staking/src/ibc.rs +++ b/contracts/provider/external-staking/src/ibc.rs @@ -117,7 +117,7 @@ pub fn ibc_packet_receive( deps: DepsMut, env: Env, msg: IbcPacketReceiveMsg, -) -> Result, ContractError> { +) -> Result, ContractError> { // There is only one channel, so we don't need to switch. // We also don't care about packet sequence as this is being ordered by height. // If a validator is in more than one of the events, the end result will depend on the diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index 1c78ba1c..de6a0f23 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -7,7 +7,7 @@ use cw_multi_test::{no_init, AppBuilder}; use mesh_native_staking::contract::sv::mt::CodeId as NativeStakingCodeId; use mesh_native_staking::contract::sv::InstantiateMsg as NativeStakingInstantiateMsg; use mesh_native_staking_proxy::contract::sv::mt::CodeId as NativeStakingProxyCodeId; -use mesh_vault::mock::sv::mt::CodeId as VaultCodeId; +use mesh_vault::mock::sv::mt::{CodeId as VaultCodeId, VaultMockProxy}; use mesh_vault::mock::VaultMock; use mesh_vault::msg::{LocalStakingInfo, StakingInitInfo}; @@ -18,7 +18,6 @@ use sylvia::multitest::{App, Proxy}; use crate::contract::sv::mt::ExternalStakingContractProxy; use crate::test_methods::sv::mt::TestMethodsProxy; use mesh_apis::cross_staking_api::sv::mt::CrossStakingApiProxy; -use mesh_vault::mock::sv::mt::VaultMockProxy; use crate::contract::sv::mt::CodeId; use crate::contract::ExternalStakingContract; diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index c8172a5b..f89317a3 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -11,7 +11,7 @@ use mesh_apis::local_staking_api::{ sv::LocalStakingApiQueryMsg, LocalStakingApiHelper, SlashRatioResponse, }; use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; -use mesh_bindings::{VaultCustomMsg, VaultMsg}; +use mesh_bindings::VaultMsg; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; @@ -47,15 +47,29 @@ fn def_false() -> bool { #[cfg(not(feature = "fake-custom"))] pub mod custom { + use cosmwasm_std::CosmosMsg; + use mesh_bindings::VaultMsg; + pub type VaultContractMsg = cosmwasm_std::Empty; pub type VaultContractQuery = cosmwasm_std::Empty; pub type Response = cosmwasm_std::Response; + + pub fn cosmos_msg(_msg: VaultMsg) -> Option> { + return None + } } #[cfg(feature = "fake-custom")] pub mod custom { + use cosmwasm_std::CosmosMsg; + use mesh_bindings::VaultMsg; + pub type VaultContractMsg = mesh_bindings::VaultCustomMsg; pub type VaultContractQuery = cosmwasm_std::Empty; pub type Response = cosmwasm_std::Response; + + pub fn cosmos_msg(msg: VaultMsg) -> Option> { + Some(CosmosMsg::Custom(VaultContractMsg::Vault(msg))) + } } pub struct VaultContract<'a> { @@ -169,12 +183,15 @@ impl VaultContract<'_> { user.collateral += amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let resp = Response::new() - .add_message(VaultMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}) + let msg = custom::cosmos_msg(VaultMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}); + let mut resp = Response::new() .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amt.to_string()); + if msg.is_some() { + resp = resp.add_message(msg.unwrap()) + } Ok(resp) } @@ -199,12 +216,14 @@ impl VaultContract<'_> { user.collateral -= amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let resp = Response::new() - .add_message(VaultMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}) + let msg = custom::cosmos_msg(VaultMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}); + let mut resp = Response::new() .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amt.to_string()); - + if msg.is_some() { + resp = resp.add_message(msg.unwrap()) + } Ok(resp) } @@ -994,7 +1013,7 @@ impl Default for VaultContract<'_> { impl VaultApi for VaultContract<'_> { type Error = ContractError; - type ExecC = VaultCustomMsg; + type ExecC = custom::VaultContractMsg; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( diff --git a/contracts/provider/vault/src/mock.rs b/contracts/provider/vault/src/mock.rs index 8d0c826b..30348b2d 100644 --- a/contracts/provider/vault/src/mock.rs +++ b/contracts/provider/vault/src/mock.rs @@ -11,14 +11,12 @@ use mesh_apis::local_staking_api::{ sv::LocalStakingApiQueryMsg, LocalStakingApiHelper, SlashRatioResponse, }; use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; -use mesh_bindings::VaultCustomMsg; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, ReplyCtx}; use sylvia::{contract, schemars}; -use crate::contract::custom::VaultContractMsg; use crate::error::ContractError; use crate::msg::{ AccountClaimsResponse, AccountDetailsResponse, AccountResponse, AllAccountsResponse, @@ -48,7 +46,6 @@ pub struct VaultMock<'a> { pub pending: Txs<'a>, } -#[cfg_attr(not(feature = "library"), sylvia::entry_points)] #[contract] #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] @@ -916,7 +913,7 @@ impl VaultMock<'_> { impl VaultApi for VaultMock<'_> { type Error = ContractError; - type ExecC = VaultContractMsg; + type ExecC = custom::VaultContractMsg; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( From fc38e68aa54ef27ddbcf7553d2d0828898d7d3aa Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Tue, 9 Jul 2024 04:24:01 +0700 Subject: [PATCH 22/29] remove function effect main logic --- .../provider/external-staking/Cargo.toml | 2 +- contracts/provider/vault/src/contract.rs | 64 +++++-------------- contracts/provider/vault/src/mock.rs | 21 +++--- 3 files changed, 29 insertions(+), 58 deletions(-) diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index 2451a2ed..8cf59681 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -23,7 +23,7 @@ fake-custom = [ "mesh-vault/fake-custom" ] mesh-apis = { workspace = true } mesh-bindings = { workspace = true } mesh-burn = { workspace = true } -mesh-vault = { workspace = true, features = ["library"] } +mesh-vault = { workspace = true } mesh-sync = { workspace = true } sylvia = { workspace = true } diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index f89317a3..0dacce4e 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -11,7 +11,7 @@ use mesh_apis::local_staking_api::{ sv::LocalStakingApiQueryMsg, LocalStakingApiHelper, SlashRatioResponse, }; use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; -use mesh_bindings::VaultMsg; +use mesh_bindings::{VaultCustomMsg, VaultMsg}; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; @@ -45,33 +45,6 @@ fn def_false() -> bool { false } -#[cfg(not(feature = "fake-custom"))] -pub mod custom { - use cosmwasm_std::CosmosMsg; - use mesh_bindings::VaultMsg; - - pub type VaultContractMsg = cosmwasm_std::Empty; - pub type VaultContractQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; - - pub fn cosmos_msg(_msg: VaultMsg) -> Option> { - return None - } -} -#[cfg(feature = "fake-custom")] -pub mod custom { - use cosmwasm_std::CosmosMsg; - use mesh_bindings::VaultMsg; - - pub type VaultContractMsg = mesh_bindings::VaultCustomMsg; - pub type VaultContractQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; - - pub fn cosmos_msg(msg: VaultMsg) -> Option> { - Some(CosmosMsg::Custom(VaultContractMsg::Vault(msg))) - } -} - pub struct VaultContract<'a> { /// General contract configuration pub config: Item<'a, Config>, @@ -95,7 +68,7 @@ pub struct VaultContract<'a> { #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] /// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::VaultContractMsg)] +#[sv::custom(msg=VaultCustomMsg)] impl VaultContract<'_> { pub fn new() -> Self { Self { @@ -121,7 +94,7 @@ impl VaultContract<'_> { ctx: InstantiateCtx, denom: String, local_staking: Option, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = Config { denom }; @@ -170,7 +143,7 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -183,20 +156,18 @@ impl VaultContract<'_> { user.collateral += amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let msg = custom::cosmos_msg(VaultMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}); - let mut resp = Response::new() + let msg = VaultMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}; + let resp = Response::new() + .add_message(msg) .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amt.to_string()); - if msg.is_some() { - resp = resp.add_message(msg.unwrap()) - } Ok(resp) } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -216,14 +187,13 @@ impl VaultContract<'_> { user.collateral -= amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let msg = custom::cosmos_msg(VaultMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}); - let mut resp = Response::new() + let msg = VaultMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}; + let resp = Response::new() + .add_message(msg) .add_attribute("action", "unbond") .add_attribute("sender", ctx.info.sender) .add_attribute("amount", amt.to_string()); - if msg.is_some() { - resp = resp.add_message(msg.unwrap()) - } + Ok(resp) } @@ -238,7 +208,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -285,7 +255,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -522,7 +492,7 @@ impl VaultContract<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result, ContractError> { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -533,7 +503,7 @@ impl VaultContract<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result { + ) -> Result, ContractError> { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; let local_staking = Addr::unchecked(init_data.contract_address); @@ -1013,7 +983,7 @@ impl Default for VaultContract<'_> { impl VaultApi for VaultContract<'_> { type Error = ContractError; - type ExecC = custom::VaultContractMsg; + type ExecC = VaultCustomMsg; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( diff --git a/contracts/provider/vault/src/mock.rs b/contracts/provider/vault/src/mock.rs index 30348b2d..fcd0af9f 100644 --- a/contracts/provider/vault/src/mock.rs +++ b/contracts/provider/vault/src/mock.rs @@ -13,6 +13,7 @@ use mesh_apis::local_staking_api::{ use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; +use mesh_bindings::VaultCustomMsg; use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, ReplyCtx}; use sylvia::{contract, schemars}; @@ -25,7 +26,7 @@ use crate::msg::{ }; use crate::state::{Config, Lien, LocalStaking, UserInfo}; use crate::txs::Txs; -use crate::contract::{custom, CONTRACT_NAME, CONTRACT_VERSION, REPLY_ID_INSTANTIATE, DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT}; +use crate::contract::{CONTRACT_NAME, CONTRACT_VERSION, REPLY_ID_INSTANTIATE, DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT}; fn clamp_page_limit(limit: Option) -> usize { limit.unwrap_or(DEFAULT_PAGE_LIMIT).max(MAX_PAGE_LIMIT) as usize @@ -49,7 +50,7 @@ pub struct VaultMock<'a> { #[contract] #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] -#[sv::custom(msg=custom::VaultContractMsg)] +#[sv::custom(msg=VaultCustomMsg)] impl VaultMock<'_> { pub fn new() -> Self { Self { @@ -75,7 +76,7 @@ impl VaultMock<'_> { ctx: InstantiateCtx, denom: String, local_staking: Option, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = Config { denom }; @@ -107,7 +108,7 @@ impl VaultMock<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -124,7 +125,7 @@ impl VaultMock<'_> { } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -157,7 +158,7 @@ impl VaultMock<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -204,7 +205,7 @@ impl VaultMock<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -438,7 +439,7 @@ impl VaultMock<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result, ContractError> { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -449,7 +450,7 @@ impl VaultMock<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result { + ) -> Result, ContractError> { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; let local_staking = Addr::unchecked(init_data.contract_address); @@ -913,7 +914,7 @@ impl VaultMock<'_> { impl VaultApi for VaultMock<'_> { type Error = ContractError; - type ExecC = custom::VaultContractMsg; + type ExecC = VaultCustomMsg; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( From 5d83a8428de9376079204d7286f5d42e8d13e14c Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Tue, 9 Jul 2024 12:01:11 +0700 Subject: [PATCH 23/29] remove unused deps --- contracts/provider/external-staking/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index 8cf59681..75f517d7 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -23,7 +23,6 @@ fake-custom = [ "mesh-vault/fake-custom" ] mesh-apis = { workspace = true } mesh-bindings = { workspace = true } mesh-burn = { workspace = true } -mesh-vault = { workspace = true } mesh-sync = { workspace = true } sylvia = { workspace = true } From f30397be552967e91faaa4d20a4758f7509a2e24 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Tue, 9 Jul 2024 13:54:46 +0700 Subject: [PATCH 24/29] remove fake custom --- .../provider/external-staking/Cargo.toml | 7 +- .../provider/external-staking/src/contract.rs | 29 ++----- .../provider/external-staking/src/ibc.rs | 4 +- .../external-staking/src/multitest.rs | 78 +++++++++---------- .../external-staking/src/multitest/utils.rs | 10 +-- .../external-staking/src/test_methods.rs | 27 ++++--- .../external-staking/src/test_methods_impl.rs | 27 ++++--- .../provider/native-staking-proxy/Cargo.toml | 2 - .../native-staking-proxy/src/contract.rs | 33 +++----- .../native-staking-proxy/src/multitest.rs | 22 ++---- contracts/provider/native-staking/Cargo.toml | 4 +- .../provider/native-staking/src/contract.rs | 12 +-- .../native-staking/src/local_staking_api.rs | 4 +- .../provider/native-staking/src/multitest.rs | 20 ++--- .../src/native_staking_callback.rs | 2 +- contracts/provider/vault/Cargo.toml | 4 +- contracts/provider/vault/src/mock.rs | 59 +++++++++----- contracts/provider/vault/src/multitest.rs | 14 +--- packages/apis/src/cross_staking_api.rs | 7 +- 19 files changed, 155 insertions(+), 210 deletions(-) diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index 75f517d7..ea675650 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -17,7 +17,6 @@ library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] # enable this for multi-tests where you need custom messages for compatibility with vault -fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } @@ -40,9 +39,9 @@ thiserror = { workspace = true } sylvia = { workspace = true, features = ["mt"] } cw-multi-test = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } -mesh-native-staking-proxy = { workspace = true, features = ["mt", "fake-custom"] } -mesh-native-staking = { workspace = true, features = ["mt", "fake-custom"] } +mesh-vault = { workspace = true, features = ["mt"] } +mesh-native-staking-proxy = { workspace = true, features = ["mt"] } +mesh-native-staking = { workspace = true, features = ["mt"] } mesh-sync = { workspace = true } [[bin]] diff --git a/contracts/provider/external-staking/src/contract.rs b/contracts/provider/external-staking/src/contract.rs index 49b14b8b..25293bc3 100644 --- a/contracts/provider/external-staking/src/contract.rs +++ b/contracts/provider/external-staking/src/contract.rs @@ -41,19 +41,6 @@ fn clamp_page_limit(limit: Option) -> usize { limit.unwrap_or(DEFAULT_PAGE_LIMIT).max(MAX_PAGE_LIMIT) as usize } -#[cfg(not(feature = "fake-custom"))] -pub mod custom { - pub type ExternalStakingMsg = cosmwasm_std::Empty; - pub type ExternalStakingQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; -} -#[cfg(feature = "fake-custom")] -pub mod custom { - pub type ExternalStakingMsg = mesh_bindings::VaultCustomMsg; - pub type ExternalStakingQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; -} - pub struct ExternalStakingContract<'a> { pub config: Item<'a, Config>, /// Stakes indexed by `(owner, validator)` pair @@ -78,8 +65,6 @@ impl Default for ExternalStakingContract<'_> { #[sv::error(ContractError)] #[sv::messages(cross_staking_api as CrossStakingApi)] #[sv::messages(crate::test_methods as TestMethods)] -/// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::ExternalStakingMsg)] impl ExternalStakingContract<'_> { pub fn new() -> Self { Self { @@ -111,7 +96,7 @@ impl ExternalStakingContract<'_> { unbonding_period: u64, remote_contact: crate::msg::AuthorizedEndpoint, slash_ratio: SlashRatio, - ) -> Result { + ) -> Result { let vault = ctx.deps.api.addr_validate(&vault)?; let vault = VaultApiHelper(vault); @@ -266,7 +251,7 @@ impl ExternalStakingContract<'_> { ctx: ExecCtx, validator: String, amount: Coin, - ) -> Result { + ) -> Result { let ExecCtx { info, deps, env } = ctx; nonpayable(&info)?; @@ -616,7 +601,7 @@ impl ExternalStakingContract<'_> { /// Tokens to be claimed have to be unbond before by calling the `unbond` message, and /// their unbonding period must have passed. #[sv::msg(exec)] - pub fn withdraw_unbonded(&self, ctx: ExecCtx) -> Result { + pub fn withdraw_unbonded(&self, ctx: ExecCtx) -> Result { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -749,7 +734,7 @@ impl ExternalStakingContract<'_> { validator: String, /// Address on the consumer side to receive the rewards remote_recipient: String, - ) -> Result { + ) -> Result { nonpayable(&ctx.info)?; let stake = self @@ -1220,7 +1205,6 @@ impl ExternalStakingContract<'_> { pub mod cross_staking { use crate::msg::ReceiveVirtualStake; - use super::custom; use super::*; use cosmwasm_std::{from_json, Binary}; @@ -1230,7 +1214,6 @@ pub mod cross_staking { #[sv::messages(mesh_apis::cross_staking_api as CrossStakingApi)] impl CrossStakingApi for ExternalStakingContract<'_> { type Error = ContractError; - type ExecC = custom::ExternalStakingMsg; #[sv::msg(exec)] fn receive_virtual_stake( @@ -1240,7 +1223,7 @@ pub mod cross_staking { amount: Coin, tx_id: u64, msg: Binary, - ) -> Result { + ) -> Result { let config = self.config.load(ctx.deps.storage)?; ensure_eq!(ctx.info.sender, config.vault.0, ContractError::Unauthorized); @@ -1323,7 +1306,7 @@ pub mod cross_staking { owner: String, amount: Coin, validator: Option, - ) -> Result { + ) -> Result { let config = self.config.load(ctx.deps.storage)?; ensure_eq!(ctx.info.sender, config.vault.0, ContractError::Unauthorized); diff --git a/contracts/provider/external-staking/src/ibc.rs b/contracts/provider/external-staking/src/ibc.rs index 4499f349..69127f2d 100644 --- a/contracts/provider/external-staking/src/ibc.rs +++ b/contracts/provider/external-staking/src/ibc.rs @@ -12,7 +12,7 @@ use mesh_apis::ibc::{ ProtocolVersion, ProviderPacket, ValsetUpdateAck, }; -use crate::contract::{custom, ExternalStakingContract}; +use crate::contract::ExternalStakingContract; use crate::error::ContractError; use crate::msg::AuthorizedEndpoint; @@ -117,7 +117,7 @@ pub fn ibc_packet_receive( deps: DepsMut, env: Env, msg: IbcPacketReceiveMsg, -) -> Result, ContractError> { +) -> Result { // There is only one channel, so we don't need to switch. // We also don't care about packet sequence as this is being ordered by height. // If a validator is in more than one of the events, the end result will depend on the diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index de6a0f23..cbbde1cc 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -2,8 +2,8 @@ mod utils; use anyhow::Result as AnyResult; -use cosmwasm_std::{coin, coins, to_json_binary, Decimal, Empty, Uint128}; -use cw_multi_test::{no_init, AppBuilder}; +use cosmwasm_std::{coin, coins, to_json_binary, Decimal, Uint128}; +use cw_multi_test::App as MtApp; use mesh_native_staking::contract::sv::mt::CodeId as NativeStakingCodeId; use mesh_native_staking::contract::sv::InstantiateMsg as NativeStakingInstantiateMsg; use mesh_native_staking_proxy::contract::sv::mt::CodeId as NativeStakingProxyCodeId; @@ -38,12 +38,6 @@ const SLASHING_PERCENTAGE: u64 = 10; const LOCAL_SLASHING_PERCENTAGE_DSIGN: u64 = 5; const LOCAL_SLASHING_PERCENTAGE_OFFLINE: u64 = 5; -// Trying to figure out how to work with the generic types -type MtApp = cw_multi_test::BasicApp< - mesh_bindings::VaultCustomMsg, - Empty, ->; - // Shortcut setuping all needed contracts // // Returns vault and external staking proxies @@ -99,7 +93,7 @@ fn setup<'app>( #[test] fn instantiate() { - let app = App::new(AppBuilder::new_custom().build(no_init)); + let app = App::default(); let owner = "owner"; let users = ["user1"]; @@ -130,12 +124,14 @@ fn staking() { // Bond tokens vault - .bond(coin(300, OSMO)) + .bond() + .with_funds(&coins(300, OSMO)) .call(users[0]) .unwrap(); vault - .bond(coin(300, OSMO)) + .bond() + .with_funds(&coins(300, OSMO)) .call(users[1]) .unwrap(); @@ -235,13 +231,13 @@ fn unstaking() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(coin(300, OSMO)) - .call(users[0]) + .bond() + .with_funds(&coins(300, OSMO)) .call(users[0]) .unwrap(); vault - .bond(coin(300, OSMO)) - .call(users[1]) + .bond() + .with_funds(&coins(300, OSMO)) .call(users[1]) .unwrap(); vault.stake(&contract, users[0], validators[0], coin(200, OSMO)); @@ -475,8 +471,8 @@ fn immediate_unstake_if_unbonded_validator() { let validators = contract.activate_validators(["validator1"]); vault - .bond(coin(200, OSMO)) - .call(user) + .bond() + .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -513,8 +509,8 @@ fn immediate_unstake_if_tombstoned_validator() { let validators = contract.activate_validators(["validator1"]); vault - .bond(coin(200, OSMO)) - .call(user) + .bond() + .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -559,13 +555,13 @@ fn distribution() { // 3/5 of validators[0] to users[1] // all of validators[1] to users[1] vault - .bond(coin(600, OSMO)) - .call(users[0]) + .bond() + .with_funds(&coins(600, OSMO)) .call(users[0]) .unwrap(); vault - .bond(coin(600, OSMO)) - .call(users[1]) + .bond() + .with_funds(&coins(600, OSMO)) .call(users[1]) .unwrap(); vault.stake(&contract, users[0], validators[0], coin(200, OSMO)); @@ -1161,12 +1157,12 @@ fn batch_distribution() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(coin(600, OSMO)) - .call(users[0]) + .bond() + .with_funds(&coins(600, OSMO)) .call(users[0]) .unwrap(); vault - .bond(coin(600, OSMO)) - .call(users[1]) + .bond() + .with_funds(&coins(600, OSMO)) .call(users[1]) .unwrap(); vault.stake(&contract, users[0], validators[0], coin(200, OSMO)); @@ -1204,8 +1200,8 @@ fn batch_distribution_invalid_token() { let validator = contract.activate_validators(["validator1"])[0]; vault - .bond(coin(600, OSMO)) - .call(user) + .bond() + .with_funds(&coins(600, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validator, coin(200, OSMO)); @@ -1229,8 +1225,8 @@ fn slashing() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(coin(300, OSMO)) - .call(user) + .bond() + .with_funds(&coins(300, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1373,8 +1369,8 @@ fn slashing_pending_tx_partial_unbond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(coin(300, OSMO)) - .call(user) + .bond() + .with_funds(&coins(300, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1459,8 +1455,8 @@ fn slashing_pending_tx_full_unbond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(coin(200, OSMO)) - .call(user) + .bond() + .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1541,8 +1537,8 @@ fn slashing_pending_tx_full_unbond_rolled_back() { let validators = contract.activate_validators(["validator1"]); vault - .bond(coin(200, OSMO)) - .call(user) + .bond() + .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1621,8 +1617,8 @@ fn slashing_pending_tx_bond() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(coin(300, OSMO)) - .call(user) + .bond() + .with_funds(&coins(300, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1705,8 +1701,8 @@ fn slashing_pending_tx_bond_rolled_back() { let validators = contract.activate_validators(["validator1", "validator2"]); vault - .bond(coin(300, OSMO)) - .call(user) + .bond() + .with_funds(&coins(300, OSMO)) .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); diff --git a/contracts/provider/external-staking/src/multitest/utils.rs b/contracts/provider/external-staking/src/multitest/utils.rs index 3303a513..5dd93860 100644 --- a/contracts/provider/external-staking/src/multitest/utils.rs +++ b/contracts/provider/external-staking/src/multitest/utils.rs @@ -1,5 +1,5 @@ -use cosmwasm_std::{to_json_binary, Addr, Coin, Empty}; -use cw_multi_test::{AppBuilder, AppResponse}; +use cosmwasm_std::{to_json_binary, Addr, Coin}; +use cw_multi_test::{App as MtApp, AppBuilder, AppResponse}; use mesh_apis::{converter_api::RewardInfo, ibc::AddValidator}; use mesh_sync::Tx; use mesh_vault::mock::{sv::mt::VaultMockProxy, VaultMock}; @@ -14,12 +14,6 @@ use crate::{ //test_methods_impl::test_utils::TestMethods as _, }; -// Trying to figure out how to work with the generic types -type MtApp = cw_multi_test::BasicApp< - mesh_bindings::VaultCustomMsg, - Empty, ->; - macro_rules! assert_rewards { ($contract:expr, $user:expr, $validator:expr, $expected:expr) => { let rewards = $contract diff --git a/contracts/provider/external-staking/src/test_methods.rs b/contracts/provider/external-staking/src/test_methods.rs index 3c3d3b83..98deae7e 100644 --- a/contracts/provider/external-staking/src/test_methods.rs +++ b/contracts/provider/external-staking/src/test_methods.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Coin, CustomMsg, Response, StdError, Uint128}; +use cosmwasm_std::{Coin, Response, StdError, Uint128}; use mesh_apis::converter_api::RewardInfo; use mesh_apis::ibc::AddValidator; use sylvia::interface; @@ -9,15 +9,14 @@ use sylvia::types::ExecCtx; #[interface] pub trait TestMethods { type Error: From; - type ExecC: CustomMsg; /// Commits a pending stake. #[sv::msg(exec)] - fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; + fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result; /// Rollbacks a pending stake. #[sv::msg(exec)] - fn test_rollback_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; + fn test_rollback_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result; /// Updates the active validator set. #[sv::msg(exec)] @@ -27,7 +26,7 @@ pub trait TestMethods { validator: AddValidator, height: u64, time: u64, - ) -> Result, Self::Error>; + ) -> Result; /// Sets validator as `unbonded`. #[sv::msg(exec)] @@ -37,7 +36,7 @@ pub trait TestMethods { valoper: String, height: u64, time: u64, - ) -> Result, Self::Error>; + ) -> Result; #[sv::msg(exec)] fn test_tombstone_validator( @@ -46,15 +45,15 @@ pub trait TestMethods { valoper: String, height: u64, time: u64, - ) -> Result, Self::Error>; + ) -> Result; /// Commits a pending unstake. #[sv::msg(exec)] - fn test_commit_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; + fn test_commit_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result; /// Rollbacks a pending unstake. #[sv::msg(exec)] - fn test_rollback_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result, Self::Error>; + fn test_rollback_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result; /// Distribute rewards. #[sv::msg(exec)] @@ -63,7 +62,7 @@ pub trait TestMethods { ctx: ExecCtx, validator: String, rewards: Coin, - ) -> Result, Self::Error>; + ) -> Result; /// Batch distribute rewards. #[sv::msg(exec)] @@ -72,7 +71,7 @@ pub trait TestMethods { ctx: ExecCtx, denom: String, rewards: Vec, - ) -> Result, Self::Error>; + ) -> Result; /// Commits a withdraw rewards transaction. #[sv::msg(exec)] @@ -80,7 +79,7 @@ pub trait TestMethods { &self, ctx: ExecCtx, tx_id: u64, - ) -> Result, Self::Error>; + ) -> Result; /// Rollbacks a withdraw rewards transaction. #[sv::msg(exec)] @@ -88,7 +87,7 @@ pub trait TestMethods { &self, ctx: ExecCtx, tx_id: u64, - ) -> Result, Self::Error>; + ) -> Result; /// Slashes a validator. /// This will not perform any check on the validator's state in the validator set, which should @@ -99,5 +98,5 @@ pub trait TestMethods { ctx: ExecCtx, validator: String, slash_amount: Uint128, - ) -> Result, Self::Error>; + ) -> Result; } diff --git a/contracts/provider/external-staking/src/test_methods_impl.rs b/contracts/provider/external-staking/src/test_methods_impl.rs index 4c92ab1a..498b671d 100644 --- a/contracts/provider/external-staking/src/test_methods_impl.rs +++ b/contracts/provider/external-staking/src/test_methods_impl.rs @@ -1,4 +1,4 @@ -use crate::contract::{custom, ExternalStakingContract}; +use crate::contract::ExternalStakingContract; use crate::error::ContractError; use crate::test_methods::TestMethods; @@ -13,11 +13,10 @@ use sylvia::types::ExecCtx; #[sv::messages(crate::test_methods as TestMethods)] impl TestMethods for ExternalStakingContract<'_> { type Error = ContractError; - type ExecC = custom::ExternalStakingMsg; /// Commits a pending stake. #[sv::msg(exec)] - fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { + fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(feature = "mt", test))] { let msg: cosmwasm_std::WasmMsg = self.commit_stake(ctx.deps, tx_id)?; @@ -32,7 +31,7 @@ impl TestMethods for ExternalStakingContract<'_> { /// Rollbacks a pending stake. #[sv::msg(exec)] - fn test_rollback_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { + fn test_rollback_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(test, feature = "mt"))] { let msg = self.rollback_stake(ctx.deps, tx_id)?; @@ -53,7 +52,7 @@ impl TestMethods for ExternalStakingContract<'_> { validator: AddValidator, height: u64, time: u64, - ) -> Result { + ) -> Result { #[cfg(any(feature = "mt", test))] { let AddValidator { valoper, pub_key } = validator; @@ -76,7 +75,7 @@ impl TestMethods for ExternalStakingContract<'_> { valoper: String, height: u64, time: u64, - ) -> Result { + ) -> Result { #[cfg(any(feature = "mt", test))] { self.val_set @@ -98,7 +97,7 @@ impl TestMethods for ExternalStakingContract<'_> { valoper: String, height: u64, time: u64, - ) -> Result { + ) -> Result { #[cfg(any(feature = "mt", test))] { self.val_set @@ -114,7 +113,7 @@ impl TestMethods for ExternalStakingContract<'_> { /// Commits a pending unstake. #[sv::msg(exec)] - fn test_commit_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result { + fn test_commit_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(test, feature = "mt"))] { self.commit_unstake(ctx.deps, ctx.env, tx_id)?; @@ -129,7 +128,7 @@ impl TestMethods for ExternalStakingContract<'_> { /// Rollbacks a pending unstake. #[sv::msg(exec)] - fn test_rollback_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result { + fn test_rollback_unstake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(test, feature = "mt"))] { self.rollback_unstake(ctx.deps, tx_id)?; @@ -149,7 +148,7 @@ impl TestMethods for ExternalStakingContract<'_> { ctx: ExecCtx, validator: String, rewards: Coin, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { let event = self.distribute_rewards(ctx.deps, &validator, rewards)?; @@ -169,7 +168,7 @@ impl TestMethods for ExternalStakingContract<'_> { ctx: ExecCtx, denom: String, rewards: Vec, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { let events = self.distribute_rewards_batch(ctx.deps, &rewards, &denom)?; @@ -188,7 +187,7 @@ impl TestMethods for ExternalStakingContract<'_> { &self, ctx: ExecCtx, tx_id: u64, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { self.commit_withdraw_rewards(ctx.deps, tx_id)?; @@ -207,7 +206,7 @@ impl TestMethods for ExternalStakingContract<'_> { &self, ctx: ExecCtx, tx_id: u64, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { self.rollback_withdraw_rewards(ctx.deps, tx_id)?; @@ -227,7 +226,7 @@ impl TestMethods for ExternalStakingContract<'_> { ctx: ExecCtx, validator: String, slash_amount: Uint128, - ) -> Result { + ) -> Result { #[cfg(any(test, feature = "mt"))] { let cfg = self.config.load(ctx.deps.storage)?; diff --git a/contracts/provider/native-staking-proxy/Cargo.toml b/contracts/provider/native-staking-proxy/Cargo.toml index a1883209..847aeaff 100644 --- a/contracts/provider/native-staking-proxy/Cargo.toml +++ b/contracts/provider/native-staking-proxy/Cargo.toml @@ -17,8 +17,6 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] -# enable this for multi-tests where you need custom messages for compatibility with vault -fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } diff --git a/contracts/provider/native-staking-proxy/src/contract.rs b/contracts/provider/native-staking-proxy/src/contract.rs index 8b4be2ee..89aa6240 100644 --- a/contracts/provider/native-staking-proxy/src/contract.rs +++ b/contracts/provider/native-staking-proxy/src/contract.rs @@ -23,24 +23,9 @@ pub struct NativeStakingProxyContract<'a> { burned: Item<'a, u128>, } -#[cfg(not(feature = "fake-custom"))] -pub mod custom { - pub type NativeStakingProxyMsg = cosmwasm_std::Empty; - pub type NativeStakingProxyQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; -} -#[cfg(feature = "fake-custom")] -pub mod custom { - pub type NativeStakingProxyMsg = mesh_bindings::VaultCustomMsg; - pub type NativeStakingProxyQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; -} - #[cfg_attr(not(feature = "library"), sylvia::entry_points)] #[contract] #[sv::error(ContractError)] -/// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::NativeStakingProxyMsg)] impl NativeStakingProxyContract<'_> { pub const fn new() -> Self { Self { @@ -58,7 +43,7 @@ impl NativeStakingProxyContract<'_> { denom: String, owner: String, validator: String, - ) -> Result { + ) -> Result { let config = Config { denom, parent: ctx.info.sender.clone(), @@ -91,7 +76,7 @@ impl NativeStakingProxyContract<'_> { /// Stakes the tokens from `info.funds` to the given validator. /// Can only be called by the parent contract #[sv::msg(exec)] - fn stake(&self, ctx: ExecCtx, validator: String) -> Result { + fn stake(&self, ctx: ExecCtx, validator: String) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.parent, ctx.info.sender, ContractError::Unauthorized {}); @@ -112,7 +97,7 @@ impl NativeStakingProxyContract<'_> { ctx: ExecCtx, validator: Option, amount: Coin, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.parent, ctx.info.sender, ContractError::Unauthorized {}); @@ -201,7 +186,7 @@ impl NativeStakingProxyContract<'_> { src_validator: String, dst_validator: String, amount: Coin, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -228,7 +213,7 @@ impl NativeStakingProxyContract<'_> { ctx: ExecCtx, proposal_id: u64, vote: VoteOption, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -245,7 +230,7 @@ impl NativeStakingProxyContract<'_> { ctx: ExecCtx, proposal_id: u64, vote: Vec, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -262,7 +247,7 @@ impl NativeStakingProxyContract<'_> { /// send the tokens to the caller. /// NOTE: must make sure not to release unbonded tokens #[sv::msg(exec)] - fn withdraw_rewards(&self, ctx: ExecCtx) -> Result { + fn withdraw_rewards(&self, ctx: ExecCtx) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -291,7 +276,7 @@ impl NativeStakingProxyContract<'_> { ctx: ExecCtx, validator: String, amount: Coin, - ) -> Result { + ) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); @@ -311,7 +296,7 @@ impl NativeStakingProxyContract<'_> { /// This will go back to the parent via `release_proxy_stake`. /// Errors if the proxy doesn't have any liquid tokens #[sv::msg(exec)] - fn release_unbonded(&self, ctx: ExecCtx) -> Result { + fn release_unbonded(&self, ctx: ExecCtx) -> Result { let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.owner, ctx.info.sender, ContractError::Unauthorized {}); diff --git a/contracts/provider/native-staking-proxy/src/multitest.rs b/contracts/provider/native-staking-proxy/src/multitest.rs index 90f5c6b2..0e170fdf 100644 --- a/contracts/provider/native-staking-proxy/src/multitest.rs +++ b/contracts/provider/native-staking-proxy/src/multitest.rs @@ -1,14 +1,14 @@ use anyhow::Result as AnyResult; use cosmwasm_std::testing::mock_env; -use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Empty, Validator}; +use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Validator}; -use cw_multi_test::{AppBuilder, StakingInfo}; +use cw_multi_test::{App as MtApp, AppBuilder, StakingInfo}; use sylvia::multitest::{App, Proxy}; -use mesh_vault::contract::sv::mt::VaultContractProxy; -use mesh_vault::contract::VaultContract; +use mesh_vault::mock::sv::mt::VaultMockProxy; +use mesh_vault::mock::VaultMock; use mesh_vault::msg::LocalStakingInfo; use crate::contract; @@ -19,12 +19,6 @@ use crate::msg::ConfigResponse; const OSMO: &str = "uosmo"; const UNBONDING_PERIOD: u64 = 17 * 24 * 60 * 60; // 7 days -// Trying to figure out how to work with the generic types -type MtApp = cw_multi_test::BasicApp< - mesh_bindings::VaultCustomMsg, - Empty, ->; - fn init_app(owner: &str, validators: &[&str]) -> App { // Fund the staking contract, and add validators to staking keeper let block = mock_env().block; @@ -66,8 +60,8 @@ fn setup<'app>( owner: &'app str, user: &str, validators: &[&str], -) -> AnyResult>> { - let vault_code = mesh_vault::contract::sv::mt::CodeId::store_code(app); +) -> AnyResult>> { + let vault_code = mesh_vault::mock::sv::mt::CodeId::store_code(app); let staking_code = mesh_native_staking::contract::sv::mt::CodeId::store_code(app); let staking_proxy_code = contract::sv::mt::CodeId::store_code(app); @@ -97,8 +91,8 @@ fn setup<'app>( // Bond some funds to the vault vault - .bond(coin(200, OSMO)) - .call(user) + .bond() + .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); // Stakes some of it locally. This instantiates the staking proxy contract for user diff --git a/contracts/provider/native-staking/Cargo.toml b/contracts/provider/native-staking/Cargo.toml index b50c6a77..40ecfb97 100644 --- a/contracts/provider/native-staking/Cargo.toml +++ b/contracts/provider/native-staking/Cargo.toml @@ -17,8 +17,6 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] -# enable this for multi-tests where you need custom messages for compatibility with vault -fake-custom = [ "mesh-vault/fake-custom" ] [dependencies] mesh-apis = { workspace = true } @@ -44,7 +42,7 @@ test-case = { workspace = true } derivative = { workspace = true } anyhow = { workspace = true } -mesh-vault = { workspace = true, features = ["mt", "fake-custom"] } +mesh-vault = { workspace = true, features = ["mt"] } [[bin]] name = "schema" diff --git a/contracts/provider/native-staking/src/contract.rs b/contracts/provider/native-staking/src/contract.rs index f11ea225..041ab945 100644 --- a/contracts/provider/native-staking/src/contract.rs +++ b/contracts/provider/native-staking/src/contract.rs @@ -78,7 +78,7 @@ impl NativeStakingContract<'_> { proxy_code_id: u64, slash_ratio_dsign: Decimal, slash_ratio_offline: Decimal, - ) -> Result { + ) -> Result { if slash_ratio_dsign > Decimal::one() || slash_ratio_offline > Decimal::one() { return Err(ContractError::InvalidSlashRatio); } @@ -103,7 +103,7 @@ impl NativeStakingContract<'_> { mut deps: DepsMut, jailed: Option>, tombstoned: Option>, - ) -> Result { + ) -> Result { let jailed = &jailed.unwrap_or_default(); let tombstoned = &tombstoned.unwrap_or_default(); @@ -197,7 +197,7 @@ impl NativeStakingContract<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -208,7 +208,7 @@ impl NativeStakingContract<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result { + ) -> Result { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; // Associate staking proxy with owner address @@ -258,7 +258,7 @@ impl NativeStakingContract<'_> { ctx: ExecCtx, jailed: Vec, tombstoned: Vec, - ) -> Result { + ) -> Result { #[cfg(any(feature = "mt", test))] { let jailed = if jailed.is_empty() { @@ -290,7 +290,7 @@ impl NativeStakingContract<'_> { ctx: SudoCtx, jailed: Option>, tombstoned: Option>, - ) -> Result { + ) -> Result { self.handle_jailing(ctx.deps, jailed, tombstoned) } } diff --git a/contracts/provider/native-staking/src/local_staking_api.rs b/contracts/provider/native-staking/src/local_staking_api.rs index f0288d22..98ff3ecb 100644 --- a/contracts/provider/native-staking/src/local_staking_api.rs +++ b/contracts/provider/native-staking/src/local_staking_api.rs @@ -23,7 +23,7 @@ impl LocalStakingApi for NativeStakingContract<'_> { ctx: ExecCtx, owner: String, msg: Binary, - ) -> Result { + ) -> Result { // Can only be called by the vault let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.vault.0, ctx.info.sender, ContractError::Unauthorized {}); @@ -89,7 +89,7 @@ impl LocalStakingApi for NativeStakingContract<'_> { owner: String, amount: Coin, validator: Option, - ) -> Result { + ) -> Result { // Can only be called by the vault let cfg = self.config.load(ctx.deps.storage)?; ensure_eq!(cfg.vault.0, ctx.info.sender, ContractError::Unauthorized {}); diff --git a/contracts/provider/native-staking/src/multitest.rs b/contracts/provider/native-staking/src/multitest.rs index cb4fd5ef..b1ba60f6 100644 --- a/contracts/provider/native-staking/src/multitest.rs +++ b/contracts/provider/native-staking/src/multitest.rs @@ -1,8 +1,8 @@ use cosmwasm_std::{ - coin, coins, to_json_binary, Addr, Decimal, Delegation, Empty, StdError, Uint128, Validator + coin, coins, to_json_binary, Addr, Decimal, Delegation, StdError, Uint128, Validator }; -use cw_multi_test::{no_init, AppBuilder, StakingInfo}; +use cw_multi_test::{App as MtApp, StakingInfo}; use sylvia::multitest::{App, Proxy}; use mesh_apis::local_staking_api::sv::mt::LocalStakingApiProxy; @@ -11,7 +11,7 @@ use mesh_native_staking_proxy::contract::sv::mt::{ }; use mesh_native_staking_proxy::contract::NativeStakingProxyContract; use mesh_sync::ValueRange; -use mesh_vault::contract::sv::mt::VaultContractProxy; +use mesh_vault::mock::sv::mt::VaultMockProxy; use mesh_vault::msg::LocalStakingInfo; use crate::contract; @@ -25,12 +25,6 @@ const OSMO: &str = "OSMO"; const SLASHING_PERCENTAGE_DSIGN: u64 = 15; const SLASHING_PERCENTAGE_OFFLINE: u64 = 10; -// Trying to figure out how to work with the generic types -type MtApp = cw_multi_test::BasicApp< - mesh_bindings::VaultCustomMsg, - Empty, ->; - fn slashing_rate_dsign() -> Decimal { Decimal::percent(SLASHING_PERCENTAGE_DSIGN) } @@ -40,7 +34,7 @@ fn slashing_rate_offline() -> Decimal { } fn app(balances: &[(&str, (u128, &str))], validators: &[&str]) -> App { - let mut mt_app = AppBuilder::new_custom().build(no_init); + let mut mt_app = MtApp::default(); let block_info = mt_app.block_info(); mt_app.init_modules(|router, api, storage| { @@ -262,7 +256,7 @@ fn releasing_proxy_stake() { let app = app(&[(user, (300, OSMO))], &[validator]); // Contracts setup - let vault_code = mesh_vault::contract::sv::mt::CodeId::store_code(&app); + let vault_code = mesh_vault::mock::sv::mt::CodeId::store_code(&app); let staking_code = contract::sv::mt::CodeId::store_code(&app); let staking_proxy_code = NativeStakingProxyCodeId::store_code(&app); @@ -302,8 +296,8 @@ fn releasing_proxy_stake() { // User bonds some funds to the vault vault - .bond(coin(200, OSMO)) - .call(user) + .bond() + .with_funds(&coins(200, OSMO)) .call(user) .unwrap(); // Vault has the funds diff --git a/contracts/provider/native-staking/src/native_staking_callback.rs b/contracts/provider/native-staking/src/native_staking_callback.rs index d2540f91..55221942 100644 --- a/contracts/provider/native-staking/src/native_staking_callback.rs +++ b/contracts/provider/native-staking/src/native_staking_callback.rs @@ -15,7 +15,7 @@ impl NativeStakingCallback for NativeStakingContract<'_> { /// This sends tokens back from the proxy to native-staking. (See info.funds) /// The native-staking contract can determine which user it belongs to via an internal Map. /// The native-staking contract will then send those tokens back to vault and release the claim. - fn release_proxy_stake(&self, ctx: ExecCtx) -> Result { + fn release_proxy_stake(&self, ctx: ExecCtx) -> Result { let cfg = self.config.load(ctx.deps.storage)?; // Assert funds are passed in diff --git a/contracts/provider/vault/Cargo.toml b/contracts/provider/vault/Cargo.toml index 64d7dd61..9969f529 100644 --- a/contracts/provider/vault/Cargo.toml +++ b/contracts/provider/vault/Cargo.toml @@ -17,8 +17,6 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] -# enable this for multi-tests where you need custom messages for compatibility with virtual staking -fake-custom = [] [dependencies] mesh-apis = { workspace = true } @@ -42,7 +40,7 @@ cw-multi-test = { workspace = true } test-case = { workspace = true } derivative = { workspace = true } anyhow = { workspace = true } -mesh-external-staking = { workspace = true, features = ["mt", "fake-custom"] } +mesh-external-staking = { workspace = true, features = ["mt"] } mesh-native-staking = { workspace = true, features = ["mt"] } mesh-native-staking-proxy = { workspace = true, features = ["mt"] } diff --git a/contracts/provider/vault/src/mock.rs b/contracts/provider/vault/src/mock.rs index fcd0af9f..ee6a9c12 100644 --- a/contracts/provider/vault/src/mock.rs +++ b/contracts/provider/vault/src/mock.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, StdResult, Storage, SubMsgResponse, Uint128, WasmMsg + coin, ensure, Addr, BankMsg, Binary, Coin, Decimal, DepsMut, Empty, Fraction, Order, Reply, Response, StdResult, Storage, SubMsgResponse, Uint128, WasmMsg }; use cw2::set_contract_version; use cw_storage_plus::{Bounder, Item, Map}; @@ -13,11 +13,13 @@ use mesh_apis::local_staking_api::{ use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; -use mesh_bindings::VaultCustomMsg; use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, ReplyCtx}; use sylvia::{contract, schemars}; +use crate::contract::{ + CONTRACT_NAME, CONTRACT_VERSION, DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT, REPLY_ID_INSTANTIATE, +}; use crate::error::ContractError; use crate::msg::{ AccountClaimsResponse, AccountDetailsResponse, AccountResponse, AllAccountsResponse, @@ -26,7 +28,6 @@ use crate::msg::{ }; use crate::state::{Config, Lien, LocalStaking, UserInfo}; use crate::txs::Txs; -use crate::contract::{CONTRACT_NAME, CONTRACT_VERSION, REPLY_ID_INSTANTIATE, DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT}; fn clamp_page_limit(limit: Option) -> usize { limit.unwrap_or(DEFAULT_PAGE_LIMIT).max(MAX_PAGE_LIMIT) as usize @@ -50,7 +51,6 @@ pub struct VaultMock<'a> { #[contract] #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] -#[sv::custom(msg=VaultCustomMsg)] impl VaultMock<'_> { pub fn new() -> Self { Self { @@ -76,7 +76,7 @@ impl VaultMock<'_> { ctx: InstantiateCtx, denom: String, local_staking: Option, - ) -> Result, ContractError> { + ) -> Result { nonpayable(&ctx.info)?; let config = Config { denom }; @@ -97,9 +97,7 @@ impl VaultMock<'_> { .save(ctx.deps.storage, &Some(local_staking))?; Ok(Response::new()) } - LocalStakingInfo::New(_) => { - Ok(Response::new()) - } + LocalStakingInfo::New(_) => Ok(Response::new()), } } else { self.local_staking.save(ctx.deps.storage, &None)?; @@ -108,27 +106,31 @@ impl VaultMock<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { - nonpayable(&ctx.info)?; - + fn bond(&self, ctx: ExecCtx) -> Result { let denom = self.config.load(ctx.deps.storage)?.denom; - ensure!(denom == amount.denom, ContractError::UnexpectedDenom(denom)); + let amount = must_pay(&ctx.info, &denom)?; let mut user = self .users .may_load(ctx.deps.storage, &ctx.info.sender)? .unwrap_or_default(); - user.collateral += amount.amount; + user.collateral += amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; - Ok(Response::new()) + let resp = Response::new() + .add_attribute("action", "bond") + .add_attribute("sender", ctx.info.sender) + .add_attribute("amount", amount.to_string()); + + Ok(resp) } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; + ensure!(denom == amount.denom, ContractError::UnexpectedDenom(denom)); let mut user = self @@ -145,7 +147,18 @@ impl VaultMock<'_> { user.collateral -= amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; - Ok(Response::new()) + let msg = BankMsg::Send { + to_address: ctx.info.sender.to_string(), + amount: vec![amount.clone()], + }; + + let resp = Response::new() + .add_message(msg) + .add_attribute("action", "unbond") + .add_attribute("sender", ctx.info.sender) + .add_attribute("amount", amount.to_string()); + + Ok(resp) } #[sv::msg(exec)] @@ -158,7 +171,7 @@ impl VaultMock<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result, ContractError> { + ) -> Result { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -205,7 +218,7 @@ impl VaultMock<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result, ContractError> { + ) -> Result { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -439,7 +452,11 @@ impl VaultMock<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result, ContractError> { + fn reply( + &self, + ctx: ReplyCtx, + reply: Reply, + ) -> Result { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -450,7 +467,7 @@ impl VaultMock<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result, ContractError> { + ) -> Result { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; let local_staking = Addr::unchecked(init_data.contract_address); @@ -914,7 +931,7 @@ impl VaultMock<'_> { impl VaultApi for VaultMock<'_> { type Error = ContractError; - type ExecC = VaultCustomMsg; + type ExecC = Empty; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index fee3af88..31488c7d 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -1,5 +1,5 @@ -use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Empty, Uint128, Validator}; -use cw_multi_test::StakingInfo; +use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Uint128, Validator}; +use cw_multi_test::{App as MtApp, StakingInfo}; use mesh_apis::ibc::AddValidator; use mesh_external_staking::contract::sv::mt::ExternalStakingContractProxy; use mesh_external_staking::contract::ExternalStakingContract; @@ -32,14 +32,6 @@ const STAR: &str = "star"; /// 10% slashing on the remote chain const SLASHING_PERCENTAGE: u64 = 10; -// Trying to figure out how to work with the generic types -type MtApp = cw_multi_test::BasicApp< - mesh_bindings::VaultCustomMsg, - Empty, ->; - -/// Test utils - /// App initialization fn init_app(users: &[&str], amounts: &[u128]) -> App { let app = App::custom(|router, _api, storage| { @@ -213,7 +205,7 @@ fn set_active_validators( /// Bond some tokens fn bond(vault: &Proxy<'_, MtApp, VaultMock<'_>>, user: &str, amount: u128) { - vault.bond(coin(amount, OSMO)).call(user).unwrap(); + vault.bond().with_funds(&coins(amount, OSMO)).call(user).unwrap(); } fn stake_locally( diff --git a/packages/apis/src/cross_staking_api.rs b/packages/apis/src/cross_staking_api.rs index 84b6b1d7..f83e0dac 100644 --- a/packages/apis/src/cross_staking_api.rs +++ b/packages/apis/src/cross_staking_api.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, CustomMsg, Deps, Response, StdError, WasmMsg}; +use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, Deps, Response, StdError, WasmMsg}; use sylvia::types::{ExecCtx, QueryCtx}; use sylvia::{interface, schemars}; @@ -14,7 +14,6 @@ pub use crate::local_staking_api::SlashRatioResponse; #[interface] pub trait CrossStakingApi { type Error: From; - type ExecC: CustomMsg; /// Receives stake from vault contract on behalf of owner and performs the action /// specified in msg with it. @@ -27,7 +26,7 @@ pub trait CrossStakingApi { amount: Coin, tx_id: u64, msg: Binary, - ) -> Result, Self::Error>; + ) -> Result; /// Burns stake. This is called when the user's collateral is slashed and, as part of slashing /// propagation, the virtual staking contract needs to burn / discount the indicated slashing amount. @@ -42,7 +41,7 @@ pub trait CrossStakingApi { owner: String, amount: Coin, validator: Option, - ) -> Result, Self::Error>; + ) -> Result; /// Returns the maximum percentage that can be slashed #[sv::msg(query)] From 942da1a38834530d715195f7a731367b5ee812c3 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Tue, 9 Jul 2024 14:02:26 +0700 Subject: [PATCH 25/29] remove unused code --- Cargo.lock | 3 -- .../provider/external-staking/Cargo.toml | 2 - .../external-staking/src/multitest.rs | 47 ++++++++++++------- .../external-staking/src/multitest/utils.rs | 4 +- .../external-staking/src/test_methods_impl.rs | 2 +- .../provider/native-staking-proxy/Cargo.toml | 1 - .../native-staking-proxy/src/multitest.rs | 8 ++-- .../src/native_staking_callback.rs | 5 +- contracts/provider/native-staking/Cargo.toml | 1 - .../provider/native-staking/src/contract.rs | 15 ------ .../native-staking/src/local_staking_api.rs | 3 +- .../provider/native-staking/src/multitest.rs | 5 +- .../src/native_staking_callback.rs | 3 +- contracts/provider/vault/src/multitest.rs | 12 +++-- packages/apis/src/local_staking_api.rs | 7 ++- 15 files changed, 56 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 278c0118..b2f0dab3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -629,7 +629,6 @@ dependencies = [ "cw-utils", "cw2", "mesh-apis", - "mesh-bindings", "mesh-burn", "mesh-native-staking", "mesh-native-staking-proxy", @@ -654,7 +653,6 @@ dependencies = [ "cw2", "derivative", "mesh-apis", - "mesh-bindings", "mesh-native-staking-proxy", "mesh-sync", "mesh-vault", @@ -678,7 +676,6 @@ dependencies = [ "cw2", "derivative", "mesh-apis", - "mesh-bindings", "mesh-burn", "mesh-native-staking", "mesh-vault", diff --git a/contracts/provider/external-staking/Cargo.toml b/contracts/provider/external-staking/Cargo.toml index ea675650..1056ac3c 100644 --- a/contracts/provider/external-staking/Cargo.toml +++ b/contracts/provider/external-staking/Cargo.toml @@ -16,11 +16,9 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] # enables generation of mt utilities mt = ["library", "sylvia/mt"] -# enable this for multi-tests where you need custom messages for compatibility with vault [dependencies] mesh-apis = { workspace = true } -mesh-bindings = { workspace = true } mesh-burn = { workspace = true } mesh-sync = { workspace = true } diff --git a/contracts/provider/external-staking/src/multitest.rs b/contracts/provider/external-staking/src/multitest.rs index cbbde1cc..ed8298a2 100644 --- a/contracts/provider/external-staking/src/multitest.rs +++ b/contracts/provider/external-staking/src/multitest.rs @@ -93,7 +93,7 @@ fn setup<'app>( #[test] fn instantiate() { - let app = App::default(); + let app = App::default(); let owner = "owner"; let users = ["user1"]; @@ -232,12 +232,14 @@ fn unstaking() { vault .bond() - .with_funds(&coins(300, OSMO)) .call(users[0]) + .with_funds(&coins(300, OSMO)) + .call(users[0]) .unwrap(); vault .bond() - .with_funds(&coins(300, OSMO)) .call(users[1]) + .with_funds(&coins(300, OSMO)) + .call(users[1]) .unwrap(); vault.stake(&contract, users[0], validators[0], coin(200, OSMO)); @@ -472,7 +474,8 @@ fn immediate_unstake_if_unbonded_validator() { vault .bond() - .with_funds(&coins(200, OSMO)) .call(user) + .with_funds(&coins(200, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -510,7 +513,8 @@ fn immediate_unstake_if_tombstoned_validator() { vault .bond() - .with_funds(&coins(200, OSMO)) .call(user) + .with_funds(&coins(200, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -556,12 +560,14 @@ fn distribution() { // all of validators[1] to users[1] vault .bond() - .with_funds(&coins(600, OSMO)) .call(users[0]) + .with_funds(&coins(600, OSMO)) + .call(users[0]) .unwrap(); vault .bond() - .with_funds(&coins(600, OSMO)) .call(users[1]) + .with_funds(&coins(600, OSMO)) + .call(users[1]) .unwrap(); vault.stake(&contract, users[0], validators[0], coin(200, OSMO)); @@ -1158,11 +1164,13 @@ fn batch_distribution() { vault .bond() - .with_funds(&coins(600, OSMO)) .call(users[0]) + .with_funds(&coins(600, OSMO)) + .call(users[0]) .unwrap(); vault .bond() - .with_funds(&coins(600, OSMO)) .call(users[1]) + .with_funds(&coins(600, OSMO)) + .call(users[1]) .unwrap(); vault.stake(&contract, users[0], validators[0], coin(200, OSMO)); @@ -1201,7 +1209,8 @@ fn batch_distribution_invalid_token() { vault .bond() - .with_funds(&coins(600, OSMO)) .call(user) + .with_funds(&coins(600, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validator, coin(200, OSMO)); @@ -1226,7 +1235,8 @@ fn slashing() { vault .bond() - .with_funds(&coins(300, OSMO)) .call(user) + .with_funds(&coins(300, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1370,7 +1380,8 @@ fn slashing_pending_tx_partial_unbond() { vault .bond() - .with_funds(&coins(300, OSMO)) .call(user) + .with_funds(&coins(300, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1456,7 +1467,8 @@ fn slashing_pending_tx_full_unbond() { vault .bond() - .with_funds(&coins(200, OSMO)) .call(user) + .with_funds(&coins(200, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1538,7 +1550,8 @@ fn slashing_pending_tx_full_unbond_rolled_back() { vault .bond() - .with_funds(&coins(200, OSMO)) .call(user) + .with_funds(&coins(200, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1618,7 +1631,8 @@ fn slashing_pending_tx_bond() { vault .bond() - .with_funds(&coins(300, OSMO)) .call(user) + .with_funds(&coins(300, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); @@ -1702,7 +1716,8 @@ fn slashing_pending_tx_bond_rolled_back() { vault .bond() - .with_funds(&coins(300, OSMO)) .call(user) + .with_funds(&coins(300, OSMO)) + .call(user) .unwrap(); vault.stake(&contract, user, validators[0], coin(200, OSMO)); diff --git a/contracts/provider/external-staking/src/multitest/utils.rs b/contracts/provider/external-staking/src/multitest/utils.rs index 5dd93860..1b7d52a4 100644 --- a/contracts/provider/external-staking/src/multitest/utils.rs +++ b/contracts/provider/external-staking/src/multitest/utils.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{to_json_binary, Addr, Coin}; -use cw_multi_test::{App as MtApp, AppBuilder, AppResponse}; +use cw_multi_test::{App as MtApp, AppResponse}; use mesh_apis::{converter_api::RewardInfo, ibc::AddValidator}; use mesh_sync::Tx; use mesh_vault::mock::{sv::mt::VaultMockProxy, VaultMock}; @@ -48,7 +48,7 @@ impl AppExt for App { #[track_caller] fn new_with_balances(balances: &[(&str, &[Coin])]) -> Self { - let app =AppBuilder::new_custom().build(|router, _api, storage| { + let app =MtApp::new(|router, _api, storage| { for (addr, coins) in balances { router .bank diff --git a/contracts/provider/external-staking/src/test_methods_impl.rs b/contracts/provider/external-staking/src/test_methods_impl.rs index 498b671d..c63927c1 100644 --- a/contracts/provider/external-staking/src/test_methods_impl.rs +++ b/contracts/provider/external-staking/src/test_methods_impl.rs @@ -19,7 +19,7 @@ impl TestMethods for ExternalStakingContract<'_> { fn test_commit_stake(&self, ctx: ExecCtx, tx_id: u64) -> Result { #[cfg(any(feature = "mt", test))] { - let msg: cosmwasm_std::WasmMsg = self.commit_stake(ctx.deps, tx_id)?; + let msg = self.commit_stake(ctx.deps, tx_id)?; Ok(Response::new().add_message(msg)) } #[cfg(not(any(feature = "mt", test)))] diff --git a/contracts/provider/native-staking-proxy/Cargo.toml b/contracts/provider/native-staking-proxy/Cargo.toml index 847aeaff..a8210310 100644 --- a/contracts/provider/native-staking-proxy/Cargo.toml +++ b/contracts/provider/native-staking-proxy/Cargo.toml @@ -20,7 +20,6 @@ mt = ["library", "sylvia/mt"] [dependencies] mesh-apis = { workspace = true } -mesh-bindings = { workspace = true } mesh-burn = { workspace = true } sylvia = { workspace = true } diff --git a/contracts/provider/native-staking-proxy/src/multitest.rs b/contracts/provider/native-staking-proxy/src/multitest.rs index 0e170fdf..90baa916 100644 --- a/contracts/provider/native-staking-proxy/src/multitest.rs +++ b/contracts/provider/native-staking-proxy/src/multitest.rs @@ -3,8 +3,7 @@ use anyhow::Result as AnyResult; use cosmwasm_std::testing::mock_env; use cosmwasm_std::{coin, coins, to_json_binary, Addr, Decimal, Validator}; -use cw_multi_test::{App as MtApp, AppBuilder, StakingInfo}; - +use cw_multi_test::{App as MtApp, StakingInfo}; use sylvia::multitest::{App, Proxy}; use mesh_vault::mock::sv::mt::VaultMockProxy; @@ -22,7 +21,7 @@ const UNBONDING_PERIOD: u64 = 17 * 24 * 60 * 60; // 7 days fn init_app(owner: &str, validators: &[&str]) -> App { // Fund the staking contract, and add validators to staking keeper let block = mock_env().block; - let app = AppBuilder::new_custom().build(|router, api, storage| { + let app = MtApp::new(|router, api, storage| { router .bank .init_balance(storage, &Addr::unchecked(owner), coins(1000, OSMO)) @@ -92,7 +91,8 @@ fn setup<'app>( // Bond some funds to the vault vault .bond() - .with_funds(&coins(200, OSMO)) .call(user) + .with_funds(&coins(200, OSMO)) + .call(user) .unwrap(); // Stakes some of it locally. This instantiates the staking proxy contract for user diff --git a/contracts/provider/native-staking-proxy/src/native_staking_callback.rs b/contracts/provider/native-staking-proxy/src/native_staking_callback.rs index eba66596..7ff4e016 100644 --- a/contracts/provider/native-staking-proxy/src/native_staking_callback.rs +++ b/contracts/provider/native-staking-proxy/src/native_staking_callback.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{CustomMsg, Response, StdError}; +use cosmwasm_std::{Response, StdError}; use sylvia::types::ExecCtx; use sylvia::{interface, schemars}; @@ -6,11 +6,10 @@ use sylvia::{interface, schemars}; #[interface] pub trait NativeStakingCallback { type Error: From; - type ExecC: CustomMsg; /// This sends tokens back from the proxy to native-staking. (See info.funds) /// The native-staking contract can determine which user it belongs to via an internal Map. /// The native-staking contract will then send those tokens back to vault and release the claim. #[sv::msg(exec)] - fn release_proxy_stake(&self, _ctx: ExecCtx) -> Result, Self::Error>; + fn release_proxy_stake(&self, _ctx: ExecCtx) -> Result; } diff --git a/contracts/provider/native-staking/Cargo.toml b/contracts/provider/native-staking/Cargo.toml index 40ecfb97..1b508ffd 100644 --- a/contracts/provider/native-staking/Cargo.toml +++ b/contracts/provider/native-staking/Cargo.toml @@ -20,7 +20,6 @@ mt = ["library", "sylvia/mt"] [dependencies] mesh-apis = { workspace = true } -mesh-bindings = { workspace = true } mesh-sync = { workspace = true } mesh-native-staking-proxy = { workspace = true, features = ["library"] } diff --git a/contracts/provider/native-staking/src/contract.rs b/contracts/provider/native-staking/src/contract.rs index 041ab945..dd0a17dd 100644 --- a/contracts/provider/native-staking/src/contract.rs +++ b/contracts/provider/native-staking/src/contract.rs @@ -23,19 +23,6 @@ pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const REPLY_ID_INSTANTIATE: u64 = 2; -#[cfg(not(feature = "fake-custom"))] -pub mod custom { - pub type NativeStakingMsg = cosmwasm_std::Empty; - pub type NativeStakingQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; -} -#[cfg(feature = "fake-custom")] -pub mod custom { - pub type NativeStakingMsg = mesh_bindings::VaultCustomMsg; - pub type NativeStakingQuery = cosmwasm_std::Empty; - pub type Response = cosmwasm_std::Response; -} - pub struct NativeStakingContract<'a> { pub config: Item<'a, Config>, /// Map of proxy contract address by owner address @@ -57,8 +44,6 @@ pub(crate) enum SlashingReason { #[sv::error(ContractError)] #[sv::messages(local_staking_api as LocalStakingApi)] #[sv::messages(native_staking_callback as NativeStakingCallback)] -/// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=custom::NativeStakingMsg)] impl NativeStakingContract<'_> { pub const fn new() -> Self { Self { diff --git a/contracts/provider/native-staking/src/local_staking_api.rs b/contracts/provider/native-staking/src/local_staking_api.rs index 98ff3ecb..292f68a0 100644 --- a/contracts/provider/native-staking/src/local_staking_api.rs +++ b/contracts/provider/native-staking/src/local_staking_api.rs @@ -5,7 +5,7 @@ use sylvia::types::{ExecCtx, QueryCtx}; #[allow(unused_imports)] use mesh_apis::local_staking_api::{self, LocalStakingApi, SlashRatioResponse}; -use crate::contract::{custom, NativeStakingContract, REPLY_ID_INSTANTIATE}; +use crate::contract::{NativeStakingContract, REPLY_ID_INSTANTIATE}; use crate::error::ContractError; use crate::msg::StakeMsg; @@ -13,7 +13,6 @@ use crate::state::Config; impl LocalStakingApi for NativeStakingContract<'_> { type Error = ContractError; - type ExecC = custom::NativeStakingMsg; /// Receives stake (info.funds) from vault contract on behalf of owner and performs the action /// specified in msg with it. diff --git a/contracts/provider/native-staking/src/multitest.rs b/contracts/provider/native-staking/src/multitest.rs index b1ba60f6..fde0c43a 100644 --- a/contracts/provider/native-staking/src/multitest.rs +++ b/contracts/provider/native-staking/src/multitest.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - coin, coins, to_json_binary, Addr, Decimal, Delegation, StdError, Uint128, Validator + coin, coins, to_json_binary, Addr, Decimal, Delegation, StdError, Uint128, Validator, }; use cw_multi_test::{App as MtApp, StakingInfo}; @@ -297,7 +297,8 @@ fn releasing_proxy_stake() { // User bonds some funds to the vault vault .bond() - .with_funds(&coins(200, OSMO)) .call(user) + .with_funds(&coins(200, OSMO)) + .call(user) .unwrap(); // Vault has the funds diff --git a/contracts/provider/native-staking/src/native_staking_callback.rs b/contracts/provider/native-staking/src/native_staking_callback.rs index 55221942..fbfe4a35 100644 --- a/contracts/provider/native-staking/src/native_staking_callback.rs +++ b/contracts/provider/native-staking/src/native_staking_callback.rs @@ -5,12 +5,11 @@ use sylvia::types::ExecCtx; #[allow(unused_imports)] use mesh_native_staking_proxy::native_staking_callback::{self, NativeStakingCallback}; -use crate::contract::{custom, NativeStakingContract}; +use crate::contract::NativeStakingContract; use crate::error::ContractError; impl NativeStakingCallback for NativeStakingContract<'_> { type Error = ContractError; - type ExecC = custom::NativeStakingMsg; /// This sends tokens back from the proxy to native-staking. (See info.funds) /// The native-staking contract can determine which user it belongs to via an internal Map. diff --git a/contracts/provider/vault/src/multitest.rs b/contracts/provider/vault/src/multitest.rs index 31488c7d..9e8b897a 100644 --- a/contracts/provider/vault/src/multitest.rs +++ b/contracts/provider/vault/src/multitest.rs @@ -18,13 +18,13 @@ use mesh_apis::vault_api::sv::mt::VaultApiProxy; use mesh_external_staking::test_methods::sv::mt::TestMethodsProxy; use crate::error::ContractError; +use crate::mock::sv::mt::CodeId as VaultCodeId; +use crate::mock::sv::mt::VaultMockProxy; +use crate::mock::VaultMock; use crate::msg::{ AccountResponse, AllAccountsResponseItem, AllActiveExternalStakingResponse, LienResponse, LocalStakingInfo, StakingInitInfo, }; -use crate::mock::VaultMock; -use crate::mock::sv::mt::VaultMockProxy; -use crate::mock::sv::mt::CodeId as VaultCodeId; const OSMO: &str = "OSMO"; const STAR: &str = "star"; @@ -205,7 +205,11 @@ fn set_active_validators( /// Bond some tokens fn bond(vault: &Proxy<'_, MtApp, VaultMock<'_>>, user: &str, amount: u128) { - vault.bond().with_funds(&coins(amount, OSMO)).call(user).unwrap(); + vault + .bond() + .with_funds(&coins(amount, OSMO)) + .call(user) + .unwrap(); } fn stake_locally( diff --git a/packages/apis/src/local_staking_api.rs b/packages/apis/src/local_staking_api.rs index 6edb27bc..c319d894 100644 --- a/packages/apis/src/local_staking_api.rs +++ b/packages/apis/src/local_staking_api.rs @@ -1,6 +1,6 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - to_json_binary, Addr, Binary, Coin, CustomMsg, Decimal, Deps, Response, StdError, WasmMsg, + to_json_binary, Addr, Binary, Coin, Decimal, Deps, Response, StdError, WasmMsg, }; use sylvia::types::{ExecCtx, QueryCtx}; use sylvia::{interface, schemars}; @@ -16,7 +16,6 @@ pub struct SlashRatioResponse { #[interface] pub trait LocalStakingApi { type Error: From; - type ExecC: CustomMsg; /// Receives stake (info.funds) from vault contract on behalf of owner and performs the action /// specified in msg with it. @@ -32,7 +31,7 @@ pub trait LocalStakingApi { // // Basically, it allows iterations on various staking designs without touching Vault msg: Binary, - ) -> Result, Self::Error>; + ) -> Result; /// Burns stake. This is called when the user's collateral is slashed and, as part of slashing /// propagation, the native staking contract needs to burn / discount the indicated slashing amount. @@ -45,7 +44,7 @@ pub trait LocalStakingApi { owner: String, amount: Coin, validator: Option, - ) -> Result, Self::Error>; + ) -> Result; /// Returns the maximum percentage that can be slashed #[sv::msg(query)] From 543850b73eb6359454250b4785cd65db7224ef35 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Tue, 9 Jul 2024 14:08:54 +0700 Subject: [PATCH 26/29] revert mock to origin contract --- .../src/native_staking_callback.rs | 2 +- .../provider/native-staking/src/contract.rs | 3 +- contracts/provider/vault/src/mock.rs | 39 ++++++++++++++----- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/contracts/provider/native-staking-proxy/src/native_staking_callback.rs b/contracts/provider/native-staking-proxy/src/native_staking_callback.rs index 7ff4e016..53dc0241 100644 --- a/contracts/provider/native-staking-proxy/src/native_staking_callback.rs +++ b/contracts/provider/native-staking-proxy/src/native_staking_callback.rs @@ -6,7 +6,7 @@ use sylvia::{interface, schemars}; #[interface] pub trait NativeStakingCallback { type Error: From; - + /// This sends tokens back from the proxy to native-staking. (See info.funds) /// The native-staking contract can determine which user it belongs to via an internal Map. /// The native-staking contract will then send those tokens back to vault and release the claim. diff --git a/contracts/provider/native-staking/src/contract.rs b/contracts/provider/native-staking/src/contract.rs index dd0a17dd..08ac3d95 100644 --- a/contracts/provider/native-staking/src/contract.rs +++ b/contracts/provider/native-staking/src/contract.rs @@ -1,7 +1,6 @@ use cosmwasm_std::Order::Ascending; use cosmwasm_std::{ - from_json, Addr, Decimal, DepsMut, Event, Reply, Response, - StdResult, SubMsgResponse, WasmMsg, + from_json, Addr, Decimal, DepsMut, Event, Reply, Response, StdResult, SubMsgResponse, WasmMsg, }; use cw2::set_contract_version; use cw_storage_plus::{Item, Map}; diff --git a/contracts/provider/vault/src/mock.rs b/contracts/provider/vault/src/mock.rs index ee6a9c12..6ac06ecf 100644 --- a/contracts/provider/vault/src/mock.rs +++ b/contracts/provider/vault/src/mock.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - coin, ensure, Addr, BankMsg, Binary, Coin, Decimal, DepsMut, Empty, Fraction, Order, Reply, Response, StdResult, Storage, SubMsgResponse, Uint128, WasmMsg + coin, ensure, Addr, BankMsg, Binary, Coin, Decimal, DepsMut, Empty, Fraction, Order, Reply, Response, StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg }; use cw2::set_contract_version; use cw_storage_plus::{Bounder, Item, Map}; @@ -13,7 +13,6 @@ use mesh_apis::local_staking_api::{ use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; - use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, ReplyCtx}; use sylvia::{contract, schemars}; @@ -48,6 +47,7 @@ pub struct VaultMock<'a> { pub pending: Txs<'a>, } +#[cfg_attr(not(feature = "library"), sylvia::entry_points)] #[contract] #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] @@ -88,16 +88,34 @@ impl VaultMock<'_> { LocalStakingInfo::Existing(exist) => { let addr = exist.existing; + // Query for max slashing percentage + let query = LocalStakingApiQueryMsg::MaxSlash {}; + let SlashRatioResponse { + slash_ratio_dsign, .. + } = ctx.deps.querier.query_wasm_smart(&addr, &query)?; + let local_staking = LocalStaking { contract: LocalStakingApiHelper(ctx.deps.api.addr_validate(&addr)?), - max_slash: Decimal::percent(10), + max_slash: slash_ratio_dsign, }; self.local_staking .save(ctx.deps.storage, &Some(local_staking))?; Ok(Response::new()) } - LocalStakingInfo::New(_) => Ok(Response::new()), + LocalStakingInfo::New(local_staking) => { + let msg = WasmMsg::Instantiate { + admin: local_staking.admin, + code_id: local_staking.code_id, + msg: local_staking.msg, + funds: vec![], + label: local_staking + .label + .unwrap_or_else(|| "Mesh Security Local Staking".to_string()), + }; + let sub_msg = SubMsg::reply_on_success(msg, REPLY_ID_INSTANTIATE); + Ok(Response::new().add_submessage(sub_msg)) + } } } else { self.local_staking.save(ctx.deps.storage, &None)?; @@ -161,6 +179,7 @@ impl VaultMock<'_> { Ok(resp) } + /// This assigns a claim of amount tokens to the remote contract, which can take some action with it #[sv::msg(exec)] fn stake_remote( &self, @@ -452,11 +471,7 @@ impl VaultMock<'_> { } #[sv::msg(reply)] - fn reply( - &self, - ctx: ReplyCtx, - reply: Reply, - ) -> Result { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -929,6 +944,12 @@ impl VaultMock<'_> { } } +impl Default for VaultMock<'_> { + fn default() -> Self { + Self::new() + } +} + impl VaultApi for VaultMock<'_> { type Error = ContractError; type ExecC = Empty; From b34450ae9c09bcf2dadae50afe50467a3cf427dc Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Thu, 11 Jul 2024 21:48:00 +0700 Subject: [PATCH 27/29] change custom message name --- contracts/provider/vault/src/contract.rs | 24 ++++++++++++------------ packages/bindings/src/lib.rs | 2 +- packages/bindings/src/msg.rs | 24 ++++++++++++------------ 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 0dacce4e..3138e37a 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -11,7 +11,7 @@ use mesh_apis::local_staking_api::{ sv::LocalStakingApiQueryMsg, LocalStakingApiHelper, SlashRatioResponse, }; use mesh_apis::vault_api::{self, SlashInfo, VaultApi}; -use mesh_bindings::{VaultCustomMsg, VaultMsg}; +use mesh_bindings::{ProviderCustomMsg, ProviderMsg}; use mesh_sync::Tx::InFlightStaking; use mesh_sync::{max_range, ValueRange}; @@ -68,7 +68,7 @@ pub struct VaultContract<'a> { #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] /// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts. -#[sv::custom(msg=VaultCustomMsg)] +#[sv::custom(msg=ProviderCustomMsg)] impl VaultContract<'_> { pub fn new() -> Self { Self { @@ -94,7 +94,7 @@ impl VaultContract<'_> { ctx: InstantiateCtx, denom: String, local_staking: Option, - ) -> Result, ContractError> { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = Config { denom }; @@ -143,7 +143,7 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { + fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -156,7 +156,7 @@ impl VaultContract<'_> { user.collateral += amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let msg = VaultMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}; + let msg = ProviderMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}; let resp = Response::new() .add_message(msg) .add_attribute("action", "unbond") @@ -167,7 +167,7 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { + fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -187,7 +187,7 @@ impl VaultContract<'_> { user.collateral -= amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let msg = VaultMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}; + let msg = ProviderMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}; let resp = Response::new() .add_message(msg) .add_attribute("action", "unbond") @@ -208,7 +208,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result, ContractError> { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -255,7 +255,7 @@ impl VaultContract<'_> { amount: Coin, // action to take with that stake msg: Binary, - ) -> Result, ContractError> { + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let config = self.config.load(ctx.deps.storage)?; @@ -492,7 +492,7 @@ impl VaultContract<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result, ContractError> { + fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result, ContractError> { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -503,7 +503,7 @@ impl VaultContract<'_> { &self, deps: DepsMut, reply: SubMsgResponse, - ) -> Result, ContractError> { + ) -> Result, ContractError> { let init_data = parse_instantiate_response_data(&reply.data.unwrap())?; let local_staking = Addr::unchecked(init_data.contract_address); @@ -983,7 +983,7 @@ impl Default for VaultContract<'_> { impl VaultApi for VaultContract<'_> { type Error = ContractError; - type ExecC = VaultCustomMsg; + type ExecC = ProviderCustomMsg; /// This must be called by the remote staking contract to release this claim fn release_cross_stake( diff --git a/packages/bindings/src/lib.rs b/packages/bindings/src/lib.rs index 4005a29c..880e1b16 100644 --- a/packages/bindings/src/lib.rs +++ b/packages/bindings/src/lib.rs @@ -1,7 +1,7 @@ mod msg; mod query; -pub use msg::{VirtualStakeCustomMsg, VirtualStakeMsg, VaultCustomMsg, VaultMsg}; +pub use msg::{VirtualStakeCustomMsg, VirtualStakeMsg, ProviderCustomMsg, ProviderMsg}; pub use query::{ BondStatusResponse, SlashRatioResponse, TokenQuerier, VirtualStakeCustomQuery, VirtualStakeQuery, diff --git a/packages/bindings/src/msg.rs b/packages/bindings/src/msg.rs index e4d3b8ba..70e94ffe 100644 --- a/packages/bindings/src/msg.rs +++ b/packages/bindings/src/msg.rs @@ -68,13 +68,13 @@ impl CustomMsg for VirtualStakeCustomMsg {} /// It is embedded like this to easily allow adding other variants that are custom /// to your chain, or other "standardized" extensions along side it. #[cw_serde] -pub enum VaultCustomMsg { - Vault(VaultMsg), +pub enum ProviderCustomMsg { + Provider(ProviderMsg), } /// Special messages to be supported by any chain that supports meshsecurityprovider #[cw_serde] -pub enum VaultMsg { +pub enum ProviderMsg { /// Bond will enforce the calling contract is the vault contract. /// It ensures amount.denom is the native staking denom. /// @@ -89,34 +89,34 @@ pub enum VaultMsg { Unbond { delegator: String, amount: Coin }, } -impl VaultMsg { - pub fn bond(denom: &str, delegator: &str, amount: impl Into) -> VaultMsg { +impl ProviderMsg { + pub fn bond(denom: &str, delegator: &str, amount: impl Into) -> ProviderMsg { let coin = Coin { amount: amount.into(), denom: denom.into(), }; - VaultMsg::Bond { + ProviderMsg::Bond { delegator: delegator.to_string(), amount: coin, } } - pub fn unbond(denom: &str, delegator: &str, amount: impl Into) -> VaultMsg { + pub fn unbond(denom: &str, delegator: &str, amount: impl Into) -> ProviderMsg { let coin = Coin { amount: amount.into(), denom: denom.into(), }; - VaultMsg::Unbond { + ProviderMsg::Unbond { delegator: delegator.to_string(), amount: coin, } } } -impl From for CosmosMsg { - fn from(msg: VaultMsg) -> CosmosMsg { - CosmosMsg::Custom(VaultCustomMsg::Vault(msg)) +impl From for CosmosMsg { + fn from(msg: ProviderMsg) -> CosmosMsg { + CosmosMsg::Custom(ProviderCustomMsg::Provider(msg)) } } -impl CustomMsg for VaultCustomMsg {} +impl CustomMsg for ProviderCustomMsg {} From 34284a38601ff132e8d7b5594a87794faa71bbed Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Mon, 15 Jul 2024 12:09:39 +0700 Subject: [PATCH 28/29] fix build error --- contracts/provider/vault/src/mock.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/provider/vault/src/mock.rs b/contracts/provider/vault/src/mock.rs index 6ac06ecf..82235b7b 100644 --- a/contracts/provider/vault/src/mock.rs +++ b/contracts/provider/vault/src/mock.rs @@ -47,7 +47,6 @@ pub struct VaultMock<'a> { pub pending: Txs<'a>, } -#[cfg_attr(not(feature = "library"), sylvia::entry_points)] #[contract] #[sv::error(ContractError)] #[sv::messages(vault_api as VaultApi)] From ad46461795cc3ba6b87ce0bc062cbab477edaa71 Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Mon, 29 Jul 2024 10:14:48 +0700 Subject: [PATCH 29/29] lint the code --- .../external-staking/src/multitest/utils.rs | 3 +- .../src/native_staking_callback.rs | 2 +- contracts/provider/vault/src/contract.rs | 43 +++++++++++++++---- contracts/provider/vault/src/lib.rs | 2 +- contracts/provider/vault/src/mock.rs | 3 +- packages/apis/src/vault_api.rs | 2 +- packages/bindings/src/lib.rs | 2 +- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/contracts/provider/external-staking/src/multitest/utils.rs b/contracts/provider/external-staking/src/multitest/utils.rs index 1b7d52a4..7d9a8e3b 100644 --- a/contracts/provider/external-staking/src/multitest/utils.rs +++ b/contracts/provider/external-staking/src/multitest/utils.rs @@ -47,8 +47,7 @@ pub(crate) trait AppExt { impl AppExt for App { #[track_caller] fn new_with_balances(balances: &[(&str, &[Coin])]) -> Self { - - let app =MtApp::new(|router, _api, storage| { + let app = MtApp::new(|router, _api, storage| { for (addr, coins) in balances { router .bank diff --git a/contracts/provider/native-staking/src/native_staking_callback.rs b/contracts/provider/native-staking/src/native_staking_callback.rs index fbfe4a35..4996296f 100644 --- a/contracts/provider/native-staking/src/native_staking_callback.rs +++ b/contracts/provider/native-staking/src/native_staking_callback.rs @@ -33,4 +33,4 @@ impl NativeStakingCallback for NativeStakingContract<'_> { Ok(Response::new().add_message(msg)) } -} \ No newline at end of file +} diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 3138e37a..cf415057 100644 --- a/contracts/provider/vault/src/contract.rs +++ b/contracts/provider/vault/src/contract.rs @@ -1,5 +1,6 @@ use cosmwasm_std::{ - coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg + coin, ensure, Addr, Binary, Coin, Decimal, DepsMut, Fraction, Order, Reply, Response, + StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg, }; use cw2::set_contract_version; use cw_storage_plus::{Bounder, Item, Map}; @@ -143,7 +144,11 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn bond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { + fn bond( + &self, + ctx: ExecCtx, + amount: Coin, + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -156,7 +161,10 @@ impl VaultContract<'_> { user.collateral += amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let msg = ProviderMsg::Bond { delegator: ctx.info.sender.clone().into_string(), amount}; + let msg = ProviderMsg::Bond { + delegator: ctx.info.sender.clone().into_string(), + amount, + }; let resp = Response::new() .add_message(msg) .add_attribute("action", "unbond") @@ -167,7 +175,11 @@ impl VaultContract<'_> { } #[sv::msg(exec)] - fn unbond(&self, ctx: ExecCtx, amount: Coin) -> Result, ContractError> { + fn unbond( + &self, + ctx: ExecCtx, + amount: Coin, + ) -> Result, ContractError> { nonpayable(&ctx.info)?; let denom = self.config.load(ctx.deps.storage)?.denom; @@ -187,7 +199,10 @@ impl VaultContract<'_> { user.collateral -= amount.amount; self.users.save(ctx.deps.storage, &ctx.info.sender, &user)?; let amt = amount.amount; - let msg = ProviderMsg::Unbond { delegator: ctx.info.sender.clone().into_string(), amount}; + let msg = ProviderMsg::Unbond { + delegator: ctx.info.sender.clone().into_string(), + amount, + }; let resp = Response::new() .add_message(msg) .add_attribute("action", "unbond") @@ -492,7 +507,11 @@ impl VaultContract<'_> { } #[sv::msg(reply)] - fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result, ContractError> { + fn reply( + &self, + ctx: ReplyCtx, + reply: Reply, + ) -> Result, ContractError> { match reply.id { REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()), _ => Err(ContractError::InvalidReplyId(reply.id)), @@ -1085,7 +1104,11 @@ impl VaultApi for VaultContract<'_> { Ok(resp) } - fn commit_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result, ContractError> { + fn commit_tx( + &self, + mut ctx: ExecCtx, + tx_id: u64, + ) -> Result, ContractError> { self.commit_stake(&mut ctx, tx_id)?; let resp = Response::new() @@ -1096,7 +1119,11 @@ impl VaultApi for VaultContract<'_> { Ok(resp) } - fn rollback_tx(&self, mut ctx: ExecCtx, tx_id: u64) -> Result, ContractError> { + fn rollback_tx( + &self, + mut ctx: ExecCtx, + tx_id: u64, + ) -> Result, ContractError> { self.rollback_stake(&mut ctx, tx_id)?; let resp = Response::new() diff --git a/contracts/provider/vault/src/lib.rs b/contracts/provider/vault/src/lib.rs index 1876926d..e9948f04 100644 --- a/contracts/provider/vault/src/lib.rs +++ b/contracts/provider/vault/src/lib.rs @@ -1,8 +1,8 @@ pub mod contract; pub mod error; +pub mod mock; pub mod msg; #[cfg(test)] pub mod multitest; -pub mod mock; mod state; pub mod txs; diff --git a/contracts/provider/vault/src/mock.rs b/contracts/provider/vault/src/mock.rs index 82235b7b..e1ea1642 100644 --- a/contracts/provider/vault/src/mock.rs +++ b/contracts/provider/vault/src/mock.rs @@ -1,5 +1,6 @@ use cosmwasm_std::{ - coin, ensure, Addr, BankMsg, Binary, Coin, Decimal, DepsMut, Empty, Fraction, Order, Reply, Response, StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg + coin, ensure, Addr, BankMsg, Binary, Coin, Decimal, DepsMut, Empty, Fraction, Order, Reply, + Response, StdResult, Storage, SubMsg, SubMsgResponse, Uint128, WasmMsg, }; use cw2::set_contract_version; use cw_storage_plus::{Bounder, Item, Map}; diff --git a/packages/apis/src/vault_api.rs b/packages/apis/src/vault_api.rs index 8e2a4d08..b2c60207 100644 --- a/packages/apis/src/vault_api.rs +++ b/packages/apis/src/vault_api.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{to_json_binary, Addr, Coin, Response, StdError, Uint128, CustomMsg, WasmMsg}; +use cosmwasm_std::{to_json_binary, Addr, Coin, CustomMsg, Response, StdError, Uint128, WasmMsg}; use sylvia::types::ExecCtx; use sylvia::{interface, schemars}; diff --git a/packages/bindings/src/lib.rs b/packages/bindings/src/lib.rs index 880e1b16..45c3ba81 100644 --- a/packages/bindings/src/lib.rs +++ b/packages/bindings/src/lib.rs @@ -1,7 +1,7 @@ mod msg; mod query; -pub use msg::{VirtualStakeCustomMsg, VirtualStakeMsg, ProviderCustomMsg, ProviderMsg}; +pub use msg::{ProviderCustomMsg, ProviderMsg, VirtualStakeCustomMsg, VirtualStakeMsg}; pub use query::{ BondStatusResponse, SlashRatioResponse, TokenQuerier, VirtualStakeCustomQuery, VirtualStakeQuery,