From 61a2c0711a3b761318577b60cb1319718fea2627 Mon Sep 17 00:00:00 2001 From: Markus Waas Date: Sat, 24 Feb 2024 16:36:29 -0600 Subject: [PATCH] feat: add contract migration system --- Cargo.lock | 51 ++++++++++++++++--------------- contracts/swap/Cargo.toml | 5 +-- contracts/swap/src/admin.rs | 2 ++ contracts/swap/src/contract.rs | 56 ++++++++++++++++++++++++++++++++-- contracts/swap/src/error.rs | 5 ++- contracts/swap/src/helpers.rs | 27 ++++++++++++++-- contracts/swap/src/msg.rs | 3 ++ contracts/swap/src/state.rs | 6 ++++ 8 files changed, 122 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdbec18..5946dff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1311,31 +1311,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "injective-converter" -version = "1.0.0" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cosmwasm-storage", - "cw-multi-test", - "cw-storage-plus 0.14.0", - "cw-utils 0.14.0", - "cw2 0.14.0", - "injective-cosmwasm", - "injective-math", - "injective-protobuf", - "injective-std", - "injective-test-tube", - "num-traits", - "prost 0.11.9", - "protobuf", - "schemars", - "serde", - "serde-json-wasm", - "thiserror", -] - [[package]] name = "injective-cosmwasm" version = "0.2.18" @@ -2389,6 +2364,32 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" +[[package]] +name = "swap-contract" +version = "1.1.0" +dependencies = [ + "cosmos-sdk-proto", + "cosmwasm-schema", + "cosmwasm-std", + "cosmwasm-storage", + "cw-multi-test", + "cw-storage-plus 0.14.0", + "cw-utils 0.14.0", + "cw2 0.14.0", + "injective-cosmwasm", + "injective-math", + "injective-protobuf", + "injective-std", + "injective-test-tube", + "num-traits", + "prost 0.11.9", + "protobuf", + "schemars", + "serde", + "serde-json-wasm", + "thiserror", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/contracts/swap/Cargo.toml b/contracts/swap/Cargo.toml index d9d0327..9e01aaf 100644 --- a/contracts/swap/Cargo.toml +++ b/contracts/swap/Cargo.toml @@ -1,8 +1,8 @@ [package] authors = [ "Markus Waas " ] edition = "2021" -name = "injective-converter" -version = "1.0.0" +name = "swap-contract" +version = "1.1.0" exclude = [ # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. @@ -45,6 +45,7 @@ serde-json-wasm = "0.5.1" thiserror = { version = "1.0.31" } [dev-dependencies] +cosmos-sdk-proto = { version = "0.19.0", default-features = false } cosmwasm-schema = "1.5.0" cw-multi-test = "0.16.2" injective-std = { version = "0.1.5" } diff --git a/contracts/swap/src/admin.rs b/contracts/swap/src/admin.rs index 79f8a98..1289aa6 100644 --- a/contracts/swap/src/admin.rs +++ b/contracts/swap/src/admin.rs @@ -24,6 +24,8 @@ pub fn save_config( fee_recipient, admin, }; + config.to_owned().validate()?; + CONFIG.save(deps.storage, &config) } diff --git a/contracts/swap/src/contract.rs b/contracts/swap/src/contract.rs index 6592215..aa54ca8 100644 --- a/contracts/swap/src/contract.rs +++ b/contracts/swap/src/contract.rs @@ -6,18 +6,18 @@ use cosmwasm_std::{ use cw2::{get_contract_version, set_contract_version}; use crate::admin::{delete_route, save_config, set_route, update_config, withdraw_support_funds}; +use crate::helpers::handle_config_migration; use crate::types::{ConfigResponse, SwapQuantityMode}; use injective_cosmwasm::{InjectiveMsgWrapper, InjectiveQueryWrapper}; use crate::error::ContractError; -use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; use crate::queries::{estimate_swap_result, SwapQuantity}; use crate::state::{get_all_swap_routes, get_config, read_swap_route}; use crate::swap::{handle_atomic_order_reply, start_swap_flow}; -// version info for migration info -pub const CONTRACT_NAME: &str = "crates.io:atomic-order-example"; +pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const ATOMIC_ORDER_REPLY_ID: u64 = 1u64; @@ -32,6 +32,7 @@ pub fn instantiate( ) -> Result, ContractError> { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; save_config(deps, env, msg.admin, msg.fee_recipient)?; + Ok(Response::new() .add_attribute("method", "instantiate") .add_attribute("owner", info.sender)) @@ -98,6 +99,55 @@ pub fn reply( } } +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate( + deps: DepsMut, + _env: Env, + _msg: MigrateMsg, +) -> Result { + let contract_version = get_contract_version(deps.storage)?; + + match contract_version.contract.as_ref() { + // old contract name + "crates.io:atomic-order-example" => match contract_version.version.as_ref() { + "0.1.0" => { + unimplemented!( + "Migration from version {} is no longer supported", + contract_version.version + ); + } + "1.0.0" => { + deps.api.debug("BBB"); + + set_contract_version( + deps.storage, + format!("crates.io:{CONTRACT_NAME}"), + CONTRACT_VERSION, + )?; + + handle_config_migration(deps)?; + } + _ => return Err(ContractError::MigrationError {}), + }, + "crates.io:swap-contract" => match contract_version.version.as_ref() { + "1.0.1" => { + unimplemented!( + "Migration from version {} is no yet supported", + contract_version.version + ); + } + _ => return Err(ContractError::MigrationError {}), + }, + _ => return Err(ContractError::MigrationError {}), + } + + Ok(Response::new() + .add_attribute("previous_contract_name", &contract_version.contract) + .add_attribute("previous_contract_version", &contract_version.version) + .add_attribute("new_contract_name", format!("crates.io:{CONTRACT_NAME}")) + .add_attribute("new_contract_version", CONTRACT_VERSION)) +} + #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { match msg { diff --git a/contracts/swap/src/error.rs b/contracts/swap/src/error.rs index f9b18cf..a0037db 100644 --- a/contracts/swap/src/error.rs +++ b/contracts/swap/src/error.rs @@ -16,7 +16,7 @@ pub enum ContractError { #[error("Failure response from submsg: {0}")] SubMsgFailure(String), - #[error("Unrecognised reply id: {0}")] + #[error("Unrecognized reply id: {0}")] UnrecognizedReply(u64), #[error("Invalid reply from sub-message {id}, {err}")] @@ -27,4 +27,7 @@ pub enum ContractError { #[error("Provided amount of {0} is below required amount of {1}")] InsufficientFundsProvided(FPDecimal, FPDecimal), + + #[error("Contract can't be migrated")] + MigrationError {}, } diff --git a/contracts/swap/src/helpers.rs b/contracts/swap/src/helpers.rs index 27d8f17..498bedc 100644 --- a/contracts/swap/src/helpers.rs +++ b/contracts/swap/src/helpers.rs @@ -1,8 +1,11 @@ -use cosmwasm_std::{CosmosMsg, SubMsg}; +use cosmwasm_std::{CosmosMsg, DepsMut, Response, SubMsg}; -use injective_cosmwasm::InjectiveMsgWrapper; +use cw_storage_plus::Item; +use injective_cosmwasm::{InjectiveMsgWrapper, InjectiveQueryWrapper}; use injective_math::FPDecimal; +use crate::{state::CONFIG, types::Config, ContractError}; + pub fn i32_to_dec(source: i32) -> FPDecimal { FPDecimal::from(i128::from(source)) } @@ -49,6 +52,26 @@ pub fn dec_scale_factor() -> FPDecimal { FPDecimal::ONE.scaled(18) } +type V100Config = Config; +const V100CONFIG: Item = Item::new("config"); + +pub fn handle_config_migration( + deps: DepsMut, +) -> Result { + let v100_config = V100CONFIG.load(deps.storage)?; + + let config = Config { + fee_recipient: v100_config.fee_recipient, + admin: v100_config.admin, + }; + + CONFIG.save(deps.storage, &config)?; + + config.validate()?; + + Ok(Response::default()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/contracts/swap/src/msg.rs b/contracts/swap/src/msg.rs index f0c841e..37590b7 100644 --- a/contracts/swap/src/msg.rs +++ b/contracts/swap/src/msg.rs @@ -18,6 +18,9 @@ pub struct InstantiateMsg { pub admin: Addr, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct MigrateMsg {} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { diff --git a/contracts/swap/src/state.rs b/contracts/swap/src/state.rs index bc90154..bcc85a2 100644 --- a/contracts/swap/src/state.rs +++ b/contracts/swap/src/state.rs @@ -9,6 +9,12 @@ pub const STEP_STATE: Item = Item::new("current_step_cache"); pub const SWAP_RESULTS: Item> = Item::new("swap_results"); pub const CONFIG: Item = Item::new("config"); +impl Config { + pub fn validate(self) -> StdResult<()> { + Ok(()) + } +} + pub fn store_swap_route(storage: &mut dyn Storage, route: &SwapRoute) -> StdResult<()> { let key = route_key(&route.source_denom, &route.target_denom); SWAP_ROUTES.save(storage, key, route)