Skip to content

Commit

Permalink
move rest of token fns from tx_prelude to namada_token::tx
Browse files Browse the repository at this point in the history
  • Loading branch information
tzemanovic committed Sep 8, 2024
1 parent ce9a7d9 commit 5713411
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 170 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion crates/core/src/masp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use borsh_ext::BorshSerializeExt;
use masp_primitives::asset_type::AssetType;
use masp_primitives::sapling::ViewingKey;
use masp_primitives::transaction::TransparentAddress;
pub use masp_primitives::transaction::TxId as TxIdInner;
pub use masp_primitives::transaction::{
Transaction as MaspTransaction, TxId as TxIdInner,
};
use namada_macros::BorshDeserializer;
#[cfg(feature = "migrations")]
use namada_migrations::*;
Expand Down
5 changes: 3 additions & 2 deletions crates/shielded_token/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ pub mod vp;

use std::str::FromStr;

pub use masp_primitives::transaction::Transaction as MaspTransaction;
use namada_core::borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
pub use namada_core::dec::Dec;
pub use namada_core::masp::{MaspEpoch, MaspTxId, MaspTxRefs, MaspValue};
pub use namada_core::masp::{
MaspEpoch, MaspTransaction, MaspTxId, MaspTxRefs, MaspValue,
};
pub use namada_state::{
ConversionLeaf, ConversionState, Error, Key, OptionExt, Result, ResultExt,
StorageRead, StorageWrite, WithConversionState,
Expand Down
3 changes: 3 additions & 0 deletions crates/token/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ namada_events = { path = "../events", default-features = false }
namada_macros = { path = "../macros" }
namada_migrations = { path = "../migrations", optional = true }
namada_shielded_token = { path = "../shielded_token" }
namada_storage = { path = "../storage" }
namada_systems = { path = "../systems" }
namada_trans_token = { path = "../trans_token" }
namada_tx = { path = "../tx" }
namada_tx_env = { path = "../tx_env" }

arbitrary = { workspace = true, optional = true }
borsh.workspace = true
Expand Down
175 changes: 174 additions & 1 deletion crates/token/src/tx.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,176 @@
//! Token transaction

pub use namada_trans_token::tx::transfer as transparent_transfer;
use std::collections::{BTreeMap, BTreeSet};

use namada_core::collections::HashSet;
use namada_core::masp;
use namada_events::{EmitEvents, EventLevel};
use namada_shielded_token::{utils, MaspTxId};
use namada_storage::{Error, OptionExt, ResultExt};
use namada_trans_token::event::{TokenEvent, TokenOperation};
pub use namada_trans_token::tx::transfer;
use namada_trans_token::UserAccount;
use namada_tx::action::{self, Action, MaspAction};
use namada_tx::BatchedTx;
use namada_tx_env::{Address, Result, TxEnv};

use crate::{Transfer, TransparentTransfersRef};

/// Transparent and shielded token transfers that can be used in a transaction.
pub fn multi_transfer<ENV>(
env: &mut ENV,
transfers: Transfer,
tx_data: &BatchedTx,
) -> Result<()>
where
ENV: TxEnv + EmitEvents + action::Write<Err = Error>,
{
// Effect the transparent multi transfer(s)
let debited_accounts =
if let Some(transparent) = transfers.transparent_part() {
apply_transparent_transfers(env, transparent)
.wrap_err("Transparent token transfer failed")?
} else {
HashSet::new()
};

// Apply the shielded transfer if there is a link to one
if let Some(masp_section_ref) = transfers.shielded_section_hash {
apply_shielded_transfer(
env,
masp_section_ref,
debited_accounts,
tx_data,
)
.wrap_err("Shielded token transfer failed")?;
}
Ok(())
}

/// Transfer tokens from `sources` to `targets` and submit a transfer event.
/// Returns an `Err` if any source has insufficient balance or if the transfer
/// to any destination would overflow (This can only happen if the total supply
/// doesn't fit in `token::Amount`). Returns a set of debited accounts.
pub fn apply_transparent_transfers<ENV>(
env: &mut ENV,
transfers: TransparentTransfersRef<'_>,
) -> Result<HashSet<Address>>
where
ENV: TxEnv + EmitEvents,
{
let sources = transfers.sources();
let targets = transfers.targets();
let debited_accounts =
namada_trans_token::multi_transfer(env, &sources, &targets)?;

let mut evt_sources = BTreeMap::new();
let mut evt_targets = BTreeMap::new();
let mut post_balances = BTreeMap::new();

for ((src, token), amount) in sources {
// The tx must be authorized by the source address
env.insert_verifier(&src)?;
if token.is_internal() {
// Established address tokens do not have VPs themselves, their
// validation is handled by the `Multitoken` internal address,
// but internal token addresses have to verify
// the transfer
env.insert_verifier(&token)?;
}
evt_sources.insert(
(UserAccount::Internal(src.clone()), token.clone()),
amount.into(),
);
post_balances.insert(
(UserAccount::Internal(src.clone()), token.clone()),
crate::read_balance(env, &token, &src)?.into(),
);
}

for ((target, token), amount) in targets {
if token.is_internal() {
// Established address tokens do not have VPs themselves, their
// validation is handled by the `Multitoken` internal address,
// but internal token addresses have to verify
// the transfer
env.insert_verifier(&token)?;
}
evt_targets.insert(
(UserAccount::Internal(target.clone()), token.clone()),
amount.into(),
);
post_balances.insert(
(UserAccount::Internal(target.clone()), token.clone()),
crate::read_balance(env, &token, &target)?.into(),
);
}

env.emit(TokenEvent {
descriptor: "transfer-from-wasm".into(),
level: EventLevel::Tx,
operation: TokenOperation::Transfer {
sources: evt_sources,
targets: evt_targets,
post_balances,
},
});

Ok(debited_accounts)
}

/// Apply a shielded transfer
pub fn apply_shielded_transfer<ENV>(
env: &mut ENV,
masp_section_ref: MaspTxId,
debited_accounts: HashSet<Address>,
tx_data: &BatchedTx,
) -> Result<()>
where
ENV: TxEnv + EmitEvents + action::Write<Err = Error>,
{
let shielded = tx_data
.tx
.get_masp_section(&masp_section_ref)
.cloned()
.ok_or_err_msg("Unable to find required shielded section in tx data")
.map_err(|err| {
env.set_commitment_sentinel();
err
})?;
utils::handle_masp_tx(env, &shielded)
.wrap_err("Encountered error while handling MASP transaction")?;
ENV::update_masp_note_commitment_tree(&shielded)
.wrap_err("Failed to update the MASP commitment tree")?;

env.push_action(Action::Masp(MaspAction::MaspSectionRef(
masp_section_ref,
)))?;
// Extract the debited accounts for the masp part of the transfer and
// push the relative actions
let vin_addresses =
shielded
.transparent_bundle()
.map_or_else(Default::default, |bndl| {
bndl.vin
.iter()
.map(|vin| vin.address)
.collect::<BTreeSet<_>>()
});
let masp_authorizers: Vec<_> = debited_accounts
.into_iter()
.filter(|account| {
vin_addresses.contains(&masp::addr_taddr(account.clone()))
})
.collect();
if masp_authorizers.len() != vin_addresses.len() {
return Err(Error::SimpleMessage(
"Transfer transaction does not debit all the expected accounts",
));
}

for authorizer in masp_authorizers {
env.push_action(Action::Masp(MaspAction::MaspAuthorizer(authorizer)))?;
}

Ok(())
}
6 changes: 6 additions & 0 deletions crates/tx_env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub use namada_core::address::Address;
pub use namada_core::borsh::{
BorshDeserialize, BorshSerialize, BorshSerializeExt,
};
pub use namada_core::masp::MaspTransaction;
pub use namada_core::storage;
pub use namada_events::{Event, EventToEmit, EventType};
pub use namada_storage::{Result, ResultExt, StorageRead, StorageWrite};
Expand Down Expand Up @@ -103,4 +104,9 @@ pub trait TxEnv: StorageRead + StorageWrite {

/// Set the sentinel for an invalid section commitment
fn set_commitment_sentinel(&mut self);

/// Update the masp note commitment tree in storage with the new notes
fn update_masp_note_commitment_tree(
transaction: &MaspTransaction,
) -> Result<bool>;
}
2 changes: 1 addition & 1 deletion crates/tx_prelude/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl IbcStorageContext for Ctx {
token: &Address,
amount: Amount,
) -> Result<()> {
token::tx::transparent_transfer(self, src, dest, token, amount)
token::transfer(self, src, dest, token, amount)
}

fn mint_token(
Expand Down
6 changes: 6 additions & 0 deletions crates/tx_prelude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,12 @@ impl TxEnv for Ctx {
fn set_commitment_sentinel(&mut self) {
unsafe { namada_tx_set_commitment_sentinel() }
}

fn update_masp_note_commitment_tree(
transaction: &MaspTransaction,
) -> Result<bool> {
update_masp_note_commitment_tree(transaction)
}
}

impl namada_tx::action::Read for Ctx {
Expand Down
Loading

0 comments on commit 5713411

Please sign in to comment.