Skip to content

feat: use Uint256 for Coin #2413

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

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
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
33 changes: 19 additions & 14 deletions packages/std/src/coin.rs
Original file line number Diff line number Diff line change
@@ -4,16 +4,16 @@ use serde::{Deserialize, Serialize};

use crate::prelude::*;
use crate::CoinFromStrError;
use crate::Uint128;
use crate::Uint256;

#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq, JsonSchema)]
pub struct Coin {
pub denom: String,
pub amount: Uint128,
pub amount: Uint256,
}

impl Coin {
pub fn new(amount: impl Into<Uint128>, denom: impl Into<String>) -> Self {
pub fn new(amount: impl Into<Uint256>, denom: impl Into<String>) -> Self {
Coin {
amount: amount.into(),
denom: denom.into(),
@@ -113,12 +113,14 @@ pub fn has_coins(coins: &[Coin], required: &Coin) -> bool {

#[cfg(test)]
mod tests {
use crate::uint256;

use super::*;

#[test]
fn coin_implements_display() {
let a = Coin {
amount: Uint128::new(123),
amount: Uint256::new(123),
denom: "ucosm".to_string(),
};

@@ -133,7 +135,7 @@ mod tests {
assert_eq!(
a,
Coin {
amount: Uint128::new(123),
amount: Uint256::new(123),
denom: "ucosm".to_string()
}
);
@@ -142,7 +144,7 @@ mod tests {
assert_eq!(
zero,
Coin {
amount: Uint128::new(0),
amount: Uint256::new(0),
denom: "ucosm".to_string()
}
);
@@ -151,7 +153,7 @@ mod tests {
assert_eq!(
string_denom,
Coin {
amount: Uint128::new(42),
amount: Uint256::new(42),
denom: "ucosm".to_string()
}
);
@@ -163,7 +165,7 @@ mod tests {
assert_eq!(
a,
vec![Coin {
amount: Uint128::new(123),
amount: Uint256::new(123),
denom: "ucosm".to_string()
}]
);
@@ -172,7 +174,7 @@ mod tests {
assert_eq!(
zero,
vec![Coin {
amount: Uint128::new(0),
amount: Uint256::new(0),
denom: "ucosm".to_string()
}]
);
@@ -181,7 +183,7 @@ mod tests {
assert_eq!(
string_denom,
vec![Coin {
amount: Uint128::new(42),
amount: Uint256::new(42),
denom: "ucosm".to_string()
}]
);
@@ -197,16 +199,19 @@ mod tests {

#[test]
fn parse_coin() {
let expected = Coin::new(123u128, "ucosm");
let expected = Coin::new(uint256!(123u128), "ucosm");
assert_eq!("123ucosm".parse::<Coin>().unwrap(), expected);
// leading zeroes should be ignored
assert_eq!("00123ucosm".parse::<Coin>().unwrap(), expected);
// 0 amount parses correctly
assert_eq!("0ucosm".parse::<Coin>().unwrap(), Coin::new(0u128, "ucosm"));
assert_eq!(
"0ucosm".parse::<Coin>().unwrap(),
Coin::new(uint256!(0u128), "ucosm")
);
// ibc denom should work
let ibc_str = "11111ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2";
let ibc_coin = Coin::new(
11111u128,
uint256!(11111u128),
"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2",
);
assert_eq!(ibc_str.parse::<Coin>().unwrap(), ibc_coin);
@@ -246,7 +251,7 @@ mod tests {

#[test]
fn debug_coin() {
let coin = Coin::new(123u128, "ucosm");
let coin = Coin::new(uint256!(123u128), "ucosm");
assert_eq!(format!("{coin:?}"), r#"Coin { 123 "ucosm" }"#);
}
}
26 changes: 13 additions & 13 deletions packages/std/src/coins.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ use alloc::collections::BTreeMap;
use core::fmt;
use core::str::FromStr;

use crate::prelude::*;
use crate::{prelude::*, Uint256};
use crate::{Coin, CoinsError, OverflowError, OverflowOperation, StdError, StdResult, Uint128};

/// A collection of coins, similar to Cosmos SDK's `sdk.Coins` struct.
@@ -133,11 +133,11 @@ impl Coins {
}

/// Returns the amount of the given denom or zero if the denom is not present.
pub fn amount_of(&self, denom: &str) -> Uint128 {
pub fn amount_of(&self, denom: &str) -> Uint256 {
self.0
.get(denom)
.map(|c| c.amount)
.unwrap_or_else(Uint128::zero)
.unwrap_or_else(Uint256::zero)
}

/// Returns the amount of the given denom if and only if this collection contains only
@@ -159,7 +159,7 @@ impl Coins {
/// let coins: Coins = [coin(100, "uatom"), coin(200, "uusd")].try_into().unwrap();
/// assert_eq!(coins.contains_only("uatom"), None);
/// ```
pub fn contains_only(&self, denom: &str) -> Option<Uint128> {
pub fn contains_only(&self, denom: &str) -> Option<Uint256> {
if self.len() == 1 {
self.0.get(denom).map(|c| c.amount)
} else {
@@ -398,14 +398,14 @@ mod tests {
fn handling_zero_amount() {
// create a Vec<Coin> that contains zero amounts
let mut vec = mock_vec();
vec[0].amount = Uint128::zero();
vec[0].amount = Uint256::zero();

let coins = Coins::try_from(vec).unwrap();
assert_eq!(coins.len(), 2);
assert_ne!(coins.amount_of("ibc/1234ABCD"), Uint128::zero());
assert_ne!(coins.amount_of("ibc/1234ABCD"), Uint256::zero());
assert_ne!(
coins.amount_of("factory/osmo1234abcd/subdenom"),
Uint128::zero()
Uint256::zero()
);

// adding a coin with zero amount should not be added
@@ -432,15 +432,15 @@ mod tests {
// existing denom
coins.add(coin(12345, "uatom")).unwrap();
assert_eq!(coins.len(), 3);
assert_eq!(coins.amount_of("uatom").u128(), 24690);
assert_eq!(coins.amount_of("uatom"), Uint256::new(24690));

// new denom
coins.add(coin(123, "uusd")).unwrap();
assert_eq!(coins.len(), 4);

// zero amount
coins.add(coin(0, "uusd")).unwrap();
assert_eq!(coins.amount_of("uusd").u128(), 123);
assert_eq!(coins.amount_of("uusd"), Uint256::new(123));

// zero amount, new denom
coins.add(coin(0, "utest")).unwrap();
@@ -462,7 +462,7 @@ mod tests {
// partial sub
coins.sub(coin(1, "uatom")).unwrap();
assert_eq!(coins.len(), 1);
assert_eq!(coins.amount_of("uatom").u128(), 12344);
assert_eq!(coins.amount_of("uatom"), Uint256::new(12344));

// full sub
coins.sub(coin(12344, "uatom")).unwrap();
@@ -476,7 +476,7 @@ mod tests {
// sub zero, non-existent denom
coins.sub(coin(0, "uatom")).unwrap();
assert_eq!(coins.len(), 1);
assert_eq!(coins.amount_of("uatom").u128(), 12345);
assert_eq!(coins.amount_of("uatom"), Uint256::new(12345));
}

#[test]
@@ -488,7 +488,7 @@ mod tests {
// happy path
let coins = Coins::from(coin(12345, "uatom"));
assert_eq!(coins.len(), 1);
assert_eq!(coins.amount_of("uatom").u128(), 12345);
assert_eq!(coins.amount_of("uatom"), Uint256::new(12345));
}

#[test]
@@ -524,6 +524,6 @@ mod tests {
.eq(coins.to_vec().iter().map(|c| &c.denom)));

// can still use the coins afterwards
assert_eq!(coins.amount_of("uatom").u128(), 12345);
assert_eq!(coins.amount_of("uatom"), Uint256::new(12345));
}
}
8 changes: 8 additions & 0 deletions packages/std/src/math/uint256.rs
Original file line number Diff line number Diff line change
@@ -52,6 +52,14 @@ pub struct Uint256(#[schemars(with = "String")] pub(crate) U256);
impl_int_serde!(Uint256);
forward_ref_partial_eq!(Uint256, Uint256);

#[macro_export]
macro_rules! uint256 {
($val:expr) => {
Uint256::from($val)
};
}
Comment on lines +55 to +60
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really that useful? What's the benefit over just writing Uint256::from?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this might become a bit tedious to look at:

Coin::new(Uint256::from(123u128), "ucosm");

But yes I get your point, it isn't really adding much value. Will remove this



impl Uint256 {
pub const MAX: Uint256 = Uint256(U256::MAX);
pub const MIN: Uint256 = Uint256(U256::ZERO);
2 changes: 1 addition & 1 deletion packages/std/src/testing/message_info.rs
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ mod tests {
MessageInfo {
sender: addr.clone(),
funds: vec![Coin {
amount: Uint128::new(123),
amount: crate::Uint256::new(123),
denom: "foo".to_string(),
}],
}
12 changes: 7 additions & 5 deletions packages/std/src/testing/mock.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::prelude::*;
use crate::uint256;
use crate::HashFunction;
use crate::Uint256;
use crate::{Addr, CanonicalAddr, Timestamp};
use alloc::collections::BTreeMap;
#[cfg(feature = "cosmwasm_1_3")]
@@ -757,7 +759,7 @@ impl Default for WasmQuerier {
pub struct BankQuerier {
#[allow(dead_code)]
/// BTreeMap<denom, amount>
supplies: BTreeMap<String, Uint128>,
supplies: BTreeMap<String, Uint256>,
/// A map from address to balance. The address is the String conversion of `Addr`,
/// i.e. the bech32 encoded address.
balances: BTreeMap<String, Vec<Coin>>,
@@ -798,15 +800,15 @@ impl BankQuerier {
.collect();
}

fn calculate_supplies(balances: &BTreeMap<String, Vec<Coin>>) -> BTreeMap<String, Uint128> {
fn calculate_supplies(balances: &BTreeMap<String, Vec<Coin>>) -> BTreeMap<String, Uint256> {
let mut supplies = BTreeMap::new();

let all_coins = balances.iter().flat_map(|(_, coins)| coins);

for coin in all_coins {
*supplies
.entry(coin.denom.clone())
.or_insert_with(Uint128::zero) += coin.amount;
.or_insert_with(Uint256::zero) += coin.amount;
}

supplies
@@ -820,10 +822,10 @@ impl BankQuerier {
.supplies
.get(denom)
.cloned()
.unwrap_or_else(Uint128::zero);
.unwrap_or_else(Uint256::zero);
let bank_res = SupplyResponse {
amount: Coin {
amount,
amount: uint256!(amount),
denom: denom.to_string(),
},
};
4 changes: 2 additions & 2 deletions packages/std/src/traits.rs
Original file line number Diff line number Diff line change
@@ -665,7 +665,7 @@ mod tests {

use super::*;
use crate::testing::MockQuerier;
use crate::{coins, Uint128};
use crate::{coins, Uint128, Uint256};

// this is a simple demo helper to prove we can use it
fn demo_helper(_querier: &dyn Querier) -> u64 {
@@ -702,7 +702,7 @@ mod tests {
.unwrap()
.unwrap();
let balance: BalanceResponse = from_json(raw).unwrap();
assert_eq!(balance.amount.amount, Uint128::new(5));
assert_eq!(balance.amount.amount, Uint256::new(5));
}

#[cfg(feature = "cosmwasm_1_1")]
12 changes: 6 additions & 6 deletions packages/vm/src/instance.rs
Original file line number Diff line number Diff line change
@@ -542,7 +542,7 @@ mod tests {
mock_instance_with_options, MockInstanceOptions,
};
use cosmwasm_std::{
coin, coins, from_json, AllBalanceResponse, BalanceResponse, BankQuery, Empty, QueryRequest,
coin, coins, from_json, AllBalanceResponse, BalanceResponse, BankQuery, Empty, QueryRequest, Uint256,
};
use wasmer::FunctionEnvMut;

@@ -1000,7 +1000,7 @@ mod tests {
.unwrap()
.unwrap();
let BalanceResponse { amount, .. } = from_json(response).unwrap();
assert_eq!(amount.amount.u128(), 8000);
assert_eq!(amount.amount, Uint256::new(8000));
assert_eq!(amount.denom, "silver");
Ok(())
})
@@ -1022,9 +1022,9 @@ mod tests {
.unwrap();
let AllBalanceResponse { amount, .. } = from_json(response).unwrap();
assert_eq!(amount.len(), 2);
assert_eq!(amount[0].amount.u128(), 10000);
assert_eq!(amount[0].amount, Uint256::new(10000));
assert_eq!(amount[0].denom, "gold");
assert_eq!(amount[1].amount.u128(), 8000);
assert_eq!(amount[1].amount, Uint256::new(8000));
assert_eq!(amount[1].denom, "silver");

Ok(())
@@ -1056,7 +1056,7 @@ mod tests {
.unwrap()
.unwrap();
let BalanceResponse { amount, .. } = from_json(response).unwrap();
assert_eq!(amount.amount.u128(), 500);
assert_eq!(amount.amount, Uint256::new(500));
Ok(())
})
.unwrap();
@@ -1085,7 +1085,7 @@ mod tests {
.unwrap()
.unwrap();
let BalanceResponse { amount, .. } = from_json(response).unwrap();
assert_eq!(amount.amount.u128(), 8000);
assert_eq!(amount.amount, Uint256::new(8000));
Ok(())
})
.unwrap();