diff --git a/Cargo.lock b/Cargo.lock index 41358bfc..83dce0ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -236,7 +236,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "0.16.4" +version = "0.16.5" dependencies = [ "anyhow", "cosmwasm-std", diff --git a/Cargo.toml b/Cargo.toml index 59925b1d..455e8d98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,11 +10,12 @@ homepage = "https://cosmwasm.com" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["iterator", "staking"] +default = ["iterator", "staking", "cosmwasm_1_1"] iterator = ["cosmwasm-std/iterator"] stargate = ["cosmwasm-std/stargate"] staking = ["cosmwasm-std/staking"] backtrace = ["anyhow/backtrace"] +cosmwasm_1_1 = ["cosmwasm-std/cosmwasm_1_1"] [dependencies] cw-utils = "1.0" diff --git a/src/bank.rs b/src/bank.rs index 15cc6617..f9c9a96a 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use cosmwasm_std::{ coin, to_binary, Addr, AllBalanceResponse, Api, BalanceResponse, BankMsg, BankQuery, Binary, - BlockInfo, Coin, Event, Querier, Storage, + BlockInfo, Coin, Event, Order, Querier, StdResult, Storage, SupplyResponse, Uint128, }; use cw_storage_plus::Map; use cw_utils::NativeBalance; @@ -18,7 +18,6 @@ const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); pub const NAMESPACE_BANK: &[u8] = b"bank"; -// WIP #[derive(Clone, std::fmt::Debug, PartialEq, Eq, JsonSchema)] pub enum BankSudo { Mint { @@ -48,6 +47,7 @@ impl BankKeeper { self.set_balance(&mut bank_storage, account, amount) } + // this is an "admin" function to let us adjust bank accounts fn set_balance( &self, bank_storage: &mut dyn Storage, @@ -61,12 +61,29 @@ impl BankKeeper { .map_err(Into::into) } - // this is an "admin" function to let us adjust bank accounts fn get_balance(&self, bank_storage: &dyn Storage, account: &Addr) -> AnyResult> { let val = BALANCES.may_load(bank_storage, account)?; Ok(val.unwrap_or_default().into_vec()) } + fn get_supply(&self, bank_storage: &dyn Storage, denom: String) -> AnyResult { + let supply: Uint128 = BALANCES + .range(bank_storage, None, None, Order::Ascending) + .collect::>>()? + .into_iter() + .map(|a| a.1) + .fold(Uint128::zero(), |accum, item| { + let mut subtotal = Uint128::zero(); + for coin in item.into_vec() { + if coin.denom == denom { + subtotal += coin.amount; + } + } + accum + subtotal + }); + Ok(coin(supply.into(), denom)) + } + fn send( &self, bank_storage: &mut dyn Storage, @@ -205,6 +222,12 @@ impl Module for BankKeeper { let res = BalanceResponse { amount }; Ok(to_binary(&res)?) } + BankQuery::Supply { denom } => { + let amount = self.get_supply(&bank_storage, denom)?; + let mut res = SupplyResponse::default(); + res.amount = amount; + Ok(to_binary(&res)?) + } q => bail!("Unsupported bank query: {:?}", q), } } @@ -241,6 +264,7 @@ mod test { let mut store = MockStorage::new(); let block = mock_env().block; let querier: MockQuerier = MockQuerier::new(&[]); + let router = MockRouter::default(); let owner = Addr::unchecked("owner"); let rcpt = Addr::unchecked("receiver"); @@ -290,12 +314,43 @@ mod test { assert_eq!(res.amount, coin(0, "foobar")); let req = BankQuery::Balance { - address: rcpt.into(), + address: rcpt.clone().into(), denom: "eth".into(), }; let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); let res: BalanceResponse = from_slice(&raw).unwrap(); assert_eq!(res.amount, coin(0, "eth")); + + // Query total supply of a denom + let req = BankQuery::Supply { + denom: "eth".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: SupplyResponse = from_slice(&raw).unwrap(); + assert_eq!(res.amount, coin(100, "eth")); + + // Mint tokens for recipient account + let msg = BankSudo::Mint { + to_address: rcpt.to_string(), + amount: norm.clone(), + }; + bank.sudo(&api, &mut store, &router, &block, msg).unwrap(); + + // Check that the recipient account has the expected balance + let req = BankQuery::AllBalances { + address: rcpt.into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: AllBalanceResponse = from_slice(&raw).unwrap(); + assert_eq!(res.amount, norm); + + // Check that the total supply of a denom is updated + let req = BankQuery::Supply { + denom: "eth".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: SupplyResponse = from_slice(&raw).unwrap(); + assert_eq!(res.amount, coin(200, "eth")); } #[test]