Skip to content
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Added Cargo example that derives bounds on shielded reward parameters to
ensure non-zero rewards ([\#4573](https://github.com/anoma/namada/pull/4573))
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 70 additions & 3 deletions crates/core/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,8 @@ impl DenominatedAmount {
}
}

/// Attempt to increase the precision of an amount. Can fail
/// if the resulting amount does not fit into 256 bits.
/// Return an equivalent denominated amount with the given denomination. Can
/// fail if the resulting amount does not fit into 256 bits.
pub fn increase_precision(
self,
denom: Denomination,
Expand All @@ -534,8 +534,43 @@ impl DenominatedAmount {
.ok_or(AmountParseError::PrecisionOverflow)
}

/// Return the closest denominated amount with the given denomination and
/// the error.
pub fn approximate(
self,
denom: Denomination,
) -> Result<(Self, Self), AmountParseError> {
if denom.0 < self.denom.0 {
// Divide numerator and denominator by a power of 10
let amount = self.amount.raw_amount();
#[allow(clippy::arithmetic_side_effects)]
let (quot, rem) = Uint::from(10)
.checked_pow(Uint::from(self.denom.0 - denom.0))
.and_then(|scaling| {
amount.checked_div(scaling).zip(amount.checked_rem(scaling))
})
.ok_or(AmountParseError::PrecisionOverflow)?;
let approx = Self {
amount: quot.into(),
denom,
};
let error = Self {
amount: rem.into(),
denom: self.denom,
};
Ok((approx, error))
} else {
// Multiply numerator and denominator by a power of 10
let error = Self {
amount: 0.into(),
denom: self.denom,
};
self.increase_precision(denom).map(|x| (x, error))
}
}

/// Create a new [`DenominatedAmount`] with the same underlying
/// amout but a new denomination.
/// amount but a new denomination.
pub fn redenominate(self, new_denom: u8) -> Self {
Self {
amount: self.amount,
Expand Down Expand Up @@ -590,6 +625,38 @@ impl DenominatedAmount {
})
}

/// Checked division computed to the given precision. Returns `None` on
/// overflow.
pub fn checked_div_precision(
&self,
rhs: DenominatedAmount,
denom: Denomination,
) -> Option<Self> {
#[allow(clippy::arithmetic_side_effects)]
let pow = i16::from(rhs.denom.0) + i16::from(denom.0)
- i16::from(self.denom.0);
if pow < 0 {
return None;
}
let amount = Uint::from(10).checked_pow(Uint::from(pow)).and_then(
|scaling| {
scaling.checked_mul_div(
self.amount.raw_amount(),
rhs.amount.raw_amount(),
)
},
)?;
Some(Self {
amount: amount.0.into(),
denom,
})
}

/// Checked division. Returns `None` on overflow.
pub fn checked_div(&self, rhs: DenominatedAmount) -> Option<Self> {
self.checked_div_precision(rhs, self.denom)
}

/// Returns the significand of this number
pub const fn amount(&self) -> Amount {
self.amount
Expand Down
6 changes: 6 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ version.workspace = true
name = "generate-txs"
path = "generate_txs.rs"

[[example]]
name = "shielded-rewards"
path = "shielded_rewards.rs"

[[example]]
name = "tx-schema"
path = "tx_schema.rs"
Expand Down Expand Up @@ -52,5 +56,7 @@ borsh.workspace = true
data-encoding.workspace = true
linkme.workspace = true
proptest.workspace = true
serde.workspace = true
serde_json.workspace = true
tokio = { workspace = true, default-features = false }
toml.workspace = true
Loading
Loading