From 6795cc51d0e7215de43c6d82b97f9ff9bea140ea Mon Sep 17 00:00:00 2001 From: Mauro Lacy Date: Thu, 5 Jan 2023 12:19:13 +0100 Subject: [PATCH 1/4] Support updating / setting half-life duration through migration --- contracts/tg4-engagement/src/contract.rs | 19 ++++++++++++++----- contracts/tg4-engagement/src/msg.rs | 6 ++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/contracts/tg4-engagement/src/contract.rs b/contracts/tg4-engagement/src/contract.rs index 2ee7541..18741ec 100644 --- a/contracts/tg4-engagement/src/contract.rs +++ b/contracts/tg4-engagement/src/contract.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - coin, to_binary, Addr, BankMsg, Binary, Coin, CustomQuery, Decimal, Deps, DepsMut, Empty, Env, - Event, MessageInfo, Order, StdResult, Timestamp, Uint128, + coin, to_binary, Addr, BankMsg, Binary, Coin, CustomQuery, Decimal, Deps, DepsMut, Env, Event, + MessageInfo, Order, StdResult, Timestamp, Uint128, }; use cw2::set_contract_version; use cw_storage_plus::Bound; @@ -14,8 +14,8 @@ use tg4::{ use crate::error::ContractError; use crate::msg::{ - DelegatedResponse, ExecuteMsg, HalflifeInfo, HalflifeResponse, InstantiateMsg, PreauthResponse, - QueryMsg, RewardsResponse, SudoMsg, + DelegatedResponse, ExecuteMsg, HalflifeInfo, HalflifeResponse, InstantiateMsg, MigrateMsg, + PreauthResponse, QueryMsg, RewardsResponse, SudoMsg, }; use crate::state::{ Distribution, Halflife, WithdrawAdjustment, DISTRIBUTION, HALFLIFE, PREAUTH_SLASHING, @@ -913,8 +913,17 @@ fn list_members_by_points( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { +pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result { ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + if let Some(duration) = msg.halflife { + // Update half life's duration + HALFLIFE.update(deps.storage, |hf| -> StdResult<_> { + Ok(Halflife { + halflife: Some(duration), + last_applied: hf.last_applied, + }) + })?; + }; Ok(Response::new()) } diff --git a/contracts/tg4-engagement/src/msg.rs b/contracts/tg4-engagement/src/msg.rs index f14ffc8..1b6dc90 100644 --- a/contracts/tg4-engagement/src/msg.rs +++ b/contracts/tg4-engagement/src/msg.rs @@ -183,6 +183,12 @@ pub struct ListSlashersResponse { pub slashers: Vec, } +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] +#[serde(rename_all = "snake_case")] +pub struct MigrateMsg { + pub halflife: Option, +} + #[cfg(test)] mod tests { use super::*; From d4af8617f615acd3c711971dc7d95436d41a02f8 Mon Sep 17 00:00:00 2001 From: Mauro Lacy Date: Thu, 5 Jan 2023 13:04:45 +0100 Subject: [PATCH 2/4] Support removing half-life through migration --- contracts/tg4-engagement/src/contract.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contracts/tg4-engagement/src/contract.rs b/contracts/tg4-engagement/src/contract.rs index 18741ec..e7ac629 100644 --- a/contracts/tg4-engagement/src/contract.rs +++ b/contracts/tg4-engagement/src/contract.rs @@ -917,9 +917,14 @@ pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result StdResult<_> { Ok(Halflife { - halflife: Some(duration), + halflife: if duration.seconds() > 0 { + Some(duration) + } else { + None + }, last_applied: hf.last_applied, }) })?; From 82e32707964b4dfbf43f996914d490da317b03c3 Mon Sep 17 00:00:00 2001 From: Mauro Lacy Date: Thu, 5 Jan 2023 15:12:40 +0100 Subject: [PATCH 3/4] Add migration test --- contracts/tg4-engagement/src/contract.rs | 6 +++- contracts/tg4-engagement/src/multitest.rs | 28 +++++++++++++++++++ .../tg4-engagement/src/multitest/suite.rs | 28 ++++++++++++++++++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/contracts/tg4-engagement/src/contract.rs b/contracts/tg4-engagement/src/contract.rs index e7ac629..3566a40 100644 --- a/contracts/tg4-engagement/src/contract.rs +++ b/contracts/tg4-engagement/src/contract.rs @@ -913,7 +913,11 @@ fn list_members_by_points( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result { +pub fn migrate( + deps: DepsMut, + _env: Env, + msg: MigrateMsg, +) -> Result { ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; if let Some(duration) = msg.halflife { // Update half life's duration diff --git a/contracts/tg4-engagement/src/multitest.rs b/contracts/tg4-engagement/src/multitest.rs index 5254814..8bb5122 100644 --- a/contracts/tg4-engagement/src/multitest.rs +++ b/contracts/tg4-engagement/src/multitest.rs @@ -921,3 +921,31 @@ mod slashing { assert_eq!(suite.token_balance(members[2]).unwrap(), 0); } } + +mod migration { + use super::*; + use crate::msg::MigrateMsg; + + #[test] + fn migration_can_alter_cfg() { + let mut suite = SuiteBuilder::new() + .with_halflife(Duration::new(100)) + .build(); + let admin = suite.admin().to_string(); + + let cfg = suite.halflife().unwrap(); + assert_eq!(cfg.halflife_info.unwrap().halflife, Duration::new(100)); + + suite + .migrate( + &admin, + &MigrateMsg { + halflife: Some(Duration::new(200)), + }, + ) + .unwrap(); + + let cfg = suite.halflife().unwrap(); + assert_eq!(cfg.halflife_info.unwrap().halflife.seconds(), 200); + } +} diff --git a/contracts/tg4-engagement/src/multitest/suite.rs b/contracts/tg4-engagement/src/multitest/suite.rs index 04eec83..f11e45f 100644 --- a/contracts/tg4-engagement/src/multitest/suite.rs +++ b/contracts/tg4-engagement/src/multitest/suite.rs @@ -15,6 +15,7 @@ fn contract_engagement() -> Box> { crate::contract::instantiate, crate::contract::query, ) + .with_migrate(crate::contract::migrate) .with_sudo(crate::contract::sudo); Box::new(contract) @@ -133,6 +134,7 @@ impl SuiteBuilder { Suite { app, + code_id: contract_id, contract, owner, denom, @@ -145,9 +147,11 @@ impl SuiteBuilder { pub struct Suite { #[derivative(Debug = "ignore")] pub app: TgradeApp, + /// The code id of the engagement contract + code_id: u64, /// Engagement contract address pub contract: Addr, - /// Mixer contract address + /// Admin of engagement contract pub owner: Addr, /// Denom of tokens which might be distributed by this contract pub denom: String, @@ -170,6 +174,10 @@ impl Suite { ) } + pub fn admin(&self) -> &str { + self.owner.as_str() + } + pub fn withdraw_funds<'s>( &mut self, executor: &str, @@ -340,4 +348,22 @@ impl Suite { )?; Ok(resp.members) } + + /// Queries engagement contract for its halflife + pub fn halflife(&self) -> StdResult { + self.app + .wrap() + .query_wasm_smart(&self.contract, &QueryMsg::Halflife {}) + } + + /// Migrates the contract to the same version (same code id), but possibly changing + /// some cfg values via MigrateMsg. + pub fn migrate(&mut self, addr: &str, msg: &MigrateMsg) -> AnyResult { + self.app.migrate_contract( + Addr::unchecked(addr), + self.contract.clone(), + msg, + self.code_id, + ) + } } From 4438119887d7a5ef043ecd837734755bdfcad05f Mon Sep 17 00:00:00 2001 From: Mauro Lacy Date: Thu, 5 Jan 2023 15:14:07 +0100 Subject: [PATCH 4/4] Add migration removes half-life test --- contracts/tg4-engagement/src/multitest.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/contracts/tg4-engagement/src/multitest.rs b/contracts/tg4-engagement/src/multitest.rs index 8bb5122..f9e2aef 100644 --- a/contracts/tg4-engagement/src/multitest.rs +++ b/contracts/tg4-engagement/src/multitest.rs @@ -948,4 +948,27 @@ mod migration { let cfg = suite.halflife().unwrap(); assert_eq!(cfg.halflife_info.unwrap().halflife.seconds(), 200); } + + #[test] + fn migration_can_remove_halflife() { + let mut suite = SuiteBuilder::new() + .with_halflife(Duration::new(100)) + .build(); + let admin = suite.admin().to_string(); + + let cfg = suite.halflife().unwrap(); + assert_eq!(cfg.halflife_info.unwrap().halflife, Duration::new(100)); + + suite + .migrate( + &admin, + &MigrateMsg { + halflife: Some(Duration::new(0)), + }, + ) + .unwrap(); + + let cfg = suite.halflife().unwrap(); + assert!(cfg.halflife_info.is_none()); + } }