Skip to content

Commit

Permalink
Hashed the token denomination into AssetTypes to tighten HW wallet si…
Browse files Browse the repository at this point in the history
…gning.
  • Loading branch information
murisi committed Jan 22, 2024
1 parent 9b8a9de commit 75076bd
Show file tree
Hide file tree
Showing 11 changed files with 300 additions and 150 deletions.
11 changes: 7 additions & 4 deletions apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2355,7 +2355,7 @@ pub async fn query_conversions(
.expect("Conversions should be defined");
// Track whether any non-sentinel conversions are found
let mut conversions_found = false;
for (addr, epoch, amt) in conversions.values() {
for (addr, _denom, digit, epoch, amt) in conversions.values() {
// If the user has specified any targets, then meet them
// If we have a sentinel conversion, then skip printing
if matches!(&target_token, Some(target) if target != addr)
Expand All @@ -2368,23 +2368,25 @@ pub async fn query_conversions(
// Print the asset to which the conversion applies
display!(
context.io(),
"{}[{}]: ",
"{}*2^{}[{}]: ",
tokens.get(addr).cloned().unwrap_or_else(|| addr.clone()),
*digit as u8 * 64,
epoch,
);
// Now print out the components of the allowed conversion
let mut prefix = "";
for (asset_type, val) in amt.components() {
// Look up the address and epoch of asset to facilitate pretty
// printing
let (addr, epoch, _) = &conversions[asset_type];
let (addr, _denom, digit, epoch, _) = &conversions[asset_type];
// Now print out this component of the conversion
display!(
context.io(),
"{}{} {}[{}]",
"{}{} {}*2^{}[{}]",
prefix,
val,
tokens.get(addr).cloned().unwrap_or_else(|| addr.clone()),
*digit as u8 * 64,
epoch
);
// Future iterations need to be prefixed with +
Expand All @@ -2407,6 +2409,7 @@ pub async fn query_conversion<C: namada::ledger::queries::Client + Sync>(
asset_type: AssetType,
) -> Option<(
Address,
token::Denomination,
MaspDenom,
Epoch,
masp_primitives::transaction::components::I128Sum,
Expand Down
87 changes: 60 additions & 27 deletions core/src/ledger/masp_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::ledger::storage_api::{StorageRead, StorageWrite};
use crate::types::address::{Address, MASP};
use crate::types::dec::Dec;
use crate::types::storage::Epoch;
use crate::types::token::{self, DenominatedAmount, MaspDenom};
use crate::types::token::{self, DenominatedAmount, Denomination, MaspDenom};
use crate::types::uint::Uint;

/// A representation of the conversion state
Expand All @@ -32,7 +32,12 @@ pub struct ConversionState {
#[allow(clippy::type_complexity)]
pub assets: BTreeMap<
AssetType,
((Address, MaspDenom), Epoch, AllowedConversion, usize),
(
(Address, Denomination, MaspDenom),
Epoch,
AllowedConversion,
usize,
),
>,
}

Expand All @@ -41,7 +46,7 @@ pub struct ConversionState {
pub fn calculate_masp_rewards<D, H>(
wl_storage: &mut WlStorage<D, H>,
addr: &Address,
) -> crate::ledger::storage_api::Result<(u128, u128)>
) -> crate::ledger::storage_api::Result<((u128, u128), Denomination)>
where
D: 'static + DB + for<'iter> DBIter<'iter>,
H: 'static + StorageHasher,
Expand Down Expand Up @@ -188,7 +193,7 @@ where

wl_storage.write(&token::masp_last_locked_ratio_key(addr), locked_ratio)?;

Ok((noterized_inflation, precision))
Ok(((noterized_inflation, precision), denomination))
}

// This is only enabled when "wasm-runtime" is on, because we're using rayon
Expand All @@ -214,7 +219,9 @@ where
use crate::ledger::storage_api::ResultExt;
use crate::types::masp::encode_asset_type;
use crate::types::storage::{Key, KeySeg};
use crate::types::token::MASP_CONVERT_ANCHOR_KEY;
use crate::types::token::{
MASP_CONVERT_ANCHOR_KEY, NATIVE_MAX_DECIMAL_PLACES,
};

// The derived conversions will be placed in MASP address space
let masp_addr = MASP;
Expand All @@ -226,6 +233,7 @@ where
.values()
.cloned()
.collect();
let mut masp_reward_denoms = BTreeMap::new();
// Put the native rewards first because other inflation computations depend
// on it
let native_token = wl_storage.storage.native_token.clone();
Expand All @@ -246,23 +254,45 @@ where
// notes clients have to use. This trick works under the assumption that
// reward tokens will then be reinflated back to the current epoch.
let reward_assets = [
encode_asset_type(Some(Epoch(0)), &native_token, MaspDenom::Zero)
.into_storage_result()?,
encode_asset_type(Some(Epoch(0)), &native_token, MaspDenom::One)
.into_storage_result()?,
encode_asset_type(Some(Epoch(0)), &native_token, MaspDenom::Two)
.into_storage_result()?,
encode_asset_type(Some(Epoch(0)), &native_token, MaspDenom::Three)
.into_storage_result()?,
encode_asset_type(
Some(Epoch(0)),
&native_token,
NATIVE_MAX_DECIMAL_PLACES.into(),
MaspDenom::Zero,
)
.into_storage_result()?,
encode_asset_type(
Some(Epoch(0)),
&native_token,
NATIVE_MAX_DECIMAL_PLACES.into(),
MaspDenom::One,
)
.into_storage_result()?,
encode_asset_type(
Some(Epoch(0)),
&native_token,
NATIVE_MAX_DECIMAL_PLACES.into(),
MaspDenom::Two,
)
.into_storage_result()?,
encode_asset_type(
Some(Epoch(0)),
&native_token,
NATIVE_MAX_DECIMAL_PLACES.into(),
MaspDenom::Three,
)
.into_storage_result()?,
];
// Conversions from the previous to current asset for each address
let mut current_convs =
BTreeMap::<(Address, MaspDenom), AllowedConversion>::new();
BTreeMap::<(Address, Denomination, MaspDenom), AllowedConversion>::new(
);
// Native token inflation values are always with respect to this
let mut ref_inflation = 0;
// Reward all tokens according to above reward rates
for addr in &masp_reward_keys {
let reward = calculate_masp_rewards(wl_storage, addr)?;
let (reward, denom) = calculate_masp_rewards(wl_storage, addr)?;
masp_reward_denoms.insert(addr, denom);
if *addr == native_token {
// The reference inflation is the denominator of the native token
// inflation, which is always a constant
Expand All @@ -272,20 +302,22 @@ where
let addr_bal: token::Amount = wl_storage
.read(&token::balance_key(addr, &masp_addr))?
.unwrap_or_default();
for denom in token::MaspDenom::iter() {
for digit in token::MaspDenom::iter() {
// Provide an allowed conversion from previous timestamp. The
// negative sign allows each instance of the old asset to be
// cancelled out/replaced with the new asset
let old_asset = encode_asset_type(
Some(wl_storage.storage.last_epoch),
addr,
denom,
digit,
)
.into_storage_result()?;
let new_asset = encode_asset_type(
Some(wl_storage.storage.block.epoch),
addr,
denom,
digit,
)
.into_storage_result()?;
// Get the last rewarded amount of the native token
Expand Down Expand Up @@ -318,7 +350,7 @@ where
// intermediate native tokens cancel/
// telescope out
current_convs.insert(
(addr.clone(), denom),
(addr.clone(), denom, digit),
(MaspAmount::from_pair(
old_asset,
-(*normed_inflation as i128),
Expand All @@ -332,7 +364,7 @@ where
.into(),
);
// Operations that happen exactly once for each token
if denom == MaspDenom::Three {
if digit == MaspDenom::Three {
// The reward for each reward.1 units of the current asset
// is reward.0 units of the reward token
let native_reward =
Expand Down Expand Up @@ -367,20 +399,20 @@ where
// conversions are added together, the
// intermediate tokens cancel/ telescope out
current_convs.insert(
(addr.clone(), denom),
(addr.clone(), denom, digit),
(MaspAmount::from_pair(old_asset, -(reward.1 as i128))
.unwrap()
+ MaspAmount::from_pair(new_asset, reward.1 as i128)
.unwrap()
+ MaspAmount::from_pair(
reward_assets[denom as usize],
reward_assets[digit as usize],
real_reward as i128,
)
.unwrap())
.into(),
);
// Operations that happen exactly once for each token
if denom == MaspDenom::Three {
if digit == MaspDenom::Three {
// The reward for each reward.1 units of the current asset
// is reward.0 units of the reward token
total_reward += (addr_bal * (reward.0, reward.1)).0;
Expand All @@ -390,7 +422,7 @@ where
wl_storage.storage.conversion_state.assets.insert(
old_asset,
(
(addr.clone(), denom),
(addr.clone(), denom, digit),
wl_storage.storage.last_epoch,
MaspAmount::zero().into(),
0,
Expand Down Expand Up @@ -470,20 +502,21 @@ where

// Add purely decoding entries to the assets map. These will be
// overwritten before the creation of the next commitment tree
for addr in masp_reward_keys {
for denom in token::MaspDenom::iter() {
for (addr, denom) in masp_reward_denoms {
for digit in token::MaspDenom::iter() {
// Add the decoding entry for the new asset type. An uncommitted
// node position is used since this is not a conversion.
let new_asset = encode_asset_type(
Some(wl_storage.storage.block.epoch),
&addr,
addr,
denom,
digit,
)
.into_storage_result()?;
wl_storage.storage.conversion_state.assets.insert(
new_asset,
(
(addr.clone(), denom),
(addr.clone(), denom, digit),
wl_storage.storage.block.epoch,
MaspAmount::zero().into(),
wl_storage.storage.conversion_state.tree.size(),
Expand Down Expand Up @@ -604,7 +637,7 @@ mod tests {
}
}

pub fn tokens() -> HashMap<Address, (&'static str, token::Denomination)> {
pub fn tokens() -> HashMap<Address, (&'static str, Denomination)> {
vec![
(address::nam(), ("nam", 6.into())),
(address::btc(), ("btc", 8.into())),
Expand Down
4 changes: 3 additions & 1 deletion core/src/proto/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::types::keccak::{keccak_hash, KeccakHash};
use crate::types::key::{self, *};
use crate::types::storage::Epoch;
use crate::types::time::DateTimeUtc;
use crate::types::token;
use crate::types::token::MaspDenom;
use crate::types::transaction::protocol::ProtocolTx;
use crate::types::transaction::{
Expand Down Expand Up @@ -767,7 +768,8 @@ pub struct MaspBuilder {
pub target: crate::types::hash::Hash,
/// The decoded set of asset types used by the transaction. Useful for
/// offline wallets trying to display AssetTypes.
pub asset_types: HashSet<(Address, MaspDenom, Option<Epoch>)>,
pub asset_types:
HashSet<(Address, token::Denomination, MaspDenom, Option<Epoch>)>,
/// Track how Info objects map to descriptors and outputs
#[serde(
serialize_with = "borsh_serde::<SaplingMetadataSerde, _>",
Expand Down
7 changes: 4 additions & 3 deletions core/src/types/masp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ use crate::types::string_encoding::{
self, MASP_EXT_FULL_VIEWING_KEY_HRP, MASP_EXT_SPENDING_KEY_HRP,
MASP_PAYMENT_ADDRESS_HRP,
};
use crate::types::token::MaspDenom;
use crate::types::token::{Denomination, MaspDenom};

/// Make asset type corresponding to given address and epoch
pub fn encode_asset_type(
epoch: Option<Epoch>,
token: &Address,
denom: MaspDenom,
denom: Denomination,
digit: MaspDenom,
) -> Result<AssetType, std::io::Error> {
// Timestamp the chosen token with the current epoch
let token_bytes = (token, denom, epoch).serialize_to_vec();
let token_bytes = (token, denom, digit, epoch).serialize_to_vec();
// Generate the unique asset identifier from the unique token address
AssetType::new(token_bytes.as_ref()).map_err(|_| {
std::io::Error::new(
Expand Down
14 changes: 10 additions & 4 deletions sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1033,15 +1033,21 @@ pub mod testing {
MaspTxType::Shielding => {
transfer.target = MASP;
// Set the transparent amount and token
let ((addr, denom, _epoch), value) = asset_types.iter().next().unwrap();
transfer.amount = DenominatedAmount::native(token::Amount::from_masp_denominated(*value, *denom));
let ((addr, denom, digit, _epoch), value) = asset_types.iter().next().unwrap();
transfer.amount = DenominatedAmount::new(
token::Amount::from_masp_denominated(*value, *digit),
*denom,
);
transfer.token = addr.clone();
},
MaspTxType::Deshielding => {
transfer.source = MASP;
// Set the transparent amount and token
let ((addr, denom, _epoch), value) = asset_types.iter().next().unwrap();
transfer.amount = DenominatedAmount::native(token::Amount::from_masp_denominated(*value, *denom));
let ((addr, denom, digit, _epoch), value) = asset_types.iter().next().unwrap();
transfer.amount = DenominatedAmount::new(
token::Amount::from_masp_denominated(*value, *digit),
*denom,
);
transfer.token = addr.clone();
},
}
Expand Down
Loading

0 comments on commit 75076bd

Please sign in to comment.