From 00f64a9e8df5b384c2648d3f0f38baa549f204b3 Mon Sep 17 00:00:00 2001 From: ByeongSu Hong Date: Thu, 16 May 2024 18:04:56 +0900 Subject: [PATCH] feat: add migration logic based on semver comparison (#130) * add hpl-utils * apply migrator (hpl-mailbox) * apply migrator (hpl-va) * apply migrator (hpl-hook-aggregate) * chore: fmt * apply migrator (hpl-hooks-fee) * apply migrator (hpl-hooks-merkle) * apply migrator (hpl-hooks-pausable) * merge & simplify * apply migrator (hpl-hook-routing) * apply migrator (hpl-hook-routing-custom) * apply migrator (hpl-hook-routing-fallback) * apply migrator (hpl-igp) * apply migrator (hpl-igp-oracle) * apply migrator (hpl-ism-aggregate) * apply migrator (hpl-ism-multisig) * apply migrator (hpl-ism-pausable) * apply migrator (hpl-ism-routing) * apply migrator (hpl-test-mock-hook) * apply migrator (hpl-test-mock-ism) * apply migrator (hpl-test-mock-msg-receiver) * apply migrator (hpl-warp-cw20) * apply migrator (hpl-warp-native) * allow & fmt --- Cargo.toml | 2 + contracts/core/mailbox/Cargo.toml | 1 + contracts/core/mailbox/src/contract.rs | 3 +- contracts/core/mailbox/src/error.rs | 3 + contracts/core/mailbox/src/execute.rs | 11 ++- contracts/core/va/Cargo.toml | 1 + contracts/core/va/src/contract.rs | 5 +- contracts/core/va/src/error.rs | 3 + contracts/hooks/aggregate/Cargo.toml | 1 + contracts/hooks/aggregate/src/error.rs | 16 ---- contracts/hooks/aggregate/src/lib.rs | 31 ++++++-- contracts/hooks/fee/Cargo.toml | 1 + contracts/hooks/fee/src/lib.rs | 15 +++- contracts/hooks/merkle/Cargo.toml | 1 + contracts/hooks/merkle/src/lib.rs | 8 +- contracts/hooks/pausable/Cargo.toml | 1 + contracts/hooks/pausable/src/lib.rs | 11 ++- contracts/hooks/routing-custom/Cargo.toml | 1 + contracts/hooks/routing-custom/src/lib.rs | 11 ++- contracts/hooks/routing-fallback/Cargo.toml | 1 + contracts/hooks/routing-fallback/src/lib.rs | 11 ++- contracts/hooks/routing/Cargo.toml | 1 + contracts/hooks/routing/src/lib.rs | 13 +++- contracts/igps/core/Cargo.toml | 1 + contracts/igps/core/src/contract.rs | 5 +- contracts/igps/core/src/error.rs | 3 + contracts/igps/oracle/Cargo.toml | 1 + contracts/igps/oracle/src/contract.rs | 10 ++- contracts/igps/oracle/src/error.rs | 3 + contracts/isms/aggregate/Cargo.toml | 1 + contracts/isms/aggregate/src/error.rs | 3 + contracts/isms/aggregate/src/lib.rs | 3 +- contracts/isms/multisig/Cargo.toml | 1 + contracts/isms/multisig/src/contract.rs | 16 ++-- contracts/isms/multisig/src/error.rs | 3 + contracts/isms/pausable/Cargo.toml | 1 + contracts/isms/pausable/src/lib.rs | 11 ++- contracts/isms/routing/Cargo.toml | 1 + contracts/isms/routing/src/contract.rs | 8 +- contracts/isms/routing/src/error.rs | 3 + contracts/mocks/mock-hook/Cargo.toml | 1 + contracts/mocks/mock-hook/src/contract.rs | 8 +- contracts/mocks/mock-ism/Cargo.toml | 1 + contracts/mocks/mock-ism/src/contract.rs | 13 ++-- contracts/mocks/mock-msg-receiver/Cargo.toml | 1 + .../mocks/mock-msg-receiver/src/contract.rs | 3 +- contracts/warp/cw20/Cargo.toml | 1 + contracts/warp/cw20/src/contract.rs | 27 +++++-- contracts/warp/cw20/src/error.rs | 3 + contracts/warp/native/Cargo.toml | 1 + contracts/warp/native/src/contract.rs | 19 ++++- contracts/warp/native/src/error.rs | 3 + packages/utils/Cargo.toml | 25 +++++++ packages/utils/src/lib.rs | 74 +++++++++++++++++++ 54 files changed, 333 insertions(+), 73 deletions(-) delete mode 100644 contracts/hooks/aggregate/src/error.rs create mode 100644 packages/utils/Cargo.toml create mode 100644 packages/utils/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 321d4a23..d40683e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ cw20 = "1.1.2" cw20-base = { version = "1.1.2", features = ["library"] } # utilities +semver = "1.0.23" thiserror = { version = "1.0.37" } anyhow = { version = "1.0.71", features = ["backtrace"] } eyre = { version = "0.6.8" } @@ -115,3 +116,4 @@ hpl-ownable = { path = "./packages/ownable" } hpl-pausable = { path = "./packages/pausable" } hpl-router = { path = "./packages/router" } hpl-interface = { path = "./packages/interface" } +hpl-utils = { path = "./packages/utils" } diff --git a/contracts/core/mailbox/Cargo.toml b/contracts/core/mailbox/Cargo.toml index 4f982939..c34da8c3 100644 --- a/contracts/core/mailbox/Cargo.toml +++ b/contracts/core/mailbox/Cargo.toml @@ -33,6 +33,7 @@ bech32.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-interface.workspace = true diff --git a/contracts/core/mailbox/src/contract.rs b/contracts/core/mailbox/src/contract.rs index 7b64d3f0..3c575819 100644 --- a/contracts/core/mailbox/src/contract.rs +++ b/contracts/core/mailbox/src/contract.rs @@ -96,7 +96,8 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Result { +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; Ok(Response::default()) } diff --git a/contracts/core/mailbox/src/error.rs b/contracts/core/mailbox/src/error.rs index 8df21fca..ec7b7b17 100644 --- a/contracts/core/mailbox/src/error.rs +++ b/contracts/core/mailbox/src/error.rs @@ -18,6 +18,9 @@ pub enum ContractError { #[error("{0}")] CoinsError(#[from] cosmwasm_std::CoinsError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, diff --git a/contracts/core/mailbox/src/execute.rs b/contracts/core/mailbox/src/execute.rs index 5f06e026..02db25bf 100644 --- a/contracts/core/mailbox/src/execute.rs +++ b/contracts/core/mailbox/src/execute.rs @@ -1,8 +1,7 @@ use cosmwasm_std::{ - ensure, ensure_eq, to_json_binary, wasm_execute, Coin, Coins, DepsMut, Env, - HexBinary, MessageInfo, Response, + ensure, ensure_eq, to_json_binary, wasm_execute, Coin, Coins, DepsMut, Env, HexBinary, + MessageInfo, Response, }; -use cw_utils::PaymentError::MissingDenom; use hpl_interface::{ core::{ mailbox::{DispatchMsg, DispatchResponse}, @@ -123,7 +122,7 @@ pub fn dispatch( let mut funds = Coins::try_from(info.funds.clone())?; for coin in required_hook_fees.iter() { - if let Err(_) = funds.sub(coin.clone()) { + if funds.sub(coin.clone()).is_err() { return Err(ContractError::HookPayment { wanted: required_hook_fees, received: info.funds, @@ -233,8 +232,8 @@ mod tests { use cosmwasm_std::{ coin, from_json, testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage}, - to_json_binary, Addr, ContractResult, CosmosMsg, OwnedDeps, QuerierResult, - SystemResult, WasmMsg, WasmQuery, + to_json_binary, Addr, ContractResult, CosmosMsg, OwnedDeps, QuerierResult, SystemResult, + WasmMsg, WasmQuery, }; use hpl_interface::{ diff --git a/contracts/core/va/Cargo.toml b/contracts/core/va/Cargo.toml index d101c16a..2a8fc1c7 100644 --- a/contracts/core/va/Cargo.toml +++ b/contracts/core/va/Cargo.toml @@ -36,6 +36,7 @@ serde.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-interface.workspace = true [dev-dependencies] diff --git a/contracts/core/va/src/contract.rs b/contracts/core/va/src/contract.rs index dd77b473..2cd7c689 100644 --- a/contracts/core/va/src/contract.rs +++ b/contracts/core/va/src/contract.rs @@ -216,8 +216,9 @@ fn announce( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(_deps: DepsMut, _env: Env, _msg: Empty) -> Result { - Ok(Response::new()) +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) } #[cfg(test)] diff --git a/contracts/core/va/src/error.rs b/contracts/core/va/src/error.rs index 2650f6b9..ce33f497 100644 --- a/contracts/core/va/src/error.rs +++ b/contracts/core/va/src/error.rs @@ -9,6 +9,9 @@ pub enum ContractError { #[error("{0}")] RecoverPubkeyError(#[from] RecoverPubkeyError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized. reason: {0}")] Unauthorized(String), diff --git a/contracts/hooks/aggregate/Cargo.toml b/contracts/hooks/aggregate/Cargo.toml index 7d196235..55d2e031 100644 --- a/contracts/hooks/aggregate/Cargo.toml +++ b/contracts/hooks/aggregate/Cargo.toml @@ -32,6 +32,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-interface.workspace = true diff --git a/contracts/hooks/aggregate/src/error.rs b/contracts/hooks/aggregate/src/error.rs deleted file mode 100644 index ded0227c..00000000 --- a/contracts/hooks/aggregate/src/error.rs +++ /dev/null @@ -1,16 +0,0 @@ -use cosmwasm_std::StdError; - -#[derive(thiserror::Error, Debug, PartialEq)] -pub enum ContractError { - #[error("{0}")] - Std(#[from] StdError), - - #[error("{0}")] - PaymentError(#[from] cw_utils::PaymentError), - - #[error("{0}")] - CoinsError(#[from] cosmwasm_std::CoinsError), - - #[error("unauthorized")] - Unauthorized {}, -} diff --git a/contracts/hooks/aggregate/src/lib.rs b/contracts/hooks/aggregate/src/lib.rs index dc91e7ca..9a7175ff 100644 --- a/contracts/hooks/aggregate/src/lib.rs +++ b/contracts/hooks/aggregate/src/lib.rs @@ -1,13 +1,10 @@ -mod error; - #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure_eq, Addr, Coins, CosmosMsg, Deps, DepsMut, Env, Event, HexBinary, MessageInfo, - QueryResponse, Response, StdResult, + ensure_eq, Addr, Coins, CosmosMsg, Deps, DepsMut, Empty, Env, Event, HexBinary, MessageInfo, + QueryResponse, Response, StdError, StdResult, }; use cw_storage_plus::Item; -use error::ContractError; use hpl_interface::{ hook::{ aggregate::{AggregateHookQueryMsg, ExecuteMsg, HooksResponse, InstantiateMsg, QueryMsg}, @@ -19,6 +16,24 @@ use hpl_interface::{ }; use hpl_ownable::get_owner; +#[derive(thiserror::Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("{0}")] + PaymentError(#[from] cw_utils::PaymentError), + + #[error("{0}")] + CoinsError(#[from] cosmwasm_std::CoinsError), + + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + + #[error("unauthorized")] + Unauthorized {}, +} + // version info for migration info pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -178,3 +193,9 @@ fn get_hooks(deps: Deps) -> Result { .collect(), }) } + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} diff --git a/contracts/hooks/fee/Cargo.toml b/contracts/hooks/fee/Cargo.toml index d5f6e792..501e7139 100644 --- a/contracts/hooks/fee/Cargo.toml +++ b/contracts/hooks/fee/Cargo.toml @@ -32,6 +32,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-interface.workspace = true diff --git a/contracts/hooks/fee/src/lib.rs b/contracts/hooks/fee/src/lib.rs index 743d6e79..be2de06b 100644 --- a/contracts/hooks/fee/src/lib.rs +++ b/contracts/hooks/fee/src/lib.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure, ensure_eq, BankMsg, Coin, CosmosMsg, Deps, DepsMut, Env, Event, MessageInfo, + ensure, ensure_eq, BankMsg, Coin, CosmosMsg, Deps, DepsMut, Empty, Env, Event, MessageInfo, QueryResponse, Response, StdError, }; use cw_storage_plus::Item; @@ -21,6 +21,9 @@ pub enum ContractError { #[error("{0}")] PaymentError(#[from] cw_utils::PaymentError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, @@ -150,6 +153,12 @@ fn quote_dispatch(deps: Deps) -> Result { Ok(QuoteDispatchResponse { fees: vec![fee] }) } +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} + #[cfg(test)] mod test { use cosmwasm_schema::serde::{de::DeserializeOwned, Serialize}; @@ -258,7 +267,9 @@ mod test { deps.as_mut(), mock_env(), mock_info(sender.as_str(), &[]), - ExecuteMsg::FeeHook(FeeHookMsg::Claim { recipient: recipient.clone() }), + ExecuteMsg::FeeHook(FeeHookMsg::Claim { + recipient: recipient.clone(), + }), ) .map_err(|e| e.to_string()) .unwrap(); diff --git a/contracts/hooks/merkle/Cargo.toml b/contracts/hooks/merkle/Cargo.toml index 7af607d0..2767188b 100644 --- a/contracts/hooks/merkle/Cargo.toml +++ b/contracts/hooks/merkle/Cargo.toml @@ -32,6 +32,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-interface.workspace = true diff --git a/contracts/hooks/merkle/src/lib.rs b/contracts/hooks/merkle/src/lib.rs index be13388a..71d76df6 100644 --- a/contracts/hooks/merkle/src/lib.rs +++ b/contracts/hooks/merkle/src/lib.rs @@ -26,6 +26,9 @@ pub enum ContractError { #[error("unauthorized. reason: {0}")] Unauthorized(String), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("hook paused")] Paused {}, } @@ -191,8 +194,9 @@ fn get_tree_checkpoint(deps: Deps) -> Result Result { - Ok(Response::new()) +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) } #[cfg(test)] diff --git a/contracts/hooks/pausable/Cargo.toml b/contracts/hooks/pausable/Cargo.toml index bccbe23c..47ab6e02 100644 --- a/contracts/hooks/pausable/Cargo.toml +++ b/contracts/hooks/pausable/Cargo.toml @@ -32,6 +32,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-pausable.workspace = true hpl-interface.workspace = true diff --git a/contracts/hooks/pausable/src/lib.rs b/contracts/hooks/pausable/src/lib.rs index 142a5d09..41db4260 100644 --- a/contracts/hooks/pausable/src/lib.rs +++ b/contracts/hooks/pausable/src/lib.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure, Deps, DepsMut, Env, Event, MessageInfo, QueryResponse, Response, StdError, + ensure, Deps, DepsMut, Empty, Env, Event, MessageInfo, QueryResponse, Response, StdError, }; use hpl_interface::{ hook::{ @@ -19,6 +19,9 @@ pub enum ContractError { #[error("{0}")] PaymentError(#[from] cw_utils::PaymentError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, @@ -99,6 +102,12 @@ fn quote_dispatch() -> Result { Ok(QuoteDispatchResponse { fees: vec![] }) } +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} + #[cfg(test)] mod test { use cosmwasm_schema::serde::{de::DeserializeOwned, Serialize}; diff --git a/contracts/hooks/routing-custom/Cargo.toml b/contracts/hooks/routing-custom/Cargo.toml index 638bd2ab..67abfe95 100644 --- a/contracts/hooks/routing-custom/Cargo.toml +++ b/contracts/hooks/routing-custom/Cargo.toml @@ -32,6 +32,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-router.workspace = true hpl-interface.workspace = true diff --git a/contracts/hooks/routing-custom/src/lib.rs b/contracts/hooks/routing-custom/src/lib.rs index 70a5b03e..1a355a7b 100644 --- a/contracts/hooks/routing-custom/src/lib.rs +++ b/contracts/hooks/routing-custom/src/lib.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure_eq, wasm_execute, Addr, Deps, DepsMut, Env, Event, HexBinary, MessageInfo, + ensure_eq, wasm_execute, Addr, Deps, DepsMut, Empty, Env, Event, HexBinary, MessageInfo, QueryResponse, Response, StdError, StdResult, Storage, }; @@ -29,6 +29,9 @@ pub enum ContractError { #[error("{0}")] PaymentError(#[from] cw_utils::PaymentError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, @@ -312,6 +315,12 @@ fn quote_dispatch( Ok(resp) } +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} + #[cfg(test)] mod test { use cosmwasm_std::{ diff --git a/contracts/hooks/routing-fallback/Cargo.toml b/contracts/hooks/routing-fallback/Cargo.toml index 2d2eca20..923e799a 100644 --- a/contracts/hooks/routing-fallback/Cargo.toml +++ b/contracts/hooks/routing-fallback/Cargo.toml @@ -32,6 +32,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-router.workspace = true hpl-interface.workspace = true diff --git a/contracts/hooks/routing-fallback/src/lib.rs b/contracts/hooks/routing-fallback/src/lib.rs index 0fd4ad46..97ef08f2 100644 --- a/contracts/hooks/routing-fallback/src/lib.rs +++ b/contracts/hooks/routing-fallback/src/lib.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure_eq, wasm_execute, Addr, Deps, DepsMut, Env, Event, HexBinary, MessageInfo, + ensure_eq, wasm_execute, Addr, Deps, DepsMut, Empty, Env, Event, HexBinary, MessageInfo, QueryResponse, Response, StdError, Storage, }; @@ -25,6 +25,9 @@ pub enum ContractError { #[error("{0}")] PaymentError(#[from] cw_utils::PaymentError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, } @@ -154,6 +157,12 @@ pub fn quote_dispatch( Ok(resp) } +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} + #[cfg(test)] mod test { use cosmwasm_std::{ diff --git a/contracts/hooks/routing/Cargo.toml b/contracts/hooks/routing/Cargo.toml index 6a6c8b39..ba2287cc 100644 --- a/contracts/hooks/routing/Cargo.toml +++ b/contracts/hooks/routing/Cargo.toml @@ -32,6 +32,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-router.workspace = true hpl-interface.workspace = true diff --git a/contracts/hooks/routing/src/lib.rs b/contracts/hooks/routing/src/lib.rs index dd4651f3..341c90c5 100644 --- a/contracts/hooks/routing/src/lib.rs +++ b/contracts/hooks/routing/src/lib.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - wasm_execute, Addr, Deps, DepsMut, Env, Event, HexBinary, MessageInfo, QueryResponse, Response, - StdError, Storage, + wasm_execute, Addr, Deps, DepsMut, Empty, Env, Event, HexBinary, MessageInfo, QueryResponse, + Response, StdError, Storage, }; use hpl_interface::{ @@ -23,6 +23,9 @@ pub enum ContractError { #[error("{0}")] PaymentError(#[from] cw_utils::PaymentError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, @@ -135,6 +138,12 @@ fn post_dispatch( )) } +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} + #[cfg(test)] mod test { use cosmwasm_std::{ diff --git a/contracts/igps/core/Cargo.toml b/contracts/igps/core/Cargo.toml index 0e4548bc..14caa04f 100644 --- a/contracts/igps/core/Cargo.toml +++ b/contracts/igps/core/Cargo.toml @@ -33,6 +33,7 @@ schemars.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-router.workspace = true hpl-interface.workspace = true diff --git a/contracts/igps/core/src/contract.rs b/contracts/igps/core/src/contract.rs index 225b794f..097be3ee 100644 --- a/contracts/igps/core/src/contract.rs +++ b/contracts/igps/core/src/contract.rs @@ -135,6 +135,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Result { - Ok(Response::new()) +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) } diff --git a/contracts/igps/core/src/error.rs b/contracts/igps/core/src/error.rs index 267149d4..662a87f5 100644 --- a/contracts/igps/core/src/error.rs +++ b/contracts/igps/core/src/error.rs @@ -11,6 +11,9 @@ pub enum ContractError { #[error("{0}")] ParseIntError(#[from] std::num::ParseIntError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, diff --git a/contracts/igps/oracle/Cargo.toml b/contracts/igps/oracle/Cargo.toml index 3b5bed51..712bf850 100644 --- a/contracts/igps/oracle/Cargo.toml +++ b/contracts/igps/oracle/Cargo.toml @@ -30,6 +30,7 @@ schemars.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-interface.workspace = true diff --git a/contracts/igps/oracle/src/contract.rs b/contracts/igps/oracle/src/contract.rs index f9ef1d5c..464a76f4 100644 --- a/contracts/igps/oracle/src/contract.rs +++ b/contracts/igps/oracle/src/contract.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure, ensure_eq, to_json_binary, Deps, DepsMut, Env, Event, MessageInfo, QueryResponse, - Response, + ensure, ensure_eq, to_json_binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, + QueryResponse, Response, }; use hpl_interface::igp::oracle::{ @@ -98,3 +98,9 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} diff --git a/contracts/igps/oracle/src/error.rs b/contracts/igps/oracle/src/error.rs index 1dd46ab6..1c5449f3 100644 --- a/contracts/igps/oracle/src/error.rs +++ b/contracts/igps/oracle/src/error.rs @@ -6,6 +6,9 @@ pub enum ContractError { #[error("{0}")] Std(#[from] StdError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, diff --git a/contracts/isms/aggregate/Cargo.toml b/contracts/isms/aggregate/Cargo.toml index e5c9f663..9c7e4443 100644 --- a/contracts/isms/aggregate/Cargo.toml +++ b/contracts/isms/aggregate/Cargo.toml @@ -34,6 +34,7 @@ schemars.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-interface.workspace = true diff --git a/contracts/isms/aggregate/src/error.rs b/contracts/isms/aggregate/src/error.rs index 6bc64a01..c6ce9495 100644 --- a/contracts/isms/aggregate/src/error.rs +++ b/contracts/isms/aggregate/src/error.rs @@ -9,6 +9,9 @@ pub enum ContractError { #[error("{0}")] VerificationError(#[from] VerificationError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized, diff --git a/contracts/isms/aggregate/src/lib.rs b/contracts/isms/aggregate/src/lib.rs index 44f4ec94..0d398486 100644 --- a/contracts/isms/aggregate/src/lib.rs +++ b/contracts/isms/aggregate/src/lib.rs @@ -171,6 +171,7 @@ fn verify_info(deps: Deps, _message: HexBinary) -> Result Result { +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; Ok(Response::default()) } diff --git a/contracts/isms/multisig/Cargo.toml b/contracts/isms/multisig/Cargo.toml index 2c68489d..68978350 100644 --- a/contracts/isms/multisig/Cargo.toml +++ b/contracts/isms/multisig/Cargo.toml @@ -34,6 +34,7 @@ schemars.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-interface.workspace = true diff --git a/contracts/isms/multisig/src/contract.rs b/contracts/isms/multisig/src/contract.rs index 6741189d..1d2aaea2 100644 --- a/contracts/isms/multisig/src/contract.rs +++ b/contracts/isms/multisig/src/contract.rs @@ -134,19 +134,15 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Result { - Ok(Response::new()) +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) } #[cfg(test)] mod test { - use cosmwasm_std::{ - testing::mock_dependencies, HexBinary, - }; - use hpl_interface::{ - build_test_executor, build_test_querier, - ism::multisig::ExecuteMsg, - }; + use cosmwasm_std::{testing::mock_dependencies, HexBinary}; + use hpl_interface::{build_test_executor, build_test_querier, ism::multisig::ExecuteMsg}; use ibcx_test_utils::{addr, hex}; use rstest::rstest; @@ -204,7 +200,7 @@ mod test { test_execute( deps.as_mut(), &addr(sender), - ExecuteMsg::UnsetDomain { domain: 1 } , + ExecuteMsg::UnsetDomain { domain: 1 }, vec![], ); diff --git a/contracts/isms/multisig/src/error.rs b/contracts/isms/multisig/src/error.rs index 7ccf0159..c0fd54f4 100644 --- a/contracts/isms/multisig/src/error.rs +++ b/contracts/isms/multisig/src/error.rs @@ -12,6 +12,9 @@ pub enum ContractError { #[error("{0}")] RecoverPubkeyError(#[from] RecoverPubkeyError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized, diff --git a/contracts/isms/pausable/Cargo.toml b/contracts/isms/pausable/Cargo.toml index 41cef4a1..6a1259df 100644 --- a/contracts/isms/pausable/Cargo.toml +++ b/contracts/isms/pausable/Cargo.toml @@ -32,6 +32,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-ownable.workspace = true hpl-pausable.workspace = true hpl-interface.workspace = true diff --git a/contracts/isms/pausable/src/lib.rs b/contracts/isms/pausable/src/lib.rs index 16b82b85..3f6a8611 100644 --- a/contracts/isms/pausable/src/lib.rs +++ b/contracts/isms/pausable/src/lib.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure, to_json_binary, Deps, DepsMut, Env, Event, MessageInfo, QueryResponse, Response, + ensure, to_json_binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, QueryResponse, Response, StdError, }; use hpl_interface::ism::{ @@ -17,6 +17,9 @@ pub enum ContractError { #[error("{0}")] PaymentError(#[from] cw_utils::PaymentError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized {}, @@ -90,6 +93,12 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} + #[cfg(test)] mod test { use cosmwasm_std::{ diff --git a/contracts/isms/routing/Cargo.toml b/contracts/isms/routing/Cargo.toml index 62f56ffa..640465da 100644 --- a/contracts/isms/routing/Cargo.toml +++ b/contracts/isms/routing/Cargo.toml @@ -34,6 +34,7 @@ schemars.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-interface.workspace = true hpl-ownable.workspace = true diff --git a/contracts/isms/routing/src/contract.rs b/contracts/isms/routing/src/contract.rs index 3cb2e23a..bba8f9af 100644 --- a/contracts/isms/routing/src/contract.rs +++ b/contracts/isms/routing/src/contract.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure_eq, to_json_binary, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, + ensure_eq, to_json_binary, Deps, DepsMut, Empty, Env, MessageInfo, QueryResponse, Response, }; use cw2::set_contract_version; use hpl_interface::{ @@ -150,3 +150,9 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} diff --git a/contracts/isms/routing/src/error.rs b/contracts/isms/routing/src/error.rs index 230ddb81..d46a7cb3 100644 --- a/contracts/isms/routing/src/error.rs +++ b/contracts/isms/routing/src/error.rs @@ -9,6 +9,9 @@ pub enum ContractError { #[error("{0}")] VerificationError(#[from] VerificationError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("Unauthorized")] Unauthorized, diff --git a/contracts/mocks/mock-hook/Cargo.toml b/contracts/mocks/mock-hook/Cargo.toml index bb22f71d..e1da4c2a 100644 --- a/contracts/mocks/mock-hook/Cargo.toml +++ b/contracts/mocks/mock-hook/Cargo.toml @@ -26,6 +26,7 @@ cosmwasm-schema.workspace = true cw2.workspace = true cw-storage-plus.workspace = true +hpl-utils.workspace = true hpl-interface.workspace = true [dev-dependencies] diff --git a/contracts/mocks/mock-hook/src/contract.rs b/contracts/mocks/mock-hook/src/contract.rs index 86096802..d509ed15 100644 --- a/contracts/mocks/mock-hook/src/contract.rs +++ b/contracts/mocks/mock-hook/src/contract.rs @@ -2,7 +2,7 @@ use cosmwasm_schema::cw_serde; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - coins, to_json_binary, Deps, DepsMut, Env, Event, MessageInfo, QueryResponse, Response, + coins, to_json_binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, QueryResponse, Response, StdError, StdResult, Uint256, }; use cw2::set_contract_version; @@ -113,6 +113,12 @@ pub fn query(deps: Deps, _env: Env, msg: ExpectedHookQueryMsg) -> StdResult StdResult { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION).unwrap(); + Ok(Response::default()) +} + #[cfg(test)] mod test { use cosmwasm_std::{from_json, to_json_binary, HexBinary}; diff --git a/contracts/mocks/mock-ism/Cargo.toml b/contracts/mocks/mock-ism/Cargo.toml index 439401cb..54a27ec1 100644 --- a/contracts/mocks/mock-ism/Cargo.toml +++ b/contracts/mocks/mock-ism/Cargo.toml @@ -34,6 +34,7 @@ schemars.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-interface.workspace = true [dev-dependencies] diff --git a/contracts/mocks/mock-ism/src/contract.rs b/contracts/mocks/mock-ism/src/contract.rs index d57ebee8..44959ec6 100644 --- a/contracts/mocks/mock-ism/src/contract.rs +++ b/contracts/mocks/mock-ism/src/contract.rs @@ -2,7 +2,7 @@ use cosmwasm_schema::cw_serde; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - to_json_binary, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, StdResult, + to_json_binary, Deps, DepsMut, Empty, Env, MessageInfo, QueryResponse, Response, StdResult, }; use cw2::set_contract_version; use hpl_interface::ism::{ @@ -32,11 +32,6 @@ pub fn instantiate( Ok(Response::new().add_attribute("method", "instantiate")) } -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult { - Ok(Response::default()) -} - /// Handling contract execution #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( @@ -64,3 +59,9 @@ pub fn query(_deps: Deps, _env: Env, msg: ExpectedIsmQueryMsg) -> StdResult StdResult { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION).unwrap(); + Ok(Response::default()) +} diff --git a/contracts/mocks/mock-msg-receiver/Cargo.toml b/contracts/mocks/mock-msg-receiver/Cargo.toml index 080b4d15..c1c7e0ce 100644 --- a/contracts/mocks/mock-msg-receiver/Cargo.toml +++ b/contracts/mocks/mock-msg-receiver/Cargo.toml @@ -34,6 +34,7 @@ schemars.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-interface.workspace = true [dev-dependencies] diff --git a/contracts/mocks/mock-msg-receiver/src/contract.rs b/contracts/mocks/mock-msg-receiver/src/contract.rs index 4f916778..9c30cbff 100644 --- a/contracts/mocks/mock-msg-receiver/src/contract.rs +++ b/contracts/mocks/mock-msg-receiver/src/contract.rs @@ -75,6 +75,7 @@ pub fn query( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(_deps: DepsMut, _env: Env, _msg: Empty) -> StdResult { +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> StdResult { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION).unwrap(); Ok(Response::default()) } diff --git a/contracts/warp/cw20/Cargo.toml b/contracts/warp/cw20/Cargo.toml index 10cbe744..3f64cf10 100644 --- a/contracts/warp/cw20/Cargo.toml +++ b/contracts/warp/cw20/Cargo.toml @@ -38,6 +38,7 @@ schemars.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-connection.workspace = true hpl-ownable.workspace = true hpl-router.workspace = true diff --git a/contracts/warp/cw20/src/contract.rs b/contracts/warp/cw20/src/contract.rs index c2f8b56c..503b2a28 100644 --- a/contracts/warp/cw20/src/contract.rs +++ b/contracts/warp/cw20/src/contract.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - ensure_eq, to_json_binary, wasm_execute, CosmosMsg, Deps, DepsMut, Env, HexBinary, MessageInfo, - QueryResponse, Reply, Response, StdError, SubMsg, Uint128, Uint256, WasmMsg, + ensure_eq, to_json_binary, wasm_execute, CosmosMsg, Deps, DepsMut, Empty, Env, HexBinary, + MessageInfo, QueryResponse, Reply, Response, StdError, SubMsg, Uint128, Uint256, WasmMsg, }; use cw20::Cw20ExecuteMsg; @@ -101,7 +101,16 @@ pub fn execute( amount, hook, metadata, - } => transfer_remote(deps, env, info, dest_domain, recipient, amount, hook, metadata), + } => transfer_remote( + deps, + env, + info, + dest_domain, + recipient, + amount, + hook, + metadata, + ), } } @@ -172,6 +181,7 @@ fn mailbox_handle( )) } +#[allow(clippy::too_many_arguments)] fn transfer_remote( deps: DepsMut, env: Env, @@ -192,7 +202,7 @@ fn transfer_remote( // validate hook if present if let Some(ref custom_hook) = hook { - let _ = deps.api.addr_validate(&custom_hook)?; + let _ = deps.api.addr_validate(custom_hook)?; } let mut msgs: Vec = vec![]; @@ -278,6 +288,12 @@ fn get_token_mode(deps: Deps) -> Result { Ok(TokenModeResponse { mode }) } +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) +} + #[cfg(test)] mod test { use cosmwasm_std::{ @@ -582,7 +598,8 @@ mod test { custom_hook.map(|h| h.to_string()), custom_metadata, vec![], - ).unwrap(); + ) + .unwrap(); match token_mode { TokenModeMsg::Bridged(_) => { diff --git a/contracts/warp/cw20/src/error.rs b/contracts/warp/cw20/src/error.rs index fc498fa4..e032ab88 100644 --- a/contracts/warp/cw20/src/error.rs +++ b/contracts/warp/cw20/src/error.rs @@ -9,6 +9,9 @@ pub enum ContractError { #[error("{0}")] ParseReplyError(#[from] cw_utils::ParseReplyError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized, diff --git a/contracts/warp/native/Cargo.toml b/contracts/warp/native/Cargo.toml index f621ef34..059eb36f 100644 --- a/contracts/warp/native/Cargo.toml +++ b/contracts/warp/native/Cargo.toml @@ -39,6 +39,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true +hpl-utils.workspace = true hpl-connection.workspace = true hpl-ownable.workspace = true hpl-router.workspace = true diff --git a/contracts/warp/native/src/contract.rs b/contracts/warp/native/src/contract.rs index 0981bf99..ef6c234f 100644 --- a/contracts/warp/native/src/contract.rs +++ b/contracts/warp/native/src/contract.rs @@ -105,7 +105,16 @@ pub fn execute( amount, hook, metadata, - } => transfer_remote(deps, env, info, dest_domain, recipient, amount, hook, metadata), + } => transfer_remote( + deps, + env, + info, + dest_domain, + recipient, + amount, + hook, + metadata, + ), } } @@ -185,6 +194,7 @@ fn mailbox_handle( )) } +#[allow(clippy::too_many_arguments)] fn transfer_remote( deps: DepsMut, env: Env, @@ -219,7 +229,7 @@ fn transfer_remote( // validate hook if present if let Some(ref custom_hook) = hook { - let _ = deps.api.addr_validate(&custom_hook)?; + let _ = deps.api.addr_validate(custom_hook)?; } let mut msgs: Vec = vec![]; @@ -292,8 +302,9 @@ fn get_token_mode(deps: Deps) -> Result { } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(_deps: DepsMut, _env: Env, _msg: Empty) -> Result { - Ok(Response::new()) +pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result { + hpl_utils::migrate(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) } #[cfg(test)] diff --git a/contracts/warp/native/src/error.rs b/contracts/warp/native/src/error.rs index 18dd1b41..58c74c6a 100644 --- a/contracts/warp/native/src/error.rs +++ b/contracts/warp/native/src/error.rs @@ -12,6 +12,9 @@ pub enum ContractError { #[error("{0}")] RecoverPubkeyError(#[from] RecoverPubkeyError), + #[error("{0}")] + MigrationError(#[from] hpl_utils::MigrationError), + #[error("unauthorized")] Unauthorized, diff --git a/packages/utils/Cargo.toml b/packages/utils/Cargo.toml new file mode 100644 index 00000000..2958d279 --- /dev/null +++ b/packages/utils/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "hpl-utils" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +documentation.workspace = true +keywords.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[dependencies] +semver.workspace = true +cosmwasm-std.workspace = true +cw2.workspace = true +thiserror.workspace = true diff --git a/packages/utils/src/lib.rs b/packages/utils/src/lib.rs new file mode 100644 index 00000000..f7820124 --- /dev/null +++ b/packages/utils/src/lib.rs @@ -0,0 +1,74 @@ +use cosmwasm_std::{ensure_eq, StdError, Storage}; +use semver::Version; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum MigrationError { + #[error("{0}")] + StdError(#[from] StdError), + + #[error("Semver parsing error: {0}")] + SemVer(String), +} + +impl From for MigrationError { + fn from(err: semver::Error) -> Self { + Self::SemVer(err.to_string()) + } +} + +pub fn migrate( + storage: &mut dyn Storage, + contract_name: &str, + contract_version: &str, +) -> Result<(), MigrationError> { + let stored = cw2::get_contract_version(storage)?; + + ensure_eq!( + stored.contract, + contract_name, + StdError::generic_err("contract name mismatch") + ); + + let version: Version = contract_version.parse()?; + let stored_version: Version = stored.version.parse()?; + + if stored_version < version { + Ok(cw2::set_contract_version( + storage, + contract_name, + contract_version, + )?) + } else { + Err(StdError::generic_err("invalid version").into()) + } +} + +#[cfg(test)] +mod test { + use cosmwasm_std::{testing::mock_dependencies, StdError, Storage}; + + use crate::migrate; + + fn assert_version(storage: &dyn Storage, contract: &str, version: &str) { + let stored = cw2::get_contract_version(storage).unwrap(); + + assert_eq!(stored.contract, contract); + assert_eq!(stored.version, version); + } + + #[test] + fn test_migrate() { + let mut deps = mock_dependencies(); + cw2::set_contract_version(&mut deps.storage, "hello", "0.0.6-rc8").unwrap(); + + migrate(&mut deps.storage, "nono", "0.0.6-rc8") + .expect_err(&StdError::generic_err("contract name mismatch").to_string()); + + migrate(&mut deps.storage, "hello", "0.0.5") + .expect_err(&StdError::generic_err("invalid version").to_string()); + + migrate(&mut deps.storage, "hello", "0.0.6").unwrap(); + assert_version(&deps.storage, "hello", "0.0.6"); + } +}