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