diff --git a/proof_of_stake/src/parameters.rs b/proof_of_stake/src/parameters.rs index 7ee0abdf986..1c265bf1a84 100644 --- a/proof_of_stake/src/parameters.rs +++ b/proof_of_stake/src/parameters.rs @@ -71,11 +71,14 @@ pub enum ValidationError { UnbondingLenTooShort(u64, u64), } +/// The number of fundamental units per whole token of the native staking token +pub const TOKENS_PER_NAM: u64 = 1_000_000; + /// From Tendermint: const MAX_TOTAL_VOTING_POWER: i64 = i64::MAX / 8; /// Assuming token amount is `u64` in micro units. -const TOKEN_MAX_AMOUNT: u64 = u64::MAX / 1_000_000; +const TOKEN_MAX_AMOUNT: u64 = u64::MAX / TOKENS_PER_NAM; impl PosParams { /// Validate PoS parameters values. Returns an empty list if the values are diff --git a/shared/src/types/token.rs b/shared/src/types/token.rs index 787a8855dc5..b19642b85af 100644 --- a/shared/src/types/token.rs +++ b/shared/src/types/token.rs @@ -6,6 +6,7 @@ use std::ops::{Add, AddAssign, Mul, Sub, SubAssign}; use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use rust_decimal::prelude::{Decimal, ToPrimitive}; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -37,7 +38,6 @@ pub struct Amount { pub const MAX_DECIMAL_PLACES: u32 = 6; /// Decimal scale of token [`Amount`] and [`Change`]. pub const SCALE: u64 = 1_000_000; -const SCALE_F64: f64 = SCALE as f64; /// A change in tokens amount pub type Change = i128; @@ -109,21 +109,16 @@ impl<'de> serde::Deserialize<'de> for Amount { } } -impl From for f64 { - /// Warning: `f64` loses precision and it should not be used when exact - /// values are required. +impl From for Decimal { fn from(amount: Amount) -> Self { - amount.micro as f64 / SCALE_F64 + Into::::into(amount.micro) / Into::::into(SCALE) } } -impl From for Amount { - /// Warning: `f64` loses precision and it should not be used when exact - /// values are required. - fn from(micro: f64) -> Self { - Self { - micro: (micro * SCALE_F64).round() as u64, - } +impl From for Amount { + fn from(micro: Decimal) -> Self { + let res = (micro * Into::::into(SCALE)).to_u64().unwrap(); + Self { micro: res } } } @@ -205,7 +200,7 @@ impl FromStr for Amount { match rust_decimal::Decimal::from_str(s) { Ok(decimal) => { let scale = decimal.scale(); - if scale > 6 { + if scale > MAX_DECIMAL_PLACES { return Err(AmountParseError::ScaleTooLarge(scale)); } let whole = @@ -440,11 +435,11 @@ mod tests { /// The upper limit is set to `2^51`, because then the float is /// starting to lose precision. #[test] - fn test_token_amount_f64_conversion(raw_amount in 0..2_u64.pow(51)) { + fn test_token_amount_decimal_conversion(raw_amount in 0..2_u64.pow(51)) { let amount = Amount::from(raw_amount); - // A round-trip conversion to and from f64 should be an identity - let float = f64::from(amount); - let identity = Amount::from(float); + // A round-trip conversion to and from Decimal should be an identity + let decimal = Decimal::from(amount); + let identity = Amount::from(decimal); assert_eq!(amount, identity); } } diff --git a/tests/src/native_vp/pos.rs b/tests/src/native_vp/pos.rs index ec6f75a15f0..61b859a7d67 100644 --- a/tests/src/native_vp/pos.rs +++ b/tests/src/native_vp/pos.rs @@ -594,6 +594,10 @@ pub mod testing { use crate::tx::{self, tx_host_env}; + const TOKENS_PER_NAM: i128 = + namada::ledger::pos::namada_proof_of_stake::parameters::TOKENS_PER_NAM + as i128; + #[derive(Clone, Debug, Default)] pub struct TestValidator { pub address: Option
, @@ -940,9 +944,9 @@ pub mod testing { // We convert the tokens from micro units to whole tokens // with division by 10^6 let vp_before = - params.votes_per_token * ((total_delta) / 1_000_000); + params.votes_per_token * (total_delta / TOKENS_PER_NAM); let vp_after = params.votes_per_token - * ((total_delta + token_delta) / 1_000_000); + * ((total_delta + token_delta) / TOKENS_PER_NAM); // voting power delta let vp_delta = vp_after - vp_before; @@ -1001,12 +1005,12 @@ pub mod testing { let total_delta = validator_total_deltas .get(epoch) .unwrap_or_default(); - // We convert the tokens from micro units to whole + // We convert the tokens from micro units to whole // tokens with division by 10^6 let vp_before = params.votes_per_token - * ((total_delta) / 1_000_000); + * (total_delta / TOKENS_PER_NAM); let vp_after = params.votes_per_token - * ((total_delta + token_delta) / 1_000_000); + * ((total_delta + token_delta) / TOKENS_PER_NAM); // voting power delta let vp_delta_at_unbonding = vp_after - vp_before - vp_delta - total_vp_delta; @@ -1080,9 +1084,9 @@ pub mod testing { // We convert the tokens from micro units to whole tokens // with division by 10^6 let vp_before = params.votes_per_token - * ((total_delta_cur) / 1_000_000); + * (total_delta_cur / TOKENS_PER_NAM); let vp_after = params.votes_per_token - * ((total_delta_cur + token_delta) / 1_000_000); + * ((total_delta_cur + token_delta) / TOKENS_PER_NAM); // voting power delta let vp_delta = vp_after - vp_before; diff --git a/wasm/checksums.json b/wasm/checksums.json index a1c87f54a24..c78fa6b23ac 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,18 +1,18 @@ { - "tx_bond.wasm": "tx_bond.6d7080f701b1e33b551019ce470bdd958ba797fd4f00e9ff184c6ca3fadd3e73.wasm", - "tx_ibc.wasm": "tx_ibc.34769825ac819d9cf5027108737f65e28f8d1e63295b4091623f7a3d6a36d59c.wasm", - "tx_init_account.wasm": "tx_init_account.fd1618c90c333d46119260fc4ef4b098ccbaf06e5f0a324cf656b9aafaf509b4.wasm", - "tx_init_nft.wasm": "tx_init_nft.d6ed48ff375dd1c4d9d033f4e0e55414c3299db3e3702f81daba6a305a199d66.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.59a9ce4eb93029aa589986c6c5facdc96747ff3124bfc70dc9ba7d3a2861170c.wasm", - "tx_init_validator.wasm": "tx_init_validator.985ebce78fa966a5a34ea220741e12a03e67fb48cb06d919c86f738a91e90f5e.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.e7b3bed7c9d0a82647f2ee44a1396c773595908ce54ba00f76daa62cedecf916.wasm", - "tx_transfer.wasm": "tx_transfer.7fcd4a519f96fdcaa714f67d98e566183967a5ab8555059b7aa17e43dee27dce.wasm", - "tx_unbond.wasm": "tx_unbond.7c293ae770379a3034e940361d82476a93b46dde75391aaa8db448e2df3b74a1.wasm", + "tx_bond.wasm": "tx_bond.09ffd094e3095cce95c729e1eb08fa784f29c3d90ea8f994e048a780ab357865.wasm", + "tx_ibc.wasm": "tx_ibc.d02e54315b1bcf7da10cc6c3d88a00d578e89edf2debf92b909cfd3f8ba3d2e1.wasm", + "tx_init_account.wasm": "tx_init_account.ae600f95fba295ee51a4856ec8ef3c48fc712d64ad64d382e2ae70a9fdac044e.wasm", + "tx_init_nft.wasm": "tx_init_nft.3c5ca793c63291961690b9debe24572b1fe011f84a7b53140c3b0f6fdf3ace9a.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.837a38aba1909c841db75dd34b6a9ab3c45c08b79a5b7c9a0103c88418bd44d8.wasm", + "tx_init_validator.wasm": "tx_init_validator.948e0596241dded9102767be3fb1c3be59becef39a31c8c5fc1722b017a1ed40.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.55d72bbbd618e16c1aaac690d125fcf115753c98b19c0e294fcd3c89c9997608.wasm", + "tx_transfer.wasm": "tx_transfer.9c96035cee8346a0a40b5ca6426c5d772a212af3ab2f3a2728692de06283a4c7.wasm", + "tx_unbond.wasm": "tx_unbond.d83db308c11f882835d8cc707add21d0187fdddc3baea8472c4729ca0fc80f44.wasm", "tx_update_vp.wasm": "tx_update_vp.d2c49722f9c5b88f5656faa6a9f39ba6a8951ea63dab24368d6da4f7089e65bb.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.d988cb2cc87ef447edf437feb568e8b38114c7e313ab5303bf4d35d00f74d165.wasm", - "tx_withdraw.wasm": "tx_withdraw.4b9880f62deae5abce63536a506604623a1856960e2e8325b8a04f441d11c6d1.wasm", - "vp_nft.wasm": "vp_nft.9b439a32a68321777f5a65bf63e7c363b9aa6e8a39cc4d9e4c55cc7372417f1d.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.c03c638802ba7517e65768cea2a4ef07db411d575f363dacf65594c0654a5326.wasm", - "vp_token.wasm": "vp_token.424ef4dc000311e7f82834a5d809bbcafa4c6f7328590f56695226ff2042cfec.wasm", - "vp_user.wasm": "vp_user.782054d956bf086e3701cfed2d074cd1487ba023e131a6a3f15f526958f921b7.wasm" + "tx_vote_proposal.wasm": "tx_vote_proposal.3f668113b025aa2a9aa7d3a501630f681e80fcc86239d3cdb1b1b58aad785dbd.wasm", + "tx_withdraw.wasm": "tx_withdraw.2e3033d2fc290e3bef98da2f3b128b1f9c782edc675d0c5f17fc0873f32ad12d.wasm", + "vp_nft.wasm": "vp_nft.482722b5550198ea1be76801650f8a8dd0ac142e4f3499d3c222dacfaf8807bc.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.7fe2048d24f019945e31fb7eb1449199b05f4ff4a4f7aea064102c6f2ad9a818.wasm", + "vp_token.wasm": "vp_token.a9b08a35382df261111857ed2059beb9a8bb61344d926adfd576d557d52b0f69.wasm", + "vp_user.wasm": "vp_user.3c46e73b77adfa10b9cffed8f0ad7d792e8e64b4a40380aa023707fd710c17fe.wasm" } \ No newline at end of file