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

F/valset updates #109

Merged
merged 10 commits into from
Aug 28, 2023
Merged
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
10 changes: 6 additions & 4 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mesh-converter = { path = "./contracts/consumer/converter" }
mesh-simple-price-feed = { path = "./contracts/consumer/simple-price-feed" }
mesh-virtual-staking = { path = "./contracts/consumer/virtual-staking" }

sylvia = "0.6.0"
sylvia = "0.7.1"
cosmwasm-schema = "1.2"
cosmwasm-std = { version = "1.2", features = ["ibc3", "cosmwasm_1_2"] }
cosmwasm-storage = "1.2"
Expand Down
40 changes: 37 additions & 3 deletions contracts/consumer/converter/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use cosmwasm_std::{
ensure_eq, to_binary, Addr, BankMsg, Coin, CosmosMsg, Decimal, Deps, DepsMut, Event, IbcMsg,
Reply, Response, SubMsg, SubMsgResponse, WasmMsg,
Reply, Response, SubMsg, SubMsgResponse, Validator, WasmMsg,
};
use cw2::set_contract_version;
use cw_storage_plus::Item;
Expand All @@ -14,7 +14,7 @@ use mesh_apis::price_feed_api;
use mesh_apis::virtual_staking_api;

use crate::error::ContractError;
use crate::ibc::{packet_timeout_rewards, IBC_CHANNEL};
use crate::ibc::{add_validators_msg, packet_timeout_rewards, IBC_CHANNEL};
use crate::msg::ConfigResponse;
use crate::state::Config;

Expand All @@ -36,7 +36,7 @@ impl ConverterContract<'_> {
pub const fn new() -> Self {
Self {
config: Item::new("config"),
virtual_stake: Item::new("bonded"),
virtual_stake: Item::new("virtual_stake"),
}
}

Expand Down Expand Up @@ -325,4 +325,38 @@ impl ConverterApi for ConverterContract<'_> {
}
Ok(resp)
}

/// Valset updates.
///
/// Sent validator set additions (entering the active validator set) to the external staking
/// contract on the Consumer via IBC.
#[msg(exec)]
fn valset_update(
&self,
ctx: ExecCtx,
additions: Vec<Validator>,
) -> Result<Response, Self::Error> {
let virtual_stake = self.virtual_stake.load(ctx.deps.storage)?;
ensure_eq!(
ctx.info.sender,
virtual_stake,
ContractError::Unauthorized {}
);

// Send over IBC to the Consumer
let channel = IBC_CHANNEL.load(ctx.deps.storage)?;
let msg = add_validators_msg(&ctx.env, channel, &additions)?;

let event = Event::new("valset_update").add_attribute(
"additions",
additions
.iter()
.map(|v| v.address.clone())
.collect::<Vec<String>>()
.join(","),
);
let resp = Response::new().add_event(event).add_message(msg);

Ok(resp)
}
}
26 changes: 18 additions & 8 deletions contracts/consumer/converter/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cosmwasm_std::{
from_slice, to_binary, DepsMut, Env, Event, Ibc3ChannelOpenResponse, IbcBasicResponse,
IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg,
IbcChannelOpenResponse, IbcMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg,
IbcReceiveResponse, IbcTimeout,
IbcReceiveResponse, IbcTimeout, Validator,
};
use cw_storage_plus::Item;

Expand Down Expand Up @@ -114,13 +114,24 @@ pub fn ibc_channel_connect(

// Send a validator sync packet to arrive with the newly established channel
let validators = deps.querier.query_all_validators()?;
let msg = add_validators_msg(&env, channel, &validators)?;

Ok(IbcBasicResponse::new().add_message(msg))
}

pub(crate) fn add_validators_msg(
env: &Env,
channel: IbcChannel,
validators: &[Validator],
) -> Result<IbcMsg, ContractError> {
let updates = validators
.into_iter()
.iter()
.map(|v| AddValidator {
valoper: v.address,
// TODO: not yet available in CosmWasm APIs
valoper: v.address.clone(),
// TODO: not yet available in CosmWasm APIs. See https://github.com/CosmWasm/cosmwasm/issues/1828
pub_key: "TODO".to_string(),
// Use current height/time as start height/time (no slashing before mesh starts)
// Use current height/time as start height/time (no slashing before mesh starts).
// Warning: These will be updated as well when updating an already existing validator.
start_height: env.block.height,
start_time: env.block.time.seconds(),
})
Expand All @@ -129,10 +140,9 @@ pub fn ibc_channel_connect(
let msg = IbcMsg::SendPacket {
channel_id: channel.endpoint.channel_id,
data: to_binary(&packet)?,
timeout: packet_timeout_validator(&env),
timeout: packet_timeout_validator(env),
};

Ok(IbcBasicResponse::new().add_message(msg))
Ok(msg)
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down
67 changes: 66 additions & 1 deletion contracts/consumer/converter/src/multitest.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
mod virtual_staking_mock;

use cosmwasm_std::{coin, Addr, Decimal, Uint128};
use cosmwasm_std::{coin, Addr, Decimal, StdError, Uint128, Validator};
use cw_multi_test::App as MtApp;
use sylvia::multitest::App;

use crate::contract;
use crate::contract::test_utils::ConverterApi;
use crate::error::ContractError;
use crate::error::ContractError::Unauthorized;

const JUNO: &str = "ujuno";

Expand Down Expand Up @@ -195,3 +198,65 @@ fn ibc_stake_and_unstake() {
]
);
}

#[test]
fn valset_update_works() {
let app = App::default();

let owner = "sunny"; // Owner of the staking contract (i. e. the vault contract)
let admin = "theman";
let discount = Decimal::percent(10); // 1 OSMO worth of JUNO should give 0.9 OSMO of stake
let native_per_foreign = Decimal::percent(40); // 1 JUNO is worth 0.4 OSMO

let SetupResponse {
price_feed: _,
converter,
virtual_staking,
} = setup(
&app,
SetupArgs {
owner,
admin,
discount,
native_per_foreign,
},
);

// Send a valset update
let new_validators = vec![
Validator {
address: "validator1".to_string(),
commission: Default::default(),
max_commission: Default::default(),
max_change_rate: Default::default(),
},
Validator {
address: "validator3".to_string(),
commission: Default::default(),
max_commission: Default::default(),
max_change_rate: Default::default(),
},
];

// Check that only the virtual staking contract can call this handler
let res = converter
.converter_api_proxy()
.valset_update(vec![])
.call(owner);
assert_eq!(res.unwrap_err(), Unauthorized {});

let res = converter
.converter_api_proxy()
.valset_update(new_validators)
.call(virtual_staking.contract_addr.as_ref());

// This fails because of lack of IBC support in mt now.
// Cannot be tested further in this setup.
// TODO: Change this when IBC support is there in mt.
assert_eq!(
res.unwrap_err(),
ContractError::Std(StdError::NotFound {
kind: "cosmwasm_std::ibc::IbcChannel".to_string()
})
);
}
12 changes: 7 additions & 5 deletions contracts/consumer/virtual-staking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ mt = ["library", "sylvia/mt"]

[dependencies]
mesh-apis = { workspace = true }
mesh-bindings = { workspace = true }
mesh-bindings = { workspace = true }

sylvia = { workspace = true }
cosmwasm-schema = { workspace = true }
Expand All @@ -35,10 +35,12 @@ serde = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
cw-multi-test = { workspace = true }
test-case = { workspace = true }
derivative = { workspace = true }
anyhow = { workspace = true }
mesh-simple-price-feed = { workspace = true, features = ["mt"] }
mesh-converter = { workspace = true, features = ["mt"] }
cw-multi-test = { workspace = true }
test-case = { workspace = true }
derivative = { workspace = true }
anyhow = { workspace = true }

[[bin]]
name = "schema"
Expand Down
35 changes: 34 additions & 1 deletion contracts/consumer/virtual-staking/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::collections::BTreeMap;
use cosmwasm_std::{
coin, ensure_eq, entry_point, to_binary, Coin, CosmosMsg, CustomQuery, DepsMut,
DistributionMsg, Env, Event, Reply, Response, StdResult, SubMsg, SubMsgResponse, Uint128,
WasmMsg,
Validator, WasmMsg,
};
use cw2::set_contract_version;
use cw_storage_plus::{Item, Map};
Expand Down Expand Up @@ -44,6 +44,7 @@ pub struct VirtualStakingContract<'a> {
#[contract]
#[error(ContractError)]
#[messages(virtual_staking_api as VirtualStakingApi)]
// #[sv::override_entry_point(sudo=sudo(SudoMsg))] // Disabled because lack of custom query support
impl VirtualStakingContract<'_> {
pub const fn new() -> Self {
Self {
Expand Down Expand Up @@ -134,6 +135,34 @@ impl VirtualStakingContract<'_> {
Ok(resp)
}

/**
* This is called every time there's a change of the active validator set.
*
*/
fn handle_valset_update(
&self,
deps: DepsMut<VirtualStakeCustomQuery>,
additions: &[Validator],
removals: &[Validator],
) -> Result<Response<VirtualStakeCustomMsg>, ContractError> {
// TODO: Store/process removals (and additions) locally, so that they are filtered out from
// the `bonded` list
let _ = removals;

// Send additions to the converter. Removals are considered non-permanent and ignored
let cfg = self.config.load(deps.storage)?;
let msg = converter_api::ExecMsg::ValsetUpdate {
additions: additions.to_vec(),
};
let msg = WasmMsg::Execute {
contract_addr: cfg.converter.to_string(),
msg: to_binary(&msg)?,
funds: vec![],
};
let resp = Response::new().add_message(msg);
Ok(resp)
}

#[msg(reply)]
fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result<Response, ContractError> {
match (reply.id, reply.result.into_result()) {
Expand Down Expand Up @@ -325,5 +354,9 @@ pub fn sudo(
) -> Result<Response<VirtualStakeCustomMsg>, ContractError> {
match msg {
SudoMsg::Rebalance {} => VirtualStakingContract::new().handle_epoch(deps, env),
SudoMsg::ValsetUpdate {
additions,
removals,
} => VirtualStakingContract::new().handle_valset_update(deps, &additions, &removals),
}
}
2 changes: 2 additions & 0 deletions contracts/consumer/virtual-staking/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod contract;
pub mod error;
pub mod msg;
#[cfg(test)]
mod multitest;
pub mod state;
Loading
Loading