diff --git a/Cargo.lock b/Cargo.lock index 20baca837..61de24f1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -409,6 +409,7 @@ dependencies = [ "cosmwasm-std", "cosmwasm-storage", "cosmwasm-vm", + "cw0", "cw2", "cw20", "hex 0.3.2", @@ -920,9 +921,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] @@ -957,9 +958,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/cw1-subkeys/schema/all_allowances_response.json b/contracts/cw1-subkeys/schema/all_allowances_response.json index 1cfbc42d3..e42702559 100644 --- a/contracts/cw1-subkeys/schema/all_allowances_response.json +++ b/contracts/cw1-subkeys/schema/all_allowances_response.json @@ -23,7 +23,7 @@ ], "properties": { "balance": { - "$ref": "#/definitions/Balance" + "$ref": "#/definitions/NativeBalance" }, "expires": { "$ref": "#/definitions/Expiration" @@ -33,12 +33,6 @@ } } }, - "Balance": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, "Coin": { "type": "object", "required": [ @@ -101,6 +95,12 @@ "HumanAddr": { "type": "string" }, + "NativeBalance": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, "Uint128": { "type": "string" } diff --git a/contracts/cw1-subkeys/schema/allowance.json b/contracts/cw1-subkeys/schema/allowance.json index 232c77b5d..af6937e76 100644 --- a/contracts/cw1-subkeys/schema/allowance.json +++ b/contracts/cw1-subkeys/schema/allowance.json @@ -8,19 +8,13 @@ ], "properties": { "balance": { - "$ref": "#/definitions/Balance" + "$ref": "#/definitions/NativeBalance" }, "expires": { "$ref": "#/definitions/Expiration" } }, "definitions": { - "Balance": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, "Coin": { "type": "object", "required": [ @@ -80,6 +74,12 @@ } ] }, + "NativeBalance": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, "Uint128": { "type": "string" } diff --git a/contracts/cw1-subkeys/src/contract.rs b/contracts/cw1-subkeys/src/contract.rs index 287d44ac6..0d8c0ac0f 100644 --- a/contracts/cw1-subkeys/src/contract.rs +++ b/contracts/cw1-subkeys/src/contract.rs @@ -437,10 +437,10 @@ pub fn query_all_permissions( #[cfg(test)] mod tests { use super::*; - use crate::balance::Balance; use crate::state::Permissions; use cosmwasm_std::testing::{mock_dependencies, mock_env, MOCK_CONTRACT_ADDR}; use cosmwasm_std::{coin, coins, StakingMsg}; + use cw0::NativeBalance; use cw1_whitelist::msg::AdminListResponse; use cw2::{get_contract_version, ContractVersion}; @@ -550,7 +550,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![allow1.clone()]), + balance: NativeBalance(vec![allow1.clone()]), expires: expires_never.clone(), } ); @@ -558,7 +558,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![allow1.clone()]), + balance: NativeBalance(vec![allow1.clone()]), expires: expires_never.clone(), } ); @@ -608,7 +608,7 @@ mod tests { allowances[0], AllowanceInfo { spender: spender1, - balance: Balance(initial_allowances.clone()), + balance: NativeBalance(initial_allowances.clone()), expires: Expiration::Never {}, } ); @@ -616,7 +616,7 @@ mod tests { allowances[1], AllowanceInfo { spender: spender2.clone(), - balance: Balance(initial_allowances.clone()), + balance: NativeBalance(initial_allowances.clone()), expires: Expiration::Never {}, } ); @@ -630,7 +630,7 @@ mod tests { allowances[0], AllowanceInfo { spender: spender3, - balance: Balance(initial_allowances.clone()), + balance: NativeBalance(initial_allowances.clone()), expires: expires_later, } ); @@ -934,7 +934,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![coin(amount1 * 2, &allow1.denom), allow2.clone()]), + balance: NativeBalance(vec![coin(amount1 * 2, &allow1.denom), allow2.clone()]), expires: expires_height.clone(), } ); @@ -952,7 +952,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![allow1.clone(), allow2.clone(), allow3.clone()]), + balance: NativeBalance(vec![allow1.clone(), allow2.clone(), allow3.clone()]), expires: expires_height.clone(), } ); @@ -970,7 +970,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![allow1.clone()]), + balance: NativeBalance(vec![allow1.clone()]), expires: expires_never.clone(), } ); @@ -988,7 +988,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![allow2.clone()]), + balance: NativeBalance(vec![allow2.clone()]), expires: expires_time, } ); @@ -1049,7 +1049,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![allow1.clone(), allow2.clone()]), + balance: NativeBalance(vec![allow1.clone(), allow2.clone()]), expires: expires_height.clone(), } ); @@ -1067,7 +1067,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![allow1.clone()]), + balance: NativeBalance(vec![allow1.clone()]), expires: expires_never.clone(), } ); @@ -1085,7 +1085,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![ + balance: NativeBalance(vec![ coin(amount1 / 2 + (amount1 & 1), denom1), allow2.clone() ]), @@ -1129,7 +1129,7 @@ mod tests { assert_eq!( allowance, Allowance { - balance: Balance(vec![allow2]), + balance: NativeBalance(vec![allow2]), expires: expires_height.clone(), } ); @@ -1378,7 +1378,7 @@ mod tests { let coin = coin(amount, denom); let allow = Allowance { - balance: Balance(vec![coin.clone()]), + balance: NativeBalance(vec![coin.clone()]), expires: Expiration::Never {}, }; let perm = Permissions { diff --git a/contracts/cw1-subkeys/src/lib.rs b/contracts/cw1-subkeys/src/lib.rs index b338268f6..2546c7677 100644 --- a/contracts/cw1-subkeys/src/lib.rs +++ b/contracts/cw1-subkeys/src/lib.rs @@ -1,4 +1,3 @@ -pub mod balance; pub mod contract; pub mod msg; pub mod state; diff --git a/contracts/cw1-subkeys/src/msg.rs b/contracts/cw1-subkeys/src/msg.rs index bf3e8ba78..c27b0b730 100644 --- a/contracts/cw1-subkeys/src/msg.rs +++ b/contracts/cw1-subkeys/src/msg.rs @@ -3,9 +3,8 @@ use serde::{Deserialize, Serialize}; use std::fmt; use cosmwasm_std::{Coin, CosmosMsg, Empty, HumanAddr}; -use cw0::Expiration; +use cw0::{Expiration, NativeBalance}; -use crate::balance::Balance; use crate::state::Permissions; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -88,7 +87,7 @@ pub struct AllAllowancesResponse { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct AllowanceInfo { pub spender: HumanAddr, - pub balance: Balance, + pub balance: NativeBalance, pub expires: Expiration, } diff --git a/contracts/cw1-subkeys/src/state.rs b/contracts/cw1-subkeys/src/state.rs index 8b04b2516..e40c3a29e 100644 --- a/contracts/cw1-subkeys/src/state.rs +++ b/contracts/cw1-subkeys/src/state.rs @@ -3,9 +3,8 @@ use serde::{Deserialize, Serialize}; use cosmwasm_std::{ReadonlyStorage, StdError, Storage}; use cosmwasm_storage::{bucket, bucket_read, Bucket, ReadonlyBucket}; -use cw0::Expiration; +use cw0::{Expiration, NativeBalance}; -use crate::balance::Balance; use std::fmt; // Permissions struct defines users message execution permissions. @@ -70,7 +69,7 @@ impl From for StdError { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema, Default)] pub struct Allowance { - pub balance: Balance, + pub balance: NativeBalance, pub expires: Expiration, } diff --git a/contracts/cw20-atomic-swap/Cargo.toml b/contracts/cw20-atomic-swap/Cargo.toml index e97ce3d25..95f5d3ce9 100644 --- a/contracts/cw20-atomic-swap/Cargo.toml +++ b/contracts/cw20-atomic-swap/Cargo.toml @@ -18,6 +18,7 @@ singlepass = ["cosmwasm-vm/default-singlepass"] library = [] [dependencies] +cw0 = { path = "../../packages/cw0", version = "0.2.1" } cw2 = { path = "../../packages/cw2", version = "0.2.1" } cw20 = { path = "../../packages/cw20", version = "0.2.1" } cosmwasm-std = { version = "0.10.0", features = ["iterator"] } diff --git a/contracts/cw20-atomic-swap/src/balance.rs b/contracts/cw20-atomic-swap/src/balance.rs index 94c7a2bd1..cd46ea83e 100644 --- a/contracts/cw20-atomic-swap/src/balance.rs +++ b/contracts/cw20-atomic-swap/src/balance.rs @@ -1,27 +1,35 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::Coin; +use cw0::NativeBalance; use cw20::Cw20Coin; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum Balance { - Native(Vec), + Native(NativeBalance), Cw20(Cw20Coin), } impl Default for Balance { fn default() -> Balance { - Balance::Native(vec![]) + Balance::Native(NativeBalance(vec![])) } } impl Balance { pub fn is_empty(&self) -> bool { match self { - Balance::Native(coins) => coins.is_empty(), + Balance::Native(balance) => balance.is_empty(), Balance::Cw20(coin) => coin.is_empty(), } } + + /// normalize Wallet + pub fn normalize(&mut self) { + match self { + Balance::Native(balance) => balance.normalize(), + Balance::Cw20(_) => {} + } + } } diff --git a/contracts/cw20-atomic-swap/src/contract.rs b/contracts/cw20-atomic-swap/src/contract.rs index b4e5ab510..0dc4291d3 100644 --- a/contracts/cw20-atomic-swap/src/contract.rs +++ b/contracts/cw20-atomic-swap/src/contract.rs @@ -4,6 +4,7 @@ use cosmwasm_std::{ from_binary, log, to_binary, Api, BankMsg, Binary, CosmosMsg, Env, Extern, HandleResponse, HumanAddr, InitResponse, Querier, StdError, StdResult, Storage, WasmMsg, }; +use cw0::NativeBalance; use cw2::set_contract_version; use cw20::{Cw20Coin, Cw20CoinHuman, Cw20HandleMsg, Cw20ReceiveMsg}; @@ -36,7 +37,7 @@ pub fn handle( match msg { HandleMsg::Create(msg) => { let sent_funds = env.message.sent_funds.clone(); - try_create(deps, env, msg, Balance::Native(sent_funds)) + try_create(deps, env, msg, Balance::Native(NativeBalance(sent_funds))) } HandleMsg::Release { id, preimage } => try_release(deps, env, id, preimage), HandleMsg::Refund { id } => try_refund(deps, env, id), @@ -72,7 +73,7 @@ pub fn try_create( return Err(StdError::generic_err("Invalid atomic swap id")); } - // FIXME: normalize array first (remove zero-valued coins), and then check for empty + // this ignores 0 value coins, must have one or more with positive balance if balance.is_empty() { return Err(StdError::generic_err( "Send some coins to create an atomic swap", @@ -197,7 +198,7 @@ fn send_tokens( Ok(vec![]) } else { match amount { - Balance::Native(coins) => { + Balance::Native(NativeBalance(coins)) => { let msg = BankMsg::Send { from_address: from.into(), to_address: to.into(), @@ -239,7 +240,7 @@ fn query_details( // Convert balance to human balance let balance_human = match swap.balance { - Balance::Native(coins) => BalanceHuman::Native(coins), + Balance::Native(coins) => BalanceHuman::Native(coins.0), Balance::Cw20(coin) => BalanceHuman::Cw20(Cw20CoinHuman { address: deps.api.human_address(&coin.address)?, amount: coin.amount, diff --git a/contracts/cw1-subkeys/src/balance.rs b/packages/cw0/src/balance.rs similarity index 75% rename from contracts/cw1-subkeys/src/balance.rs rename to packages/cw0/src/balance.rs index 36042fcf6..745a792e9 100644 --- a/contracts/cw1-subkeys/src/balance.rs +++ b/packages/cw0/src/balance.rs @@ -2,14 +2,14 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::ops; -use cosmwasm_std::{Coin, StdError, StdResult}; +use cosmwasm_std::{Coin, StdError, StdResult, Uint128}; // Balance wraps Vec and provides some nice helpers. It mutates the Vec and can be // unwrapped when done. #[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)] -pub struct Balance(pub Vec); +pub struct NativeBalance(pub Vec); -impl Balance { +impl NativeBalance { pub fn into_vec(self) -> Vec { self.0 } @@ -65,7 +65,7 @@ impl Balance { } pub fn is_empty(&self) -> bool { - self.0.is_empty() + !self.0.iter().any(|x| x.amount != Uint128(0)) } /// similar to `Balance.sub`, but doesn't fail when minuend less than subtrahend @@ -85,7 +85,7 @@ impl Balance { } } -impl ops::AddAssign for Balance { +impl ops::AddAssign for NativeBalance { fn add_assign(&mut self, other: Coin) { match self.find(&other.denom) { Some((i, c)) => { @@ -100,7 +100,7 @@ impl ops::AddAssign for Balance { } } -impl ops::Add for Balance { +impl ops::Add for NativeBalance { type Output = Self; fn add(mut self, other: Coin) -> Self { @@ -109,24 +109,24 @@ impl ops::Add for Balance { } } -impl ops::AddAssign for Balance { - fn add_assign(&mut self, other: Balance) { +impl ops::AddAssign for NativeBalance { + fn add_assign(&mut self, other: NativeBalance) { for coin in other.0.into_iter() { self.add_assign(coin); } } } -impl ops::Add for Balance { +impl ops::Add for NativeBalance { type Output = Self; - fn add(mut self, other: Balance) -> Self { + fn add(mut self, other: NativeBalance) -> Self { self += other; self } } -impl ops::Sub for Balance { +impl ops::Sub for NativeBalance { type Output = StdResult; fn sub(mut self, other: Coin) -> StdResult { @@ -146,7 +146,7 @@ impl ops::Sub for Balance { } } -impl ops::Sub> for Balance { +impl ops::Sub> for NativeBalance { type Output = StdResult; fn sub(self, amount: Vec) -> StdResult { @@ -165,7 +165,7 @@ mod test { #[test] fn balance_has_works() { - let balance = Balance(vec![coin(555, "BTC"), coin(12345, "ETH")]); + let balance = NativeBalance(vec![coin(555, "BTC"), coin(12345, "ETH")]); // less than same type assert!(balance.has(&coin(777, "ETH"))); @@ -180,20 +180,20 @@ mod test { #[test] fn balance_add_works() { - let balance = Balance(vec![coin(555, "BTC"), coin(12345, "ETH")]); + let balance = NativeBalance(vec![coin(555, "BTC"), coin(12345, "ETH")]); // add an existing coin let more_eth = balance.clone() + coin(54321, "ETH"); assert_eq!( more_eth, - Balance(vec![coin(555, "BTC"), coin(66666, "ETH")]) + NativeBalance(vec![coin(555, "BTC"), coin(66666, "ETH")]) ); // add an new coin let add_atom = balance.clone() + coin(777, "ATOM"); assert_eq!( add_atom, - Balance(vec![ + NativeBalance(vec![ coin(777, "ATOM"), coin(555, "BTC"), coin(12345, "ETH"), @@ -203,40 +203,40 @@ mod test { #[test] fn balance_in_place_addition() { - let mut balance = Balance(vec![coin(555, "BTC")]); + let mut balance = NativeBalance(vec![coin(555, "BTC")]); balance += coin(777, "ATOM"); assert_eq!( &balance, - &Balance(vec![coin(777, "ATOM"), coin(555, "BTC")]) + &NativeBalance(vec![coin(777, "ATOM"), coin(555, "BTC")]) ); - balance += Balance(vec![coin(666, "ETH"), coin(123, "ATOM")]); + balance += NativeBalance(vec![coin(666, "ETH"), coin(123, "ATOM")]); assert_eq!( &balance, - &Balance(vec![coin(900, "ATOM"), coin(555, "BTC"), coin(666, "ETH")]) + &NativeBalance(vec![coin(900, "ATOM"), coin(555, "BTC"), coin(666, "ETH")]) ); - let foo = balance + Balance(vec![coin(234, "BTC")]); + let foo = balance + NativeBalance(vec![coin(234, "BTC")]); assert_eq!( &foo, - &Balance(vec![coin(900, "ATOM"), coin(789, "BTC"), coin(666, "ETH")]) + &NativeBalance(vec![coin(900, "ATOM"), coin(789, "BTC"), coin(666, "ETH")]) ); } #[test] fn balance_subtract_works() { - let balance = Balance(vec![coin(555, "BTC"), coin(12345, "ETH")]); + let balance = NativeBalance(vec![coin(555, "BTC"), coin(12345, "ETH")]); // subtract less than we have let less_eth = (balance.clone() - coin(2345, "ETH")).unwrap(); assert_eq!( less_eth, - Balance(vec![coin(555, "BTC"), coin(10000, "ETH")]) + NativeBalance(vec![coin(555, "BTC"), coin(10000, "ETH")]) ); // subtract all of one coin (and remove with 0 amount) let no_btc = (balance.clone() - coin(555, "BTC")).unwrap(); - assert_eq!(no_btc, Balance(vec![coin(12345, "ETH")])); + assert_eq!(no_btc, NativeBalance(vec![coin(12345, "ETH")])); // subtract more than we have let underflow = balance.clone() - coin(666, "BTC"); @@ -249,23 +249,23 @@ mod test { #[test] fn balance_subtract_saturating_works() { - let balance = Balance(vec![coin(555, "BTC"), coin(12345, "ETH")]); + let balance = NativeBalance(vec![coin(555, "BTC"), coin(12345, "ETH")]); // subtract less than we have let less_eth = balance.clone().sub_saturating(coin(2345, "ETH")).unwrap(); assert_eq!( less_eth, - Balance(vec![coin(555, "BTC"), coin(10000, "ETH")]) + NativeBalance(vec![coin(555, "BTC"), coin(10000, "ETH")]) ); // subtract all of one coin (and remove with 0 amount) let no_btc = balance.clone().sub_saturating(coin(555, "BTC")).unwrap(); - assert_eq!(no_btc, Balance(vec![coin(12345, "ETH")])); + assert_eq!(no_btc, NativeBalance(vec![coin(12345, "ETH")])); // subtract more than we have let saturating = balance.clone().sub_saturating(coin(666, "BTC")); assert!(saturating.is_ok()); - assert_eq!(saturating.unwrap(), Balance(vec![coin(12345, "ETH")])); + assert_eq!(saturating.unwrap(), NativeBalance(vec![coin(12345, "ETH")])); // subtract non-existent denom let missing = balance.clone() - coin(1, "ATOM"); @@ -275,18 +275,24 @@ mod test { #[test] fn normalize_balance() { // remove 0 value items and sort - let mut balance = Balance(vec![coin(123, "ETH"), coin(0, "BTC"), coin(8990, "ATOM")]); + let mut balance = NativeBalance(vec![coin(123, "ETH"), coin(0, "BTC"), coin(8990, "ATOM")]); balance.normalize(); - assert_eq!(balance, Balance(vec![coin(8990, "ATOM"), coin(123, "ETH")])); + assert_eq!( + balance, + NativeBalance(vec![coin(8990, "ATOM"), coin(123, "ETH")]) + ); // merge duplicate entries of same denom - let mut balance = Balance(vec![ + let mut balance = NativeBalance(vec![ coin(123, "ETH"), coin(789, "BTC"), coin(321, "ETH"), coin(11, "BTC"), ]); balance.normalize(); - assert_eq!(balance, Balance(vec![coin(800, "BTC"), coin(444, "ETH")])); + assert_eq!( + balance, + NativeBalance(vec![coin(800, "BTC"), coin(444, "ETH")]) + ); } } diff --git a/packages/cw0/src/lib.rs b/packages/cw0/src/lib.rs index d1b29c31e..30b91b75a 100644 --- a/packages/cw0/src/lib.rs +++ b/packages/cw0/src/lib.rs @@ -1,5 +1,7 @@ +mod balance; mod expiration; +pub use crate::balance::NativeBalance; pub use crate::expiration::Expiration; #[cfg(test)]