From 3cbbc6f2b81bf90358dcef1d5ff61f89b600fbdb Mon Sep 17 00:00:00 2001 From: Reisen Date: Mon, 6 Sep 2021 08:27:27 +0000 Subject: [PATCH] terra/contracts: columbus-5 migration for cw20-wrapped Change-Id: I32a703cdeb60dcf288907df6318ae504171fc5f0 --- terra/contracts-5/cw20-wrapped/Cargo.toml | 1 + .../contracts-5/cw20-wrapped/src/contract.rs | 283 +++++++++--------- terra/contracts-5/cw20-wrapped/src/lib.rs | 6 +- terra/contracts-5/cw20-wrapped/src/msg.rs | 14 +- terra/contracts-5/cw20-wrapped/src/state.rs | 9 +- 5 files changed, 164 insertions(+), 149 deletions(-) diff --git a/terra/contracts-5/cw20-wrapped/Cargo.toml b/terra/contracts-5/cw20-wrapped/Cargo.toml index c342d6f8..f35f2042 100644 --- a/terra/contracts-5/cw20-wrapped/Cargo.toml +++ b/terra/contracts-5/cw20-wrapped/Cargo.toml @@ -18,6 +18,7 @@ cosmwasm-std = { version = "0.16.0" } cosmwasm-storage = { version = "0.16.0" } schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } +cw2 = { version = "0.8.0" } cw20 = { version = "0.8.0" } cw20-legacy = { version = "0.2.0", features = ["library"]} cw-storage-plus = { version = "0.8.0" } diff --git a/terra/contracts-5/cw20-wrapped/src/contract.rs b/terra/contracts-5/cw20-wrapped/src/contract.rs index 4c053b77..528af955 100644 --- a/terra/contracts-5/cw20-wrapped/src/contract.rs +++ b/terra/contracts-5/cw20-wrapped/src/contract.rs @@ -1,48 +1,47 @@ use cosmwasm_std::{ + entry_point, to_binary, - Api, Binary, CosmosMsg, + Deps, + DepsMut, Env, - Extern, - HandleResponse, - HumanAddr, - InitResponse, - Querier, + MessageInfo, + Response, StdError, StdResult, - Storage, Uint128, WasmMsg, }; -use cw20_base::{ +use cw2::set_contract_version; +use cw20_legacy::{ allowances::{ - handle_burn_from, - handle_decrease_allowance, - handle_increase_allowance, - handle_send_from, - handle_transfer_from, + execute_burn_from, + execute_decrease_allowance, + execute_increase_allowance, + execute_send_from, + execute_transfer_from, query_allowance, }, contract::{ - handle_mint, - handle_send, - handle_transfer, + execute_mint, + execute_send, + execute_transfer, query_balance, }, state::{ - token_info, - token_info_read, MinterData, TokenInfo, + TOKEN_INFO, }, + ContractError, }; use crate::{ msg::{ - HandleMsg, - InitMsg, + ExecuteMsg, + InstantiateMsg, QueryMsg, WrappedAssetInfoResponse, }, @@ -55,116 +54,136 @@ use crate::{ use cw20::TokenInfoResponse; use std::string::String; -pub fn init( - deps: &mut Extern, +type HumanAddr = String; + +// version info for migration info +const CONTRACT_NAME: &str = "crates.io:cw20-base"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, env: Env, - msg: InitMsg, -) -> StdResult { + info: MessageInfo, + msg: InstantiateMsg, +) -> StdResult { + set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + // store token info using cw20-base format let data = TokenInfo { name: msg.name, symbol: msg.symbol, decimals: msg.decimals, - total_supply: Uint128(0), + total_supply: Uint128::new(0), // set creator as minter mint: Some(MinterData { - minter: deps.api.canonical_address(&env.message.sender)?, + minter: deps.api.addr_canonicalize(&info.sender.as_str())?, cap: None, }), }; - token_info(&mut deps.storage).save(&data)?; + TOKEN_INFO.save(deps.storage, &data)?; // save wrapped asset info let data = WrappedAssetInfo { asset_chain: msg.asset_chain, asset_address: msg.asset_address, - bridge: deps.api.canonical_address(&env.message.sender)?, + bridge: deps.api.addr_canonicalize(&info.sender.as_str())?, }; - wrapped_asset_info(&mut deps.storage).save(&data)?; + wrapped_asset_info(deps.storage).save(&data)?; if let Some(mint_info) = msg.mint { - handle_mint(deps, env, mint_info.recipient, mint_info.amount)?; + execute_mint(deps, env, info, mint_info.recipient, mint_info.amount) + .map_err(|e| StdError::generic_err(format!("{}", e)))?; } if let Some(hook) = msg.init_hook { - Ok(InitResponse { - messages: vec![CosmosMsg::Wasm(WasmMsg::Execute { + Ok( + Response::new().add_message(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: hook.contract_addr, msg: hook.msg, - send: vec![], - })], - log: vec![], - }) + funds: vec![], + })), + ) } else { - Ok(InitResponse::default()) + Ok(Response::default()) } } -pub fn handle( - deps: &mut Extern, +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, env: Env, - msg: HandleMsg, -) -> StdResult { + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { match msg { // these all come from cw20-base to implement the cw20 standard - HandleMsg::Transfer { recipient, amount } => { - Ok(handle_transfer(deps, env, recipient, amount)?) + ExecuteMsg::Transfer { recipient, amount } => { + Ok(execute_transfer(deps, env, info, recipient, amount)?) } - HandleMsg::Burn { account, amount } => Ok(handle_burn_from(deps, env, account, amount)?), - HandleMsg::Send { + ExecuteMsg::Burn { account, amount } => { + Ok(execute_burn_from(deps, env, info, account, amount)?) + } + ExecuteMsg::Send { contract, amount, msg, - } => Ok(handle_send(deps, env, contract, amount, msg)?), - HandleMsg::Mint { recipient, amount } => handle_mint_wrapped(deps, env, recipient, amount), - HandleMsg::IncreaseAllowance { + } => Ok(execute_send(deps, env, info, contract, amount, msg)?), + ExecuteMsg::Mint { recipient, amount } => { + execute_mint_wrapped(deps, env, info, recipient, amount) + } + ExecuteMsg::IncreaseAllowance { spender, amount, expires, - } => Ok(handle_increase_allowance( - deps, env, spender, amount, expires, + } => Ok(execute_increase_allowance( + deps, env, info, spender, amount, expires, )?), - HandleMsg::DecreaseAllowance { + ExecuteMsg::DecreaseAllowance { spender, amount, expires, - } => Ok(handle_decrease_allowance( - deps, env, spender, amount, expires, + } => Ok(execute_decrease_allowance( + deps, env, info, spender, amount, expires, )?), - HandleMsg::TransferFrom { + ExecuteMsg::TransferFrom { owner, recipient, amount, - } => Ok(handle_transfer_from(deps, env, owner, recipient, amount)?), - HandleMsg::BurnFrom { owner, amount } => Ok(handle_burn_from(deps, env, owner, amount)?), - HandleMsg::SendFrom { + } => Ok(execute_transfer_from( + deps, env, info, owner, recipient, amount, + )?), + ExecuteMsg::BurnFrom { owner, amount } => { + Ok(execute_burn_from(deps, env, info, owner, amount)?) + } + ExecuteMsg::SendFrom { owner, contract, amount, msg, - } => Ok(handle_send_from(deps, env, owner, contract, amount, msg)?), + } => Ok(execute_send_from( + deps, env, info, owner, contract, amount, msg, + )?), } } -fn handle_mint_wrapped( - deps: &mut Extern, +fn execute_mint_wrapped( + deps: DepsMut, env: Env, + info: MessageInfo, recipient: HumanAddr, amount: Uint128, -) -> StdResult { +) -> Result { // Only bridge can mint - let wrapped_info = wrapped_asset_info_read(&deps.storage).load()?; - if wrapped_info.bridge != deps.api.canonical_address(&env.message.sender)? { - return Err(StdError::unauthorized()); + let wrapped_info = wrapped_asset_info_read(deps.storage).load()?; + if wrapped_info.bridge != deps.api.addr_canonicalize(&info.sender.as_str())? { + return Err(ContractError::Unauthorized {}); } - Ok(handle_mint(deps, env, recipient, amount)?) + Ok(execute_mint(deps, env, info, recipient, amount)?) } -pub fn query( - deps: &Extern, - msg: QueryMsg, -) -> StdResult { +pub fn query(deps: Deps, msg: QueryMsg) -> StdResult { match msg { QueryMsg::WrappedAssetInfo {} => to_binary(&query_wrapped_asset_info(deps)?), // inherited from cw20-base @@ -176,66 +195,58 @@ pub fn query( } } -pub fn query_token_info( - deps: &Extern, -) -> StdResult { - let info = token_info_read(&deps.storage).load()?; - let res = TokenInfoResponse { +pub fn query_token_info(deps: Deps) -> StdResult { + let info = TOKEN_INFO.load(deps.storage)?; + Ok(TokenInfoResponse { name: String::from("Wormhole:") + info.name.as_str(), symbol: String::from("wh") + info.symbol.as_str(), decimals: info.decimals, total_supply: info.total_supply, - }; - Ok(res) + }) } -pub fn query_wrapped_asset_info( - deps: &Extern, -) -> StdResult { - let info = wrapped_asset_info_read(&deps.storage).load()?; - let res = WrappedAssetInfoResponse { +pub fn query_wrapped_asset_info(deps: Deps) -> StdResult { + let info = wrapped_asset_info_read(deps.storage).load()?; + Ok(WrappedAssetInfoResponse { asset_chain: info.asset_chain, asset_address: info.asset_address, - bridge: deps.api.human_address(&info.bridge)?, - }; - Ok(res) + bridge: deps.api.addr_humanize(&info.bridge)?, + }) } #[cfg(test)] mod tests { use super::*; - use cosmwasm_std::{ - testing::{ - mock_dependencies, - mock_env, - }, - HumanAddr, + use cosmwasm_std::testing::{ + mock_dependencies, + mock_env, + mock_info, }; use cw20::TokenInfoResponse; const CANONICAL_LENGTH: usize = 20; - fn get_balance>( - deps: &Extern, - address: T, - ) -> Uint128 { - query_balance(&deps, address.into()).unwrap().balance + fn get_balance(deps: Deps, address: HumanAddr) -> Uint128 { + query_balance(deps, address.into()).unwrap().balance } - fn do_init(deps: &mut Extern, creator: &HumanAddr) { - let init_msg = InitMsg { + fn do_init(mut deps: DepsMut, creator: &HumanAddr) { + let init_msg = InstantiateMsg { + name: "Integers".to_string(), + symbol: "INT".to_string(), asset_chain: 1, asset_address: vec![1; 32].into(), decimals: 10, mint: None, init_hook: None, }; - let env = mock_env(creator, &[]); - let res = init(deps, env, init_msg).unwrap(); + let env = mock_env(); + let info = mock_info(creator, &[]); + let res = instantiate(deps, env, info, init_msg).unwrap(); assert_eq!(0, res.messages.len()); assert_eq!( - query_token_info(&deps).unwrap(), + query_token_info(deps.as_ref()).unwrap(), TokenInfoResponse { name: "Wormhole Wrapped".to_string(), symbol: "WWT".to_string(), @@ -245,35 +256,36 @@ mod tests { ); assert_eq!( - query_wrapped_asset_info(&deps).unwrap(), + query_wrapped_asset_info(deps.as_ref()).unwrap(), WrappedAssetInfoResponse { asset_chain: 1, asset_address: vec![1; 32].into(), - bridge: creator.clone(), + bridge: deps.api.addr_validate(creator).unwrap(), } ); } - fn do_init_and_mint( - deps: &mut Extern, + fn do_init_and_mint( + mut deps: DepsMut, creator: &HumanAddr, mint_to: &HumanAddr, amount: Uint128, ) { do_init(deps, creator); - let msg = HandleMsg::Mint { + let msg = ExecuteMsg::Mint { recipient: mint_to.clone(), amount, }; - let env = mock_env(&creator, &[]); - let res = handle(deps, env, msg.clone()).unwrap(); + let env = mock_env(); + let info = mock_info(creator, &[]); + let res = execute(deps.as_mut(), env, info, msg.clone()).unwrap(); assert_eq!(0, res.messages.len()); - assert_eq!(get_balance(deps, mint_to), amount); + assert_eq!(get_balance(deps.as_ref(), mint_to.clone(),), amount); assert_eq!( - query_token_info(&deps).unwrap(), + query_token_info(deps.as_ref()).unwrap(), TokenInfoResponse { name: "Wormhole Wrapped".to_string(), symbol: "WWT".to_string(), @@ -285,29 +297,30 @@ mod tests { #[test] fn can_mint_by_minter() { - let mut deps = mock_dependencies(CANONICAL_LENGTH, &[]); + let mut deps = mock_dependencies(&[]); let minter = HumanAddr::from("minter"); let recipient = HumanAddr::from("recipient"); - let amount = Uint128(222_222_222); - do_init_and_mint(&mut deps, &minter, &recipient, amount); + let amount = Uint128::new(222_222_222); + do_init_and_mint(deps.as_mut(), &minter, &recipient, amount); } #[test] fn others_cannot_mint() { - let mut deps = mock_dependencies(CANONICAL_LENGTH, &[]); + let mut deps = mock_dependencies(&[]); let minter = HumanAddr::from("minter"); let recipient = HumanAddr::from("recipient"); - do_init(&mut deps, &minter); + do_init(deps.as_mut(), &minter); - let amount = Uint128(222_222_222); - let msg = HandleMsg::Mint { + let amount = Uint128::new(222_222_222); + let msg = ExecuteMsg::Mint { recipient: recipient.clone(), amount, }; let other_address = HumanAddr::from("other"); - let env = mock_env(&other_address, &[]); - let res = handle(&mut deps, env, msg); + let env = mock_env(); + let info = mock_info(&other_address, &[]); + let res = execute(deps.as_mut(), env, info, msg); assert_eq!( format!("{}", res.unwrap_err()), format!("{}", crate::error::ContractError::Unauthorized {}) @@ -316,44 +329,46 @@ mod tests { #[test] fn transfer_balance_success() { - let mut deps = mock_dependencies(CANONICAL_LENGTH, &[]); + let mut deps = mock_dependencies(&[]); let minter = HumanAddr::from("minter"); let owner = HumanAddr::from("owner"); - let amount_initial = Uint128(222_222_222); - do_init_and_mint(&mut deps, &minter, &owner, amount_initial); + let amount_initial = Uint128::new(222_222_222); + do_init_and_mint(deps.as_mut(), &minter, &owner, amount_initial); // Transfer let recipient = HumanAddr::from("recipient"); - let amount_transfer = Uint128(222_222); - let msg = HandleMsg::Transfer { + let amount_transfer = Uint128::new(222_222); + let msg = ExecuteMsg::Transfer { recipient: recipient.clone(), amount: amount_transfer, }; - let env = mock_env(&owner, &[]); - let res = handle(&mut deps, env, msg.clone()).unwrap(); + let env = mock_env(); + let info = mock_info(&owner, &[]); + let res = execute(deps.as_mut(), env, info, msg.clone()).unwrap(); assert_eq!(0, res.messages.len()); - assert_eq!(get_balance(&deps, owner), Uint128(222_000_000)); - assert_eq!(get_balance(&deps, recipient), amount_transfer); + assert_eq!(get_balance(deps.as_ref(), owner), Uint128::new(222_000_000)); + assert_eq!(get_balance(deps.as_ref(), recipient), amount_transfer); } #[test] fn transfer_balance_not_enough() { - let mut deps = mock_dependencies(CANONICAL_LENGTH, &[]); + let mut deps = mock_dependencies(&[]); let minter = HumanAddr::from("minter"); let owner = HumanAddr::from("owner"); - let amount_initial = Uint128(222_221); - do_init_and_mint(&mut deps, &minter, &owner, amount_initial); + let amount_initial = Uint128::new(222_221); + do_init_and_mint(deps.as_mut(), &minter, &owner, amount_initial); // Transfer let recipient = HumanAddr::from("recipient"); - let amount_transfer = Uint128(222_222); - let msg = HandleMsg::Transfer { + let amount_transfer = Uint128::new(222_222); + let msg = ExecuteMsg::Transfer { recipient: recipient.clone(), amount: amount_transfer, }; - let env = mock_env(&owner, &[]); - let _ = handle(&mut deps, env, msg.clone()).unwrap_err(); // Will panic if no error + let env = mock_env(); + let info = mock_info(&owner, &[]); + let _ = execute(deps.as_mut(), env, info, msg.clone()).unwrap_err(); // Will panic if no error } } diff --git a/terra/contracts-5/cw20-wrapped/src/lib.rs b/terra/contracts-5/cw20-wrapped/src/lib.rs index e8a83276..6e2ebd88 100644 --- a/terra/contracts-5/cw20-wrapped/src/lib.rs +++ b/terra/contracts-5/cw20-wrapped/src/lib.rs @@ -1,9 +1,7 @@ -pub mod contract; mod error; + +pub mod contract; pub mod msg; pub mod state; pub use crate::error::ContractError; - -#[cfg(all(target_arch = "wasm32", not(feature = "library")))] -cosmwasm_std::create_entry_points!(contract); diff --git a/terra/contracts-5/cw20-wrapped/src/msg.rs b/terra/contracts-5/cw20-wrapped/src/msg.rs index 31c8cd6e..25ca6377 100644 --- a/terra/contracts-5/cw20-wrapped/src/msg.rs +++ b/terra/contracts-5/cw20-wrapped/src/msg.rs @@ -6,14 +6,16 @@ use serde::{ }; use cosmwasm_std::{ + Addr, Binary, - HumanAddr, Uint128, }; use cw20::Expiration; +type HumanAddr = String; + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct InitMsg { +pub struct InstantiateMsg { pub name: String, pub symbol: String, pub asset_chain: u16, @@ -37,7 +39,7 @@ pub struct InitMint { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] -pub enum HandleMsg { +pub enum ExecuteMsg { /// Implements CW20. Transfer is a base message to move tokens to another account without triggering actions Transfer { recipient: HumanAddr, @@ -50,7 +52,7 @@ pub enum HandleMsg { Send { contract: HumanAddr, amount: Uint128, - msg: Option, + msg: Binary, }, /// Implements CW20 "mintable" extension. If authorized, creates amount new tokens /// and adds to the recipient balance. @@ -87,7 +89,7 @@ pub enum HandleMsg { owner: HumanAddr, contract: HumanAddr, amount: Uint128, - msg: Option, + msg: Binary, }, /// Implements CW20 "approval" extension. Destroys tokens forever BurnFrom { owner: HumanAddr, amount: Uint128 }, @@ -116,5 +118,5 @@ pub enum QueryMsg { pub struct WrappedAssetInfoResponse { pub asset_chain: u16, // Asset chain id pub asset_address: Binary, // Asset smart contract address in the original chain - pub bridge: HumanAddr, // Bridge address, authorized to mint and burn wrapped tokens + pub bridge: Addr, // Bridge address, authorized to mint and burn wrapped tokens } diff --git a/terra/contracts-5/cw20-wrapped/src/state.rs b/terra/contracts-5/cw20-wrapped/src/state.rs index 382f7d83..2d9ba10f 100644 --- a/terra/contracts-5/cw20-wrapped/src/state.rs +++ b/terra/contracts-5/cw20-wrapped/src/state.rs @@ -7,7 +7,6 @@ use serde::{ use cosmwasm_std::{ Binary, CanonicalAddr, - ReadonlyStorage, Storage, }; use cosmwasm_storage::{ @@ -27,12 +26,12 @@ pub struct WrappedAssetInfo { pub bridge: CanonicalAddr, // Bridge address, authorized to mint and burn wrapped tokens } -pub fn wrapped_asset_info(storage: &mut S) -> Singleton { +pub fn wrapped_asset_info(storage: &mut dyn Storage) -> Singleton { singleton(storage, KEY_WRAPPED_ASSET) } -pub fn wrapped_asset_info_read( - storage: &S, -) -> ReadonlySingleton { +pub fn wrapped_asset_info_read( + storage: &dyn Storage, +) -> ReadonlySingleton { singleton_read(storage, KEY_WRAPPED_ASSET) }