Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow depositing vesting tokens in the vault #1

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions contracts/provider/external-staking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand All @@ -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]]
Expand Down
29 changes: 23 additions & 6 deletions contracts/provider/external-staking/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ fn clamp_page_limit(limit: Option<u32>) -> 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<ExternalStakingMsg>;
}
#[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<ExternalStakingMsg>;
}

pub struct ExternalStakingContract<'a> {
pub config: Item<'a, Config>,
/// Stakes indexed by `(owner, validator)` pair
Expand All @@ -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::ExternalStakingMsg)]
impl ExternalStakingContract<'_> {
pub fn new() -> Self {
Self {
Expand Down Expand Up @@ -96,7 +111,7 @@ impl ExternalStakingContract<'_> {
unbonding_period: u64,
remote_contact: crate::msg::AuthorizedEndpoint,
slash_ratio: SlashRatio,
) -> Result<Response, ContractError> {
) -> Result<custom::Response, ContractError> {
let vault = ctx.deps.api.addr_validate(&vault)?;
let vault = VaultApiHelper(vault);

Expand Down Expand Up @@ -251,7 +266,7 @@ impl ExternalStakingContract<'_> {
ctx: ExecCtx,
validator: String,
amount: Coin,
) -> Result<Response, ContractError> {
) -> Result<custom::Response, ContractError> {
let ExecCtx { info, deps, env } = ctx;
nonpayable(&info)?;

Expand Down Expand Up @@ -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<Response, ContractError> {
pub fn withdraw_unbonded(&self, ctx: ExecCtx) -> Result<custom::Response, ContractError> {
nonpayable(&ctx.info)?;

let config = self.config.load(ctx.deps.storage)?;
Expand Down Expand Up @@ -734,7 +749,7 @@ impl ExternalStakingContract<'_> {
validator: String,
/// Address on the consumer side to receive the rewards
remote_recipient: String,
) -> Result<Response, ContractError> {
) -> Result<custom::Response, ContractError> {
nonpayable(&ctx.info)?;

let stake = self
Expand Down Expand Up @@ -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};
Expand All @@ -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::ExternalStakingMsg;

#[sv::msg(exec)]
fn receive_virtual_stake(
Expand All @@ -1223,7 +1240,7 @@ pub mod cross_staking {
amount: Coin,
tx_id: u64,
msg: Binary,
) -> Result<Response, Self::Error> {
) -> Result<custom::Response, Self::Error> {
let config = self.config.load(ctx.deps.storage)?;
ensure_eq!(ctx.info.sender, config.vault.0, ContractError::Unauthorized);

Expand Down Expand Up @@ -1306,7 +1323,7 @@ pub mod cross_staking {
owner: String,
amount: Coin,
validator: Option<String>,
) -> Result<Response, Self::Error> {
) -> Result<custom::Response, Self::Error> {
let config = self.config.load(ctx.deps.storage)?;
ensure_eq!(ctx.info.sender, config.vault.0, ContractError::Unauthorized);

Expand Down
4 changes: 2 additions & 2 deletions contracts/provider/external-staking/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -117,7 +117,7 @@ pub fn ibc_packet_receive(
deps: DepsMut,
env: Env,
msg: IbcPacketReceiveMsg,
) -> Result<IbcReceiveResponse, ContractError> {
) -> Result<IbcReceiveResponse<custom::ExternalStakingMsg>, 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
Expand Down
70 changes: 29 additions & 41 deletions contracts/provider/external-staking/src/multitest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,22 @@ 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 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, VaultMockProxy};
use mesh_vault::mock::VaultMock;
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;
use crate::test_methods::sv::mt::TestMethodsProxy;
use mesh_apis::cross_staking_api::sv::mt::CrossStakingApiProxy;
use mesh_vault::contract::sv::mt::VaultContractProxy;

use crate::contract::sv::mt::CodeId;
use crate::contract::ExternalStakingContract;
Expand All @@ -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
Expand All @@ -47,7 +52,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);
Expand Down Expand Up @@ -94,7 +99,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"];
Expand Down Expand Up @@ -125,14 +130,12 @@ fn staking() {

// Bond tokens
vault
.bond()
.with_funds(&coins(300, OSMO))
.bond(coin(300, OSMO))
.call(users[0])
.unwrap();

vault
.bond()
.with_funds(&coins(300, OSMO))
.bond(coin(300, OSMO))
.call(users[1])
.unwrap();

Expand Down Expand Up @@ -232,14 +235,12 @@ fn unstaking() {
let validators = contract.activate_validators(["validator1", "validator2"]);

vault
.bond()
.with_funds(&coins(300, OSMO))
.bond(coin(300, OSMO))
.call(users[0])
.unwrap();

vault
.bond()
.with_funds(&coins(300, OSMO))
.bond(coin(300, OSMO))
.call(users[1])
.unwrap();

Expand Down Expand Up @@ -474,8 +475,7 @@ fn immediate_unstake_if_unbonded_validator() {
let validators = contract.activate_validators(["validator1"]);

vault
.bond()
.with_funds(&coins(200, OSMO))
.bond(coin(200, OSMO))
.call(user)
.unwrap();
vault.stake(&contract, user, validators[0], coin(200, OSMO));
Expand Down Expand Up @@ -513,8 +513,7 @@ fn immediate_unstake_if_tombstoned_validator() {
let validators = contract.activate_validators(["validator1"]);

vault
.bond()
.with_funds(&coins(200, OSMO))
.bond(coin(200, OSMO))
.call(user)
.unwrap();
vault.stake(&contract, user, validators[0], coin(200, OSMO));
Expand Down Expand Up @@ -560,14 +559,12 @@ fn distribution() {
// 3/5 of validators[0] to users[1]
// all of validators[1] to users[1]
vault
.bond()
.with_funds(&coins(600, OSMO))
.bond(coin(600, OSMO))
.call(users[0])
.unwrap();

vault
.bond()
.with_funds(&coins(600, OSMO))
.bond(coin(600, OSMO))
.call(users[1])
.unwrap();

Expand Down Expand Up @@ -1164,13 +1161,11 @@ fn batch_distribution() {
let validators = contract.activate_validators(["validator1", "validator2"]);

vault
.bond()
.with_funds(&coins(600, OSMO))
.bond(coin(600, OSMO))
.call(users[0])
.unwrap();
vault
.bond()
.with_funds(&coins(600, OSMO))
.bond(coin(600, OSMO))
.call(users[1])
.unwrap();

Expand Down Expand Up @@ -1209,8 +1204,7 @@ fn batch_distribution_invalid_token() {
let validator = contract.activate_validators(["validator1"])[0];

vault
.bond()
.with_funds(&coins(600, OSMO))
.bond(coin(600, OSMO))
.call(user)
.unwrap();

Expand All @@ -1235,8 +1229,7 @@ fn slashing() {
let validators = contract.activate_validators(["validator1", "validator2"]);

vault
.bond()
.with_funds(&coins(300, OSMO))
.bond(coin(300, OSMO))
.call(user)
.unwrap();

Expand Down Expand Up @@ -1380,8 +1373,7 @@ fn slashing_pending_tx_partial_unbond() {
let validators = contract.activate_validators(["validator1", "validator2"]);

vault
.bond()
.with_funds(&coins(300, OSMO))
.bond(coin(300, OSMO))
.call(user)
.unwrap();

Expand Down Expand Up @@ -1467,8 +1459,7 @@ fn slashing_pending_tx_full_unbond() {
let validators = contract.activate_validators(["validator1", "validator2"]);

vault
.bond()
.with_funds(&coins(200, OSMO))
.bond(coin(200, OSMO))
.call(user)
.unwrap();

Expand Down Expand Up @@ -1550,8 +1541,7 @@ fn slashing_pending_tx_full_unbond_rolled_back() {
let validators = contract.activate_validators(["validator1"]);

vault
.bond()
.with_funds(&coins(200, OSMO))
.bond(coin(200, OSMO))
.call(user)
.unwrap();

Expand Down Expand Up @@ -1631,8 +1621,7 @@ fn slashing_pending_tx_bond() {
let validators = contract.activate_validators(["validator1", "validator2"]);

vault
.bond()
.with_funds(&coins(300, OSMO))
.bond(coin(300, OSMO))
.call(user)
.unwrap();

Expand Down Expand Up @@ -1716,8 +1705,7 @@ fn slashing_pending_tx_bond_rolled_back() {
let validators = contract.activate_validators(["validator1", "validator2"]);

vault
.bond()
.with_funds(&coins(300, OSMO))
.bond(coin(300, OSMO))
.call(user)
.unwrap();

Expand Down
Loading