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: Handle zero max cap #2

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
6649fb1
add config module addr
neitdung Jun 27, 2024
c967bf0
add sender param to bond func and modify tests
neitdung Jun 27, 2024
6208794
handle unbond message from sdk
neitdung Jul 1, 2024
8cf2ea4
Custom contract for zero max cap
trinitys7 Jul 2, 2024
766fe98
change internal_unstake logic to immediate
trinitys7 Jul 2, 2024
3764141
revert adding config and func params
neitdung Jul 3, 2024
0e37ad1
revert unused
neitdung Jul 3, 2024
a9b50dd
remove tab spacing
neitdung Jul 3, 2024
4cc0bab
move update delegation to separate msg
trinitys7 Jul 3, 2024
3c31f0c
add provider binding msg
neitdung Jul 4, 2024
ae41e93
add dependencies
neitdung Jul 4, 2024
de9759a
impl custom response for vault messgae
neitdung Jul 4, 2024
00db35d
Add fake custom to all workspace using mesh-vault
trinitys7 Jul 4, 2024
180d287
fix error
neitdung Jul 4, 2024
e723970
remove unused file
neitdung Jul 4, 2024
b50d126
update dependencies
neitdung Jul 4, 2024
d03c9cc
remove unused config
neitdung Jul 5, 2024
7d981de
fix vault contract error
neitdung Jul 5, 2024
3d0c602
move max_retrieve to config
trinitys7 Jul 5, 2024
a7c170f
Add fake custom to all provider contract
trinitys7 Jul 7, 2024
6b29335
Merge pull request #3 from decentrio/trinity/vesting-delegate
neitdung Jul 8, 2024
28ae4cc
Custom MtApp for multitests
trinitys7 Jul 8, 2024
7a560ce
Fix message name for fitting workspace name
neitdung Jul 8, 2024
63dabbc
add vault mock contract
neitdung Jul 8, 2024
245169b
add mock for multitest
neitdung Jul 8, 2024
41f0f7d
Make the code compile
trinitys7 Jul 8, 2024
fc38e68
remove function effect main logic
neitdung Jul 8, 2024
5d83a84
remove unused deps
neitdung Jul 9, 2024
f30397b
remove fake custom
neitdung Jul 9, 2024
942da1a
remove unused code
neitdung Jul 9, 2024
543850b
revert mock to origin contract
neitdung Jul 9, 2024
1f9b907
make max_retrieve work on converter contract
trinitys7 Jul 9, 2024
b34450a
change custom message name
neitdung Jul 11, 2024
34284a3
fix build error
neitdung Jul 15, 2024
ad46461
lint the code
neitdung Jul 29, 2024
360a8f4
lint
trinitys7 Aug 5, 2024
d7fa396
lint
trinitys7 Aug 5, 2024
0894cda
add doc
trinitys7 Aug 5, 2024
b6a0bfb
lint
trinitys7 Aug 5, 2024
c6a34ff
Merge pull request #196 from decentrio/feat/vesting-delegate-remake
trinitys7 Aug 21, 2024
f7993df
Merge branch 'main' into trinity/zero-max-cap
trinitys7 Aug 21, 2024
aba6c2a
Recalculate the price when unbond
trinitys7 Aug 23, 2024
90c34a4
fix logic for zero max cap
trinitys7 Aug 23, 2024
a0bba9b
lint
trinitys7 Aug 23, 2024
2dd8d50
lint
trinitys7 Aug 23, 2024
9d82cc7
Update schedule logic for zero max cap
trinitys7 Sep 5, 2024
8b6f4ee
Fix tests
trinitys7 Sep 5, 2024
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
3 changes: 3 additions & 0 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion contracts/consumer/converter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ fake-custom = [ "mesh-simple-price-feed/fake-custom" ]
[dependencies]
mesh-apis = { workspace = true }
mesh-bindings = { workspace = true }
mesh-sync = { workspace = true }
mesh-virtual-staking = { workspace = true }

sylvia = { workspace = true }
cosmwasm-schema = { workspace = true }
Expand All @@ -38,7 +40,7 @@ thiserror = { workspace = true }
[dev-dependencies]
mesh-burn = { workspace = true }
mesh-simple-price-feed = { workspace = true, features = ["mt"] }

mesh-virtual-staking = { workspace = true, features = ["mt"] }
cw-multi-test = { workspace = true }
test-case = { workspace = true }
derivative = { workspace = true }
Expand Down
73 changes: 63 additions & 10 deletions contracts/consumer/converter/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use cosmwasm_std::{
ensure_eq, to_json_binary, Addr, BankMsg, Coin, CosmosMsg, Decimal, Deps, DepsMut, Event,
Fraction, MessageInfo, Reply, Response, StdError, SubMsg, SubMsgResponse, Uint128, Validator,
WasmMsg,
Fraction, IbcMsg, MessageInfo, Reply, Response, StdError, SubMsg, SubMsgResponse, Uint128,
Validator, WasmMsg,
};
use cw2::set_contract_version;
use cw_storage_plus::Item;
Expand All @@ -15,7 +15,9 @@ use mesh_apis::price_feed_api;
use mesh_apis::virtual_staking_api;

use crate::error::ContractError;
use crate::ibc::{make_ibc_packet, valset_update_msg, IBC_CHANNEL};
use crate::ibc::{
make_ibc_packet, packet_timeout_internal_unstake, valset_update_msg, IBC_CHANNEL,
};
use crate::msg::ConfigResponse;
use crate::state::Config;

Expand Down Expand Up @@ -72,6 +74,7 @@ impl ConverterContract<'_> {
remote_denom: String,
virtual_staking_code_id: u64,
admin: Option<String>,
max_retrieve: u16,
) -> Result<custom::Response, ContractError> {
nonpayable(&ctx.info)?;
// validate args
Expand All @@ -95,11 +98,13 @@ impl ConverterContract<'_> {
ctx.deps.api.addr_validate(admin)?;
}

let msg =
to_json_binary(&mesh_virtual_staking::contract::sv::InstantiateMsg { max_retrieve })?;
// Instantiate virtual staking contract
let init_msg = WasmMsg::Instantiate {
admin,
code_id: virtual_staking_code_id,
msg: b"{}".into(),
msg,
funds: vec![],
label: format!("Virtual Staking: {}", &config.remote_denom),
};
Expand Down Expand Up @@ -138,17 +143,18 @@ impl ConverterContract<'_> {
fn test_stake(
&self,
ctx: ExecCtx<custom::ConverterQuery>,
delegator: String,
validator: String,
stake: Coin,
) -> Result<custom::Response, ContractError> {
#[cfg(any(test, feature = "mt"))]
{
// This can only ever be called in tests
self.stake(ctx.deps, validator, stake)
self.stake(ctx.deps, delegator, validator, stake)
}
#[cfg(not(any(test, feature = "mt")))]
{
let _ = (ctx, validator, stake);
let _ = (ctx, delegator, validator, stake);
Err(ContractError::Unauthorized)
}
}
Expand All @@ -159,17 +165,18 @@ impl ConverterContract<'_> {
fn test_unstake(
&self,
ctx: ExecCtx<custom::ConverterQuery>,
delegator: String,
validator: String,
unstake: Coin,
) -> Result<custom::Response, ContractError> {
#[cfg(any(test, feature = "mt"))]
{
// This can only ever be called in tests
self.unstake(ctx.deps, validator, unstake)
self.unstake(ctx.deps, delegator, validator, unstake)
}
#[cfg(not(any(test, feature = "mt")))]
{
let _ = (ctx, validator, unstake);
let _ = (ctx, delegator, validator, unstake);
Err(ContractError::Unauthorized)
}
}
Expand Down Expand Up @@ -214,6 +221,7 @@ impl ConverterContract<'_> {
pub(crate) fn stake(
&self,
deps: DepsMut<custom::ConverterQuery>,
delegator: String,
validator: String,
stake: Coin,
) -> Result<custom::Response, ContractError> {
Expand All @@ -223,7 +231,11 @@ impl ConverterContract<'_> {
.add_attribute("validator", &validator)
.add_attribute("amount", amount.amount.to_string());

let msg = virtual_staking_api::sv::ExecMsg::Bond { validator, amount };
let msg = virtual_staking_api::sv::ExecMsg::Bond {
delegator,
validator,
amount,
};
let msg = WasmMsg::Execute {
contract_addr: self.virtual_stake.load(deps.storage)?.into(),
msg: to_json_binary(&msg)?,
Expand All @@ -238,6 +250,7 @@ impl ConverterContract<'_> {
pub(crate) fn unstake(
&self,
deps: DepsMut<custom::ConverterQuery>,
delegator: String,
validator: String,
unstake: Coin,
) -> Result<custom::Response, ContractError> {
Expand All @@ -247,7 +260,11 @@ impl ConverterContract<'_> {
.add_attribute("validator", &validator)
.add_attribute("amount", amount.amount.to_string());

let msg = virtual_staking_api::sv::ExecMsg::Unbond { validator, amount };
let msg = virtual_staking_api::sv::ExecMsg::Unbond {
delegator,
validator,
amount,
};
let msg = WasmMsg::Execute {
contract_addr: self.virtual_stake.load(deps.storage)?.into(),
msg: to_json_binary(&msg)?,
Expand Down Expand Up @@ -603,4 +620,40 @@ impl ConverterApi for ConverterContract<'_> {
resp = resp.add_event(event);
Ok(resp)
}

fn internal_unstake(
&self,
ctx: ExecCtx<custom::ConverterQuery>,
delegator: String,
validator: String,
amount: Coin,
) -> Result<custom::Response, Self::Error> {
let virtual_stake = self.virtual_stake.load(ctx.deps.storage)?;
ensure_eq!(ctx.info.sender, virtual_stake, ContractError::Unauthorized);

#[allow(unused_mut)]
let mut resp = Response::new()
.add_attribute("action", "internal_unstake")
.add_attribute("amount", amount.amount.to_string())
.add_attribute("owner", delegator.clone());

let channel = IBC_CHANNEL.load(ctx.deps.storage)?;

// Recalculate the price when unbond
let inverted_amount = self.invert_price(ctx.deps.as_ref(), amount.clone())?;
let packet = ConsumerPacket::InternalUnstake {
delegator,
validator,
normalize_amount: amount,
inverted_amount,
};
let msg = IbcMsg::SendPacket {
channel_id: channel.endpoint.channel_id,
data: to_json_binary(&packet)?,
timeout: packet_timeout_internal_unstake(&ctx.env),
};
// send packet if we are ibc enabled
resp = resp.add_message(msg);
Ok(resp)
}
}
48 changes: 43 additions & 5 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_json, to_json_binary, DepsMut, Env, Event, Ibc3ChannelOpenResponse, IbcBasicResponse,
IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg,
IbcChannelOpenResponse, IbcMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg,
IbcReceiveResponse, IbcTimeout, Validator,
IbcReceiveResponse, IbcTimeout, Validator, WasmMsg,
};
use cw_storage_plus::Item;

Expand All @@ -14,6 +14,7 @@ use mesh_apis::ibc::{
ack_success, validate_channel_order, AckWrapper, AddValidator, ConsumerPacket, ProtocolVersion,
ProviderPacket, StakeAck, TransferRewardsAck, UnstakeAck, PROTOCOL_NAME,
};
use mesh_apis::virtual_staking_api;
use sylvia::types::ExecCtx;

use crate::{
Expand All @@ -34,6 +35,8 @@ const DEFAULT_VALIDATOR_TIMEOUT: u64 = 24 * 60 * 60;
// But reward messages should go faster or timeout
const DEFAULT_REWARD_TIMEOUT: u64 = 60 * 60;

const DEFAULT_INTERNAL_UNSTAKE_TIMEOUT: u64 = 60 * 60;

pub fn packet_timeout_validator(env: &Env) -> IbcTimeout {
// No idea about their block time, but 24 hours ahead of our view of the clock
// should be decently in the future.
Expand All @@ -48,6 +51,16 @@ pub fn packet_timeout_rewards(env: &Env) -> IbcTimeout {
IbcTimeout::with_timestamp(timeout)
}

pub fn packet_timeout_internal_unstake(env: &Env) -> IbcTimeout {
// No idea about their block time, but 24 hours ahead of our view of the clock
// should be decently in the future.
let timeout = env
.block
.time
.plus_seconds(DEFAULT_INTERNAL_UNSTAKE_TIMEOUT);
IbcTimeout::with_timestamp(timeout)
}

#[cfg_attr(not(feature = "library"), entry_point)]
/// enforces ordering and versioning constraints
pub fn ibc_channel_open(
Expand Down Expand Up @@ -195,11 +208,12 @@ pub fn ibc_packet_receive(
let contract = ConverterContract::new();
let res = match packet {
ProviderPacket::Stake {
delegator,
validator,
stake,
tx_id: _,
} => {
let response = contract.stake(deps, validator, stake)?;
let response = contract.stake(deps, delegator, validator, stake)?;
let ack = ack_success(&StakeAck {})?;
IbcReceiveResponse::new()
.set_ack(ack)
Expand All @@ -208,11 +222,12 @@ pub fn ibc_packet_receive(
.add_attributes(response.attributes)
}
ProviderPacket::Unstake {
delegator,
validator,
unstake,
tx_id: _,
} => {
let response = contract.unstake(deps, validator, unstake)?;
let response = contract.unstake(deps, delegator, validator, unstake)?;
let ack = ack_success(&UnstakeAck {})?;
IbcReceiveResponse::new()
.set_ack(ack)
Expand Down Expand Up @@ -245,14 +260,37 @@ pub fn ibc_packet_receive(
/// If it succeeded, take no action. If it errored, we can't do anything else and let it go.
/// We just log the error cases so they can be detected.
pub fn ibc_packet_ack(
_deps: DepsMut,
deps: DepsMut,
_env: Env,
msg: IbcPacketAckMsg,
) -> Result<IbcBasicResponse, ContractError> {
let ack: AckWrapper = from_json(&msg.acknowledgement.data)?;
let contract = ConverterContract::new();
let mut res = IbcBasicResponse::new();
match ack {
AckWrapper::Result(_) => {}
AckWrapper::Result(_) => {
let packet: ConsumerPacket = from_json(&msg.original_packet.data)?;
if let ConsumerPacket::InternalUnstake {
delegator,
validator,
normalize_amount,
inverted_amount: _,
} = packet
{
// execute virtual contract's internal unbond
let msg = virtual_staking_api::sv::ExecMsg::InternalUnbond {
delegator,
validator,
amount: normalize_amount,
};
let msg = WasmMsg::Execute {
contract_addr: contract.virtual_stake.load(deps.storage)?.into(),
msg: to_json_binary(&msg)?,
funds: vec![],
};
res = res.add_message(msg);
}
}
AckWrapper::Error(e) => {
// The wasmd framework will label this with the contract_addr, which helps us find the port and issue.
// Provide info to find the actual packet.
Expand Down
11 changes: 6 additions & 5 deletions contracts/consumer/converter/src/multitest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ fn setup<'a>(app: &'a App<MtApp>, args: SetupArgs<'a>) -> SetupResponse<'a> {
JUNO.to_owned(),
virtual_staking_code.code_id(),
Some(admin.to_owned()),
50,
)
.with_label("Juno Converter")
.with_admin(admin)
Expand Down Expand Up @@ -172,17 +173,17 @@ fn ibc_stake_and_unstake() {

// let's stake some
converter
.test_stake(val1.to_string(), coin(1000, JUNO))
.test_stake(owner.to_string(), val1.to_string(), coin(1000, JUNO))
.call(owner)
.unwrap();
converter
.test_stake(val2.to_string(), coin(4000, JUNO))
.test_stake(owner.to_string(), val2.to_string(), coin(4000, JUNO))
.call(owner)
.unwrap();

// and unstake some
converter
.test_unstake(val2.to_string(), coin(2000, JUNO))
.test_unstake(owner.to_string(), val2.to_string(), coin(2000, JUNO))
.call(owner)
.unwrap();

Expand Down Expand Up @@ -258,11 +259,11 @@ fn ibc_stake_and_burn() {

// let's stake some
converter
.test_stake(val1.to_string(), coin(1000, JUNO))
.test_stake(owner.to_string(), val1.to_string(), coin(1000, JUNO))
.call(owner)
.unwrap();
converter
.test_stake(val2.to_string(), coin(4000, JUNO))
.test_stake(owner.to_string(), val2.to_string(), coin(4000, JUNO))
.call(owner)
.unwrap();

Expand Down
12 changes: 12 additions & 0 deletions contracts/consumer/converter/src/multitest/virtual_staking_mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ impl VirtualStakingApi for VirtualStakingMock<'_> {
fn bond(
&self,
ctx: ExecCtx<Self::QueryC>,
_delegator: String,
validator: String,
amount: Coin,
) -> Result<Response<Self::ExecC>, Self::Error> {
Expand Down Expand Up @@ -160,6 +161,7 @@ impl VirtualStakingApi for VirtualStakingMock<'_> {
fn unbond(
&self,
ctx: ExecCtx<Self::QueryC>,
_delegator: String,
validator: String,
amount: Coin,
) -> Result<Response<Self::ExecC>, Self::Error> {
Expand Down Expand Up @@ -241,6 +243,16 @@ impl VirtualStakingApi for VirtualStakingMock<'_> {
Ok(Response::new())
}

fn internal_unbond(
&self,
_ctx: ExecCtx<Self::QueryC>,
_delegator: String,
_validator: String,
_amount: Coin,
) -> Result<Response<Self::ExecC>, Self::Error> {
unimplemented!()
}

/// SudoMsg::HandleEpoch{} should be called once per epoch by the sdk (in EndBlock).
/// It allows the virtual staking contract to bond or unbond any pending requests, as well
/// as to perform a rebalance if needed (over the max cap).
Expand Down
1 change: 1 addition & 0 deletions contracts/consumer/virtual-staking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ serde = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
sylvia = { workspace = true, features = ["mt"] }
mesh-simple-price-feed = { workspace = true, features = ["mt", "fake-custom"] }
mesh-converter = { workspace = true, features = ["mt", "fake-custom"] }
cw-multi-test = { workspace = true }
Expand Down
Loading