diff --git a/contracts/provider/vault/Cargo.toml b/contracts/provider/vault/Cargo.toml index 9969f529..f3d76812 100644 --- a/contracts/provider/vault/Cargo.toml +++ b/contracts/provider/vault/Cargo.toml @@ -19,9 +19,10 @@ library = [] mt = ["library", "sylvia/mt"] [dependencies] -mesh-apis = { workspace = true } -mesh-sync = { workspace = true } -mesh-bindings = { workspace = true } +mesh-apis = { workspace = true } +mesh-sync = { workspace = true } +mesh-bindings = { workspace = true } +mesh-native-staking = { workspace = true, features = ["mt", "library"] } sylvia = { workspace = true } cosmwasm-schema = { workspace = true } diff --git a/contracts/provider/vault/src/contract.rs b/contracts/provider/vault/src/contract.rs index 3138e37a..f18f429c 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, to_json_binary }; use cw2::set_contract_version; use cw_storage_plus::{Bounder, Item, Map}; @@ -197,6 +198,63 @@ impl VaultContract<'_> { Ok(resp) } + #[sv::msg(exec)] + fn restake( + &self, + mut ctx: ExecCtx, + amount: Coin, + validator: String, + ) -> Result, ContractError> { + 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)?; + + let amt = amount.amount; + let mut resp = Response::new() + .add_attribute("action", "restake") + .add_attribute("sender", ctx.info.sender.clone().into_string()) + .add_attribute("amount", amt.to_string()); + let restake_msg = ProviderMsg::Restake { + delegator: ctx.info.sender.clone().into_string(), + validator: validator.clone(), + amount: amount.clone(), + }; + resp = resp.add_message(restake_msg); + + 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(), + to_json_binary(&mesh_native_staking::msg::StakeMsg { + validator: validator.to_owned(), + }).unwrap(), + vec![amount.clone()], + )?; + + resp = resp.add_message(stake_msg); + Ok(resp) + } else { + Err(ContractError::NoLocalStaking) + } + } + /// This assigns a claim of amount tokens to the remote contract, which can take some action with it #[sv::msg(exec)] fn stake_remote( diff --git a/packages/bindings/src/msg.rs b/packages/bindings/src/msg.rs index fde80955..439aea1e 100644 --- a/packages/bindings/src/msg.rs +++ b/packages/bindings/src/msg.rs @@ -93,6 +93,12 @@ pub enum ProviderMsg { /// If these conditions are met, it will instantly unstake /// amount.amount tokens from the native staking proxy contract. Unstake { validator: String, amount: Coin }, + /// Restake ensures that amount.denom is the native staking denom and + /// the calling contract is the native staking proxy contract. + /// + /// If these conditions are met, it will instantly restake + /// amount.amount tokens from staking module to local staking contract. + Restake { delegator: String, validator: String, amount: Coin }, } impl ProviderMsg { @@ -128,6 +134,18 @@ impl ProviderMsg { amount: coin, } } + + pub fn restake(denom: &str, delegator: &str, validator: &str, amount: impl Into) -> ProviderMsg { + let coin = Coin { + amount: amount.into(), + denom: denom.into(), + }; + ProviderMsg::Restake { + delegator: delegator.to_string(), + validator: validator.to_string(), + amount: coin, + } + } } impl From for CosmosMsg {