Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add query for the total supply of a coin #1356

Merged
merged 28 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9de7624
add bank supply query
larry0x Jul 12, 2022
eb66d7a
export `SupplyResponse`
larry0x Jul 12, 2022
de275e8
add a helper function for querying supply
larry0x Jul 12, 2022
ddd4e3c
update schema
larry0x Jul 12, 2022
787cef0
update import
larry0x Jul 12, 2022
ce2577b
fix import
larry0x Jul 12, 2022
c1e0b78
add unit test for bank query helpers
larry0x Jul 13, 2022
0293397
add an entry to changelog
larry0x Jul 13, 2022
ecb68ea
Update packages/std/src/query/bank.rs
larry0x Jul 13, 2022
11cd9a5
clarify in comment the case if a denom doesn not exist
larry0x Jul 13, 2022
7d47853
add a unit test for querying the supply of a non-existing denom
larry0x Jul 13, 2022
d97d68b
revert changes made to `Cargo.toml` (not supposed to be pushed)
larry0x Jul 13, 2022
f15a25f
remove a contract unintentionally pushed (only used for local testing)
larry0x Jul 13, 2022
21e505c
format changelog
larry0x Jul 13, 2022
032c34c
revert unintential changes made to `Cargo.toml`
larry0x Jul 13, 2022
2aeca60
update schema
larry0x Jul 13, 2022
2cd39d1
resolve conflict
larry0x Jul 14, 2022
6f125e4
updat schema
larry0x Jul 14, 2022
abe4a4f
Update packages/std/src/query/bank.rs
webmaster128 Jul 14, 2022
0e619bc
Merge branch 'main' into larry/bank-query-total-supply
larry0x Jul 29, 2022
ef952c3
Merge branch 'main' into larry/bank-query-total-supply
uint Aug 23, 2022
162bcfd
fix poorly resolved merge conflict
uint Aug 23, 2022
61bcb49
hide BankQuery::Supply behind the `cosmwasm_1_1` feature
uint Aug 23, 2022
914f87c
fix Rust 1.63 lints
uint Aug 23, 2022
b440266
generate std schemas including cosmwasm_1_1 feature
uint Aug 23, 2022
3cdc9ef
test BankQuery::Supply using the reflect contract
uint Aug 23, 2022
74a68bc
update CI after introducing the `cosmwasm_1_1` feature
uint Aug 23, 2022
492e6d7
avoid BankQuerier.supplies ending up with invalid state
uint Aug 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ and this project adheres to
- cosmwasm-std: Implement `ceil`/`floor` for `Decimal`/`Decimal256`.
- cosmwasm-std: Implement `saturating_add`/`sub`/`mul` for
`Decimal`/`Decimal256`.
- cosmwasm-std: Implement `BankQuery::Supply` to allow querying the total supply
of a native token

[#1334]: https://github.com/CosmWasm/cosmwasm/pull/1334

Expand Down
21 changes: 21 additions & 0 deletions contracts/reflect/schema/reflect.json
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,27 @@
"definitions": {
"BankQuery": {
"oneOf": [
{
"description": "This calls into the native bank module for querying the total supply of one denomination. It does the same as the SupplyOf call in Cosmos SDK's RPC API. Return value is of type SupplyResponse.",
"type": "object",
"required": [
"supply"
],
"properties": {
"supply": {
"type": "object",
"required": [
"denom"
],
"properties": {
"denom": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This calls into the native bank module for one denomination Return value is BalanceResponse",
"type": "object",
Expand Down
21 changes: 21 additions & 0 deletions packages/std/schema/query_request.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@
"definitions": {
"BankQuery": {
"oneOf": [
{
"description": "This calls into the native bank module for querying the total supply of one denomination. It does the same as the SupplyOf call in Cosmos SDK's RPC API. Return value is of type SupplyResponse.",
"type": "object",
"required": [
"supply"
],
"properties": {
"supply": {
"type": "object",
"required": [
"denom"
],
"properties": {
"denom": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This calls into the native bank module for one denomination Return value is BalanceResponse",
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion packages/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub use crate::math::{
};
pub use crate::query::{
AllBalanceResponse, BalanceResponse, BankQuery, ContractInfoResponse, CustomQuery,
QueryRequest, WasmQuery,
QueryRequest, SupplyResponse, WasmQuery,
};
#[cfg(feature = "staking")]
pub use crate::query::{
Expand Down
73 changes: 69 additions & 4 deletions packages/std/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ use crate::ibc::{
IbcEndpoint, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg,
IbcTimeoutBlock,
};
use crate::math::Uint128;
use crate::query::{
AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, WasmQuery,
AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, SupplyResponse,
WasmQuery,
};
#[cfg(feature = "staking")]
use crate::query::{
Expand Down Expand Up @@ -564,20 +566,44 @@ impl Default for WasmQuerier {

#[derive(Clone, Default)]
pub struct BankQuerier {
supplies: HashMap<String, Uint128>,
balances: HashMap<String, Vec<Coin>>,
}

impl BankQuerier {
pub fn new(balances: &[(&str, &[Coin])]) -> Self {
let mut map = HashMap::new();
let mut supplies_map = HashMap::new();
let mut balances_map = HashMap::new();
for (addr, coins) in balances.iter() {
map.insert(addr.to_string(), coins.to_vec());
balances_map.insert(addr.to_string(), coins.to_vec());
for coin in coins.iter() {
*supplies_map
.entry(coin.denom.clone())
.or_insert_with(Uint128::zero) += coin.amount;
}
}
BankQuerier {
supplies: supplies_map,
balances: balances_map,
}
BankQuerier { balances: map }
}

pub fn query(&self, request: &BankQuery) -> QuerierResult {
let contract_result: ContractResult<Binary> = match request {
BankQuery::Supply { denom } => {
let amount = self
.supplies
.get(denom)
.cloned()
.unwrap_or_else(Uint128::zero);
let bank_res = SupplyResponse {
amount: Coin {
amount,
denom: denom.to_string(),
},
};
to_binary(&bank_res).into()
}
BankQuery::Balance { address, denom } => {
// proper error on not found, serialize result on found
let amount = self
Expand Down Expand Up @@ -1060,6 +1086,45 @@ mod tests {
assert_eq!(res.unwrap_err(), VerificationError::InvalidPubkeyFormat);
}

#[test]
fn bank_querier_supply() {
let addr1 = String::from("foo");
let balance1 = vec![coin(123, "ELF"), coin(777, "FLY")];

let addr2 = String::from("bar");
let balance2 = coins(321, "ELF");

let bank = BankQuerier::new(&[(&addr1, &balance1), (&addr2, &balance2)]);

let elf = bank
.query(&BankQuery::Supply {
denom: "ELF".to_string(),
})
.unwrap()
.unwrap();
let res: SupplyResponse = from_binary(&elf).unwrap();
assert_eq!(res.amount, coin(444, "ELF"));

let fly = bank
.query(&BankQuery::Supply {
denom: "FLY".to_string(),
})
.unwrap()
.unwrap();
let res: SupplyResponse = from_binary(&fly).unwrap();
assert_eq!(res.amount, coin(777, "FLY"));

// if a denom does not exist, should return zero amount, instead of throwing an error
let atom = bank
.query(&BankQuery::Supply {
denom: "ATOM".to_string(),
})
.unwrap()
.unwrap();
let res: SupplyResponse = from_binary(&atom).unwrap();
assert_eq!(res.amount, coin(0, "ATOM"));
}

#[test]
fn bank_querier_all_balances() {
let addr = String::from("foobar");
Expand Down
13 changes: 13 additions & 0 deletions packages/std/src/query/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ use crate::Coin;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum BankQuery {
/// This calls into the native bank module for querying the total supply of one denomination.
/// It does the same as the SupplyOf call in Cosmos SDK's RPC API.
/// Return value is of type SupplyResponse.
Supply { denom: String },
/// This calls into the native bank module for one denomination
/// Return value is BalanceResponse
Balance { address: String, denom: String },
Expand All @@ -16,6 +20,15 @@ pub enum BankQuery {
AllBalances { address: String },
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
#[non_exhaustive]
pub struct SupplyResponse {
/// Always returns a Coin with the requested denom.
/// This will be of zero amount if the denom does not exist.
pub amount: Coin,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct BalanceResponse {
Expand Down
2 changes: 1 addition & 1 deletion packages/std/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod ibc;
mod staking;
mod wasm;

pub use bank::{AllBalanceResponse, BalanceResponse, BankQuery};
pub use bank::{AllBalanceResponse, BalanceResponse, BankQuery, SupplyResponse};
#[cfg(feature = "stargate")]
pub use ibc::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse};
#[cfg(feature = "staking")]
Expand Down
32 changes: 30 additions & 2 deletions packages/std/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use crate::errors::{RecoverPubkeyError, StdError, StdResult, VerificationError};
#[cfg(feature = "iterator")]
use crate::iterator::{Order, Record};
use crate::query::{
AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, WasmQuery,
AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, SupplyResponse,
WasmQuery,
};
#[cfg(feature = "staking")]
use crate::query::{
Expand Down Expand Up @@ -197,6 +198,15 @@ impl<'a, C: CustomQuery> QuerierWrapper<'a, C> {
}
}

pub fn query_supply(&self, denom: impl Into<String>) -> StdResult<Coin> {
let request = BankQuery::Supply {
denom: denom.into(),
}
.into();
let res: SupplyResponse = self.query(&request)?;
Ok(res.amount)
}

pub fn query_balance(
&self,
address: impl Into<String>,
Expand Down Expand Up @@ -332,7 +342,7 @@ impl<'a, C: CustomQuery> QuerierWrapper<'a, C> {
mod tests {
use super::*;
use crate::mock::MockQuerier;
use crate::{coins, from_slice, Uint128};
use crate::{coin, coins, from_slice, Uint128};

// this is a simple demo helper to prove we can use it
fn demo_helper(_querier: &dyn Querier) -> u64 {
Expand Down Expand Up @@ -371,4 +381,22 @@ mod tests {
let balance: BalanceResponse = from_slice(&raw).unwrap();
assert_eq!(balance.amount.amount, Uint128::new(5));
}

#[test]
fn bank_query_helpers_work() {
let querier: MockQuerier<Empty> = MockQuerier::new(&[
("foo", &[coin(123, "ELF"), coin(777, "FLY")]),
("bar", &[coin(321, "ELF")]),
]);
let wrapper = QuerierWrapper::<Empty>::new(&querier);

let supply = wrapper.query_supply("ELF").unwrap();
assert_eq!(supply, coin(444, "ELF"));

let balance = wrapper.query_balance("foo", "ELF").unwrap();
assert_eq!(balance, coin(123, "ELF"));

let all_balances = wrapper.query_all_balances("foo").unwrap();
assert_eq!(all_balances, vec![coin(123, "ELF"), coin(777, "FLY")]);
}
}