diff --git a/.changelog/unreleased/improvements/3297-split-transfer-tx.md b/.changelog/unreleased/improvements/3297-split-transfer-tx.md new file mode 100644 index 0000000000..a4a8b2fa4c --- /dev/null +++ b/.changelog/unreleased/improvements/3297-split-transfer-tx.md @@ -0,0 +1,6 @@ +- The transfer command has been split into: + - `transfer` (shielded transfer) + - `transparent-transfer` + - `shield` (from transparent to shielded) + - `unshield` (from shielded to transparent) + ([\#3297](https://github.com/anoma/namada/pull/3297)) \ No newline at end of file diff --git a/.github/workflows/scripts/hermes.txt b/.github/workflows/scripts/hermes.txt index 7588db229e..7258f5d5db 100644 --- a/.github/workflows/scripts/hermes.txt +++ b/.github/workflows/scripts/hermes.txt @@ -1 +1 @@ -1.8.2-namada-beta10-rc +1.8.2-namada-beta11-rc diff --git a/Cargo.lock b/Cargo.lock index 40787e4c1c..ce37252eb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5423,11 +5423,15 @@ dependencies = [ name = "namada_token" version = "0.38.1" dependencies = [ + "borsh 1.2.1", "namada_core", "namada_events", + "namada_macros", "namada_shielded_token", "namada_storage", "namada_trans_token", + "proptest", + "serde", ] [[package]] diff --git a/crates/apps/src/bin/namada/cli.rs b/crates/apps/src/bin/namada/cli.rs index 9b97f2e761..ac56cd02d3 100644 --- a/crates/apps/src/bin/namada/cli.rs +++ b/crates/apps/src/bin/namada/cli.rs @@ -45,7 +45,10 @@ fn handle_command(cmd: cli::cmds::Namada, raw_sub_cmd: String) -> Result<()> { } cli::cmds::Namada::Client(_) | cli::cmds::Namada::TxCustom(_) - | cli::cmds::Namada::TxTransfer(_) + | cli::cmds::Namada::TxTransparentTransfer(_) + | cli::cmds::Namada::TxShieldedTransfer(_) + | cli::cmds::Namada::TxShieldingTransfer(_) + | cli::cmds::Namada::TxUnshieldingTransfer(_) | cli::cmds::Namada::TxIbcTransfer(_) | cli::cmds::Namada::TxUpdateAccount(_) | cli::cmds::Namada::TxRevealPk(_) diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index 88e00d6485..78284f2c99 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -57,7 +57,10 @@ pub mod cmds { // Inlined commands from the client. TxCustom(TxCustom), - TxTransfer(TxTransfer), + TxTransparentTransfer(TxTransparentTransfer), + TxShieldedTransfer(TxShieldedTransfer), + TxShieldingTransfer(TxShieldingTransfer), + TxUnshieldingTransfer(TxUnshieldingTransfer), TxIbcTransfer(TxIbcTransfer), TxUpdateAccount(TxUpdateAccount), TxInitProposal(TxInitProposal), @@ -74,7 +77,10 @@ pub mod cmds { .subcommand(EthBridgePool::def()) .subcommand(Ledger::def()) .subcommand(TxCustom::def()) - .subcommand(TxTransfer::def()) + .subcommand(TxTransparentTransfer::def()) + .subcommand(TxShieldedTransfer::def()) + .subcommand(TxShieldingTransfer::def()) + .subcommand(TxUnshieldingTransfer::def()) .subcommand(TxIbcTransfer::def()) .subcommand(TxUpdateAccount::def()) .subcommand(TxInitProposal::def()) @@ -91,7 +97,14 @@ pub mod cmds { let wallet = SubCmd::parse(matches).map(Self::Wallet); let ledger = SubCmd::parse(matches).map(Self::Ledger); let tx_custom = SubCmd::parse(matches).map(Self::TxCustom); - let tx_transfer = SubCmd::parse(matches).map(Self::TxTransfer); + let tx_transparent_transfer = + SubCmd::parse(matches).map(Self::TxTransparentTransfer); + let tx_shielded_transfer = + SubCmd::parse(matches).map(Self::TxShieldedTransfer); + let tx_shielding_transfer = + SubCmd::parse(matches).map(Self::TxShieldingTransfer); + let tx_unshielding_transfer = + SubCmd::parse(matches).map(Self::TxUnshieldingTransfer); let tx_ibc_transfer = SubCmd::parse(matches).map(Self::TxIbcTransfer); let tx_update_account = @@ -107,7 +120,10 @@ pub mod cmds { .or(wallet) .or(ledger) .or(tx_custom) - .or(tx_transfer) + .or(tx_transparent_transfer) + .or(tx_shielded_transfer) + .or(tx_shielding_transfer) + .or(tx_unshielding_transfer) .or(tx_ibc_transfer) .or(tx_update_account) .or(tx_init_proposal) @@ -218,7 +234,10 @@ pub mod cmds { app // Simple transactions .subcommand(TxCustom::def().display_order(1)) - .subcommand(TxTransfer::def().display_order(1)) + .subcommand(TxTransparentTransfer::def().display_order(1)) + .subcommand(TxShieldedTransfer::def().display_order(1)) + .subcommand(TxShieldingTransfer::def().display_order(1)) + .subcommand(TxUnshieldingTransfer::def().display_order(1)) .subcommand(TxIbcTransfer::def().display_order(1)) .subcommand(TxUpdateAccount::def().display_order(1)) .subcommand(TxInitAccount::def().display_order(1)) @@ -280,7 +299,14 @@ pub mod cmds { fn parse(matches: &ArgMatches) -> Option { use NamadaClientWithContext::*; let tx_custom = Self::parse_with_ctx(matches, TxCustom); - let tx_transfer = Self::parse_with_ctx(matches, TxTransfer); + let tx_transparent_transfer = + Self::parse_with_ctx(matches, TxTransparentTransfer); + let tx_shielded_transfer = + Self::parse_with_ctx(matches, TxShieldedTransfer); + let tx_shielding_transfer = + Self::parse_with_ctx(matches, TxShieldingTransfer); + let tx_unshielding_transfer = + Self::parse_with_ctx(matches, TxUnshieldingTransfer); let tx_ibc_transfer = Self::parse_with_ctx(matches, TxIbcTransfer); let tx_update_account = Self::parse_with_ctx(matches, TxUpdateAccount); @@ -356,7 +382,10 @@ pub mod cmds { let shielded_sync = Self::parse_with_ctx(matches, ShieldedSync); let utils = SubCmd::parse(matches).map(Self::WithoutContext); tx_custom - .or(tx_transfer) + .or(tx_transparent_transfer) + .or(tx_shielded_transfer) + .or(tx_shielding_transfer) + .or(tx_unshielding_transfer) .or(tx_ibc_transfer) .or(tx_update_account) .or(tx_init_account) @@ -443,7 +472,10 @@ pub mod cmds { pub enum NamadaClientWithContext { // Ledger cmds TxCustom(TxCustom), - TxTransfer(TxTransfer), + TxTransparentTransfer(TxTransparentTransfer), + TxShieldedTransfer(TxShieldedTransfer), + TxShieldingTransfer(TxShieldingTransfer), + TxUnshieldingTransfer(TxUnshieldingTransfer), TxIbcTransfer(TxIbcTransfer), QueryResult(QueryResult), TxUpdateAccount(TxUpdateAccount), @@ -1249,21 +1281,90 @@ pub mod cmds { } #[derive(Clone, Debug)] - pub struct TxTransfer(pub args::TxTransfer); + pub struct TxTransparentTransfer( + pub args::TxTransparentTransfer, + ); + + impl SubCmd for TxTransparentTransfer { + const CMD: &'static str = "transparent-transfer"; + + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + TxTransparentTransfer(args::TxTransparentTransfer::parse( + matches, + )) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about(wrap!("Send a transparent transfer transaction.")) + .add_args::>() + } + } + + #[derive(Clone, Debug)] + pub struct TxShieldedTransfer( + pub args::TxShieldedTransfer, + ); - impl SubCmd for TxTransfer { + impl SubCmd for TxShieldedTransfer { const CMD: &'static str = "transfer"; fn parse(matches: &ArgMatches) -> Option { - matches - .subcommand_matches(Self::CMD) - .map(|matches| TxTransfer(args::TxTransfer::parse(matches))) + matches.subcommand_matches(Self::CMD).map(|matches| { + TxShieldedTransfer(args::TxShieldedTransfer::parse(matches)) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about(wrap!("Send a shielded transfer transaction (from a shielded address to a shielded address).")) + .add_args::>() + } + } + + #[derive(Clone, Debug)] + pub struct TxShieldingTransfer( + pub args::TxShieldingTransfer, + ); + + impl SubCmd for TxShieldingTransfer { + const CMD: &'static str = "shield"; + + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + TxShieldingTransfer(args::TxShieldingTransfer::parse(matches)) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about(wrap!("Send a shielding transfer transaction (from a transparent address to a shielded address).")) + .add_args::>() + } + } + + #[derive(Clone, Debug)] + pub struct TxUnshieldingTransfer( + pub args::TxUnshieldingTransfer, + ); + + impl SubCmd for TxUnshieldingTransfer { + const CMD: &'static str = "unshield"; + + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + TxUnshieldingTransfer(args::TxUnshieldingTransfer::parse( + matches, + )) + }) } fn def() -> App { App::new(Self::CMD) - .about(wrap!("Send a signed transfer transaction.")) - .add_args::>() + .about(wrap!("Send an unshielding transfer transaction (from a shielded address to a transparent address).")) + .add_args::>() } } @@ -2997,10 +3098,11 @@ pub mod args { TX_CHANGE_METADATA_WASM, TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL, TX_REACTIVATE_VALIDATOR_WASM, TX_REDELEGATE_WASM, - TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_TRANSFER_WASM, TX_UNBOND_WASM, - TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, - TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, - VP_USER_WASM, + TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_SHIELDED_TRANSFER_WASM, + TX_SHIELDING_TRANSFER_WASM, TX_TRANSPARENT_TRANSFER_WASM, + TX_UNBOND_WASM, TX_UNJAIL_VALIDATOR_WASM, TX_UNSHIELDING_TRANSFER_WASM, + TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, + TX_WITHDRAW_WASM, VP_USER_WASM, }; use namada_sdk::DEFAULT_GAS_LIMIT; @@ -3184,6 +3286,7 @@ pub mod args { pub const OWNER_OPT: ArgOpt = OWNER.opt(); pub const PATH: Arg = arg("path"); pub const PATH_OPT: ArgOpt = arg_opt("path"); + pub const PAYMENT_ADDRESS_TARGET: Arg = arg("target"); pub const PORT_ID: ArgDefault = arg_default( "port-id", DefaultFn(|| PortId::from_str("transfer").unwrap()), @@ -3234,12 +3337,14 @@ pub mod args { pub const SIGNATURES: ArgMulti = arg_multi("signatures"); pub const SOURCE: Arg = arg("source"); pub const SOURCE_OPT: ArgOpt = SOURCE.opt(); + pub const SOURCE_VALIDATOR: Arg = arg("source-validator"); + pub const SPENDING_KEY_SOURCE: Arg = arg("source"); pub const SPENDING_KEYS: ArgMulti = arg_multi("spending-keys"); pub const STEWARD: Arg = arg("steward"); - pub const SOURCE_VALIDATOR: Arg = arg("source-validator"); pub const STORAGE_KEY: Arg = arg("storage-key"); pub const SUSPEND_ACTION: ArgFlag = flag("suspend"); + pub const TARGET: Arg = arg("target"); pub const TEMPLATES_PATH: Arg = arg("templates-path"); pub const TIMEOUT_HEIGHT: ArgOpt = arg_opt("timeout-height"); pub const TIMEOUT_SEC_OFFSET: ArgOpt = arg_opt("timeout-sec-offset"); @@ -4221,19 +4326,21 @@ pub mod args { } } - impl CliToSdk> for TxTransfer { + impl CliToSdk> + for TxTransparentTransfer + { type Error = std::io::Error; fn to_sdk( self, ctx: &mut Context, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { let tx = self.tx.to_sdk(ctx)?; let chain_ctx = ctx.borrow_mut_chain_or_exit(); - Ok(TxTransfer:: { + Ok(TxTransparentTransfer:: { tx, - source: chain_ctx.get_cached(&self.source), + source: chain_ctx.get(&self.source), target: chain_ctx.get(&self.target), token: chain_ctx.get(&self.token), amount: self.amount, @@ -4242,14 +4349,14 @@ pub mod args { } } - impl Args for TxTransfer { + impl Args for TxTransparentTransfer { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); - let source = TRANSFER_SOURCE.parse(matches); - let target = TRANSFER_TARGET.parse(matches); + let source = SOURCE.parse(matches); + let target = TARGET.parse(matches); let token = TOKEN.parse(matches); let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); - let tx_code_path = PathBuf::from(TX_TRANSFER_WASM); + let tx_code_path = PathBuf::from(TX_TRANSPARENT_TRANSFER_WASM); Self { tx, source, @@ -4262,15 +4369,193 @@ pub mod args { fn def(app: App) -> App { app.add_args::>() - .arg(TRANSFER_SOURCE.def().help(wrap!( + .arg(SOURCE.def().help(wrap!( "The source account address. The source's key may be used \ to produce the signature." ))) - .arg(TRANSFER_TARGET.def().help(wrap!( - "The target account address. The target's key may be used \ - to produce the signature." + .arg(TARGET.def().help(wrap!("The target account address."))) + .arg(TOKEN.def().help(wrap!("The token address."))) + .arg( + AMOUNT + .def() + .help(wrap!("The amount to transfer in decimal.")), + ) + } + } + + impl CliToSdk> for TxShieldedTransfer { + type Error = std::io::Error; + + fn to_sdk( + self, + ctx: &mut Context, + ) -> Result, Self::Error> { + let tx = self.tx.to_sdk(ctx)?; + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + + Ok(TxShieldedTransfer:: { + tx, + source: chain_ctx.get_cached(&self.source), + target: chain_ctx.get(&self.target), + token: chain_ctx.get(&self.token), + amount: self.amount, + tx_code_path: self.tx_code_path.to_path_buf(), + }) + } + } + + impl Args for TxShieldedTransfer { + fn parse(matches: &ArgMatches) -> Self { + let tx = Tx::parse(matches); + let source = SPENDING_KEY_SOURCE.parse(matches); + let target = PAYMENT_ADDRESS_TARGET.parse(matches); + let token = TOKEN.parse(matches); + let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); + let tx_code_path = PathBuf::from(TX_SHIELDED_TRANSFER_WASM); + Self { + tx, + source, + target, + token, + amount, + tx_code_path, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg( + SPENDING_KEY_SOURCE + .def() + .help(wrap!("The source shielded spending key.")), + ) + .arg( + PAYMENT_ADDRESS_TARGET + .def() + .help(wrap!("The shielded target account address.")), + ) + .arg(TOKEN.def().help(wrap!("The token address."))) + .arg( + AMOUNT + .def() + .help(wrap!("The amount to transfer in decimal.")), + ) + } + } + + impl CliToSdk> for TxShieldingTransfer { + type Error = std::io::Error; + + fn to_sdk( + self, + ctx: &mut Context, + ) -> Result, Self::Error> { + let tx = self.tx.to_sdk(ctx)?; + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + + Ok(TxShieldingTransfer:: { + tx, + source: chain_ctx.get(&self.source), + target: chain_ctx.get(&self.target), + token: chain_ctx.get(&self.token), + amount: self.amount, + tx_code_path: self.tx_code_path.to_path_buf(), + }) + } + } + + impl Args for TxShieldingTransfer { + fn parse(matches: &ArgMatches) -> Self { + let tx = Tx::parse(matches); + let source = SOURCE.parse(matches); + let target = PAYMENT_ADDRESS_TARGET.parse(matches); + let token = TOKEN.parse(matches); + let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); + let tx_code_path = PathBuf::from(TX_SHIELDING_TRANSFER_WASM); + Self { + tx, + source, + target, + token, + amount, + tx_code_path, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg(SOURCE.def().help(wrap!( + "The transparent source account address. The source's key \ + will be used to produce the signature." ))) - .arg(TOKEN.def().help(wrap!("The transfer token."))) + .arg( + PAYMENT_ADDRESS_TARGET + .def() + .help(wrap!("The target shielded account address.")), + ) + .arg(TOKEN.def().help(wrap!("The token address."))) + .arg( + AMOUNT + .def() + .help(wrap!("The amount to transfer in decimal.")), + ) + } + } + + impl CliToSdk> + for TxUnshieldingTransfer + { + type Error = std::io::Error; + + fn to_sdk( + self, + ctx: &mut Context, + ) -> Result, Self::Error> { + let tx = self.tx.to_sdk(ctx)?; + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + + Ok(TxUnshieldingTransfer:: { + tx, + source: chain_ctx.get_cached(&self.source), + target: chain_ctx.get(&self.target), + token: chain_ctx.get(&self.token), + amount: self.amount, + tx_code_path: self.tx_code_path.to_path_buf(), + }) + } + } + + impl Args for TxUnshieldingTransfer { + fn parse(matches: &ArgMatches) -> Self { + let tx = Tx::parse(matches); + let source = SPENDING_KEY_SOURCE.parse(matches); + let target = TARGET.parse(matches); + let token = TOKEN.parse(matches); + let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); + let tx_code_path = PathBuf::from(TX_UNSHIELDING_TRANSFER_WASM); + Self { + tx, + source, + target, + token, + amount, + tx_code_path, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg( + SPENDING_KEY_SOURCE + .def() + .help(wrap!("The source shielded spending key.")), + ) + .arg( + TARGET + .def() + .help(wrap!("The transparent target account address.")), + ) + .arg(TOKEN.def().help(wrap!("The token address."))) .arg( AMOUNT .def() @@ -6472,6 +6757,7 @@ pub mod args { type Data = PathBuf; type EthereumAddress = String; type Keypair = WalletKeypair; + type PaymentAddress = WalletPaymentAddr; type PublicKey = WalletPublicKey; type SpendingKey = WalletSpendingKey; type TendermintAddress = tendermint_rpc::Url; diff --git a/crates/apps_lib/src/cli/client.rs b/crates/apps_lib/src/cli/client.rs index cb9dc532ed..79103a9f3d 100644 --- a/crates/apps_lib/src/cli/client.rs +++ b/crates/apps_lib/src/cli/client.rs @@ -52,7 +52,7 @@ impl CliApi { ) } } - Sub::TxTransfer(TxTransfer(args)) => { + Sub::TxTransparentTransfer(TxTransparentTransfer(args)) => { let chain_ctx = ctx.borrow_mut_chain_or_exit(); let ledger_address = chain_ctx.get(&args.tx.ledger_address); @@ -62,7 +62,43 @@ impl CliApi { client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx)?; let namada = ctx.to_sdk(client, io); - tx::submit_transfer(&namada, args).await?; + tx::submit_transparent_transfer(&namada, args).await?; + } + Sub::TxShieldedTransfer(TxShieldedTransfer(args)) => { + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let ledger_address = + chain_ctx.get(&args.tx.ledger_address); + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&ledger_address) + }); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx)?; + let namada = ctx.to_sdk(client, io); + tx::submit_shielded_transfer(&namada, args).await?; + } + Sub::TxShieldingTransfer(TxShieldingTransfer(args)) => { + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let ledger_address = + chain_ctx.get(&args.tx.ledger_address); + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&ledger_address) + }); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx)?; + let namada = ctx.to_sdk(client, io); + tx::submit_shielding_transfer(&namada, args).await?; + } + Sub::TxUnshieldingTransfer(TxUnshieldingTransfer(args)) => { + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let ledger_address = + chain_ctx.get(&args.tx.ledger_address); + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&ledger_address) + }); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx)?; + let namada = ctx.to_sdk(client, io); + tx::submit_unshielding_transfer(&namada, args).await?; } Sub::TxIbcTransfer(TxIbcTransfer(args)) => { let chain_ctx = ctx.borrow_mut_chain_or_exit(); diff --git a/crates/apps_lib/src/cli/context.rs b/crates/apps_lib/src/cli/context.rs index 2fad9721c5..2045b890e2 100644 --- a/crates/apps_lib/src/cli/context.rs +++ b/crates/apps_lib/src/cli/context.rs @@ -9,9 +9,9 @@ use color_eyre::eyre::Result; use namada::core::address::{Address, InternalAddress}; use namada::core::chain::ChainId; use namada::core::ethereum_events::EthAddress; -use namada::core::ibc::{is_ibc_denom, is_nft_trace}; use namada::core::key::*; use namada::core::masp::*; +use namada::ibc::{is_ibc_denom, is_nft_trace}; use namada::io::Io; use namada::ledger::ibc::storage::ibc_token; use namada_sdk::masp::fs::FsShieldedUtils; diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index f7a2a182c6..44857b43e8 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -739,18 +739,30 @@ pub async fn submit_init_validator( .await } -pub async fn submit_transfer( +pub async fn submit_transparent_transfer( namada: &impl Namada, - args: args::TxTransfer, + args: args::TxTransparentTransfer, ) -> Result<(), error::Error> { - for _ in 0..2 { - submit_reveal_aux( - namada, - args.tx.clone(), - &args.source.effective_address(), - ) - .await?; + submit_reveal_aux(namada, args.tx.clone(), &args.source).await?; + + let (mut tx, signing_data) = args.clone().build(namada).await?; + + if args.tx.dump_tx { + tx::dump_tx(namada.io(), &args.tx, tx); + } else { + sign(namada, &mut tx, &args.tx, signing_data).await?; + namada.submit(tx, &args.tx).await?; + } + Ok(()) +} + +pub async fn submit_shielded_transfer( + namada: &impl Namada, + args: args::TxShieldedTransfer, +) -> Result<(), error::Error> { + // Repeat once if the tx fails on a crossover of an epoch + for _ in 0..2 { let (mut tx, signing_data, tx_epoch) = args.clone().build(namada).await?; @@ -760,22 +772,59 @@ pub async fn submit_transfer( } else { sign(namada, &mut tx, &args.tx, signing_data).await?; let cmt_hash = tx.first_commitments().unwrap().get_hash(); - let result = namada.submit(tx, &args.tx).await?; + match result { + ProcessTxResponse::Applied(resp) if + // If a transaction is rejected by a VP + matches!(resp.batch_result().get(&cmt_hash), Some(InnerTxResult::VpsRejected(_))) => + { + let submission_epoch = rpc::query_and_print_epoch(namada).await; + // And its submission epoch doesn't match construction epoch + if tx_epoch != submission_epoch { + // Then we probably straddled an epoch boundary. Let's retry... + edisplay_line!(namada.io(), + "Shielded transaction rejected and this may be due to the \ + epoch changing. Attempting to resubmit transaction.", + ); + continue; + } + }, + // Otherwise either the transaction was successful or it will not + // benefit from resubmission + _ => break, + } + } + } + Ok(()) +} + +pub async fn submit_shielding_transfer( + namada: &impl Namada, + args: args::TxShieldingTransfer, +) -> Result<(), error::Error> { + // Repeat once if the tx fails on a crossover of an epoch + for _ in 0..2 { + let (mut tx, signing_data, tx_epoch) = + args.clone().build(namada).await?; + if args.tx.dump_tx { + tx::dump_tx(namada.io(), &args.tx, tx); + break; + } else { + sign(namada, &mut tx, &args.tx, signing_data).await?; + let cmt_hash = tx.first_commitments().unwrap().get_hash(); + let result = namada.submit(tx, &args.tx).await?; match result { ProcessTxResponse::Applied(resp) if - // If a transaction is shielded - tx_epoch.is_some() && - // And it is rejected by a VP + // If a transaction is rejected by a VP matches!(resp.batch_result().get(&cmt_hash), Some(InnerTxResult::VpsRejected(_))) => { let submission_epoch = rpc::query_and_print_epoch(namada).await; // And its submission epoch doesn't match construction epoch - if tx_epoch.unwrap() != submission_epoch { + if tx_epoch != submission_epoch { // Then we probably straddled an epoch boundary. Let's retry... edisplay_line!(namada.io(), - "MASP transaction rejected and this may be due to the \ + "Shielding transaction rejected and this may be due to the \ epoch changing. Attempting to resubmit transaction.", ); continue; @@ -787,7 +836,47 @@ pub async fn submit_transfer( } } } + Ok(()) +} +pub async fn submit_unshielding_transfer( + namada: &impl Namada, + args: args::TxUnshieldingTransfer, +) -> Result<(), error::Error> { + // Repeat once if the tx fails on a crossover of an epoch + for _ in 0..2 { + let (mut tx, signing_data, tx_epoch) = + args.clone().build(namada).await?; + + if args.tx.dump_tx { + tx::dump_tx(namada.io(), &args.tx, tx); + break; + } else { + sign(namada, &mut tx, &args.tx, signing_data).await?; + let cmt_hash = tx.first_commitments().unwrap().get_hash(); + let result = namada.submit(tx, &args.tx).await?; + match result { + ProcessTxResponse::Applied(resp) if + // If a transaction is rejected by a VP + matches!(resp.batch_result().get(&cmt_hash), Some(InnerTxResult::VpsRejected(_))) => + { + let submission_epoch = rpc::query_and_print_epoch(namada).await; + // And its submission epoch doesn't match construction epoch + if tx_epoch != submission_epoch { + // Then we probably straddled an epoch boundary. Let's retry... + edisplay_line!(namada.io(), + "Unshielding transaction rejected and this may be due to the \ + epoch changing. Attempting to resubmit transaction.", + ); + continue; + } + }, + // Otherwise either the transaction was successful or it will not + // benefit from resubmission + _ => break, + } + } + } Ok(()) } diff --git a/crates/benches/host_env.rs b/crates/benches/host_env.rs index 8b13760964..1eee561163 100644 --- a/crates/benches/host_env.rs +++ b/crates/benches/host_env.rs @@ -3,29 +3,29 @@ use namada::core::account::AccountPublicKeysMap; use namada::core::address; use namada::core::collections::{HashMap, HashSet}; use namada::ledger::storage::DB; -use namada::token::{Amount, Transfer}; +use namada::token::{Amount, TransparentTransfer}; use namada::tx::Authorization; use namada::vm::wasm::TxCache; use namada_apps_lib::wallet::defaults; use namada_apps_lib::wasm_loader; use namada_node::bench_utils::{ - BenchShell, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, TX_TRANSFER_WASM, - TX_UPDATE_ACCOUNT_WASM, VP_USER_WASM, WASM_DIR, + BenchShell, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_UPDATE_ACCOUNT_WASM, VP_USER_WASM, + WASM_DIR, }; // Benchmarks the validation of a single signature on a single `Section` of a // transaction fn tx_section_signature_validation(c: &mut Criterion) { let shell = BenchShell::default(); - let transfer_data = Transfer { + let transfer_data = TransparentTransfer { source: defaults::albert_address(), target: defaults::bertha_address(), token: address::testing::nam(), amount: Amount::native_whole(500).native_denominated(), - shielded: None, }; let tx = shell.generate_tx( - TX_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, transfer_data, None, None, @@ -62,7 +62,7 @@ fn compile_wasm(c: &mut Criterion) { let mut txs: HashMap<&str, Vec> = HashMap::default(); for tx in [ - TX_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, TX_UPDATE_ACCOUNT_WASM, @@ -111,7 +111,7 @@ fn untrusted_wasm_validation(c: &mut Criterion) { let mut txs: HashMap<&str, Vec> = HashMap::default(); for tx in [ - TX_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, TX_UPDATE_ACCOUNT_WASM, diff --git a/crates/benches/native_vps.rs b/crates/benches/native_vps.rs index 5f2b4455e4..298c37fcf5 100644 --- a/crates/benches/native_vps.rs +++ b/crates/benches/native_vps.rs @@ -55,14 +55,15 @@ use namada::sdk::masp_primitives::merkle_tree::CommitmentTree; use namada::sdk::masp_primitives::transaction::Transaction; use namada::sdk::masp_proofs::sapling::SaplingVerificationContextInner; use namada::state::{Epoch, StorageRead, StorageWrite, TxIndex}; -use namada::token::{Amount, Transfer}; +use namada::token::{Amount, TransparentTransfer}; use namada::tx::{BatchedTx, Code, Section, Tx}; use namada_apps_lib::wallet::defaults; use namada_node::bench_utils::{ generate_foreign_key_tx, BenchShell, BenchShieldedCtx, ALBERT_PAYMENT_ADDRESS, ALBERT_SPENDING_KEY, BERTHA_PAYMENT_ADDRESS, TX_BRIDGE_POOL_WASM, TX_IBC_WASM, TX_INIT_PROPOSAL_WASM, TX_RESIGN_STEWARD, - TX_TRANSFER_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_UPDATE_STEWARD_COMMISSION, + TX_VOTE_PROPOSAL_WASM, }; use rand_core::OsRng; @@ -474,13 +475,12 @@ fn vp_multitoken(c: &mut Criterion) { generate_foreign_key_tx(&defaults::albert_keypair()); let transfer = shell.generate_tx( - TX_TRANSFER_WASM, - Transfer { + TX_TRANSPARENT_TRANSFER_WASM, + TransparentTransfer { source: defaults::albert_address(), target: defaults::bertha_address(), token: address::testing::nam(), amount: Amount::native_whole(1000).native_denominated(), - shielded: None, }, None, None, diff --git a/crates/benches/process_wrapper.rs b/crates/benches/process_wrapper.rs index 2d1c1241ba..9510ee3125 100644 --- a/crates/benches/process_wrapper.rs +++ b/crates/benches/process_wrapper.rs @@ -3,11 +3,11 @@ use namada::core::address; use namada::core::key::RefTo; use namada::core::storage::BlockHeight; use namada::core::time::DateTimeUtc; -use namada::token::{Amount, DenominatedAmount, Transfer}; +use namada::token::{Amount, DenominatedAmount, TransparentTransfer}; use namada::tx::data::{Fee, WrapperTx}; use namada::tx::Authorization; use namada_apps_lib::wallet::defaults; -use namada_node::bench_utils::{BenchShell, TX_TRANSFER_WASM}; +use namada_node::bench_utils::{BenchShell, TX_TRANSPARENT_TRANSFER_WASM}; use namada_node::shell::process_proposal::ValidationMeta; fn process_tx(c: &mut Criterion) { @@ -18,13 +18,12 @@ fn process_tx(c: &mut Criterion) { BlockHeight(2); let mut batched_tx = shell.generate_tx( - TX_TRANSFER_WASM, - Transfer { + TX_TRANSPARENT_TRANSFER_WASM, + TransparentTransfer { source: defaults::albert_address(), target: defaults::bertha_address(), token: address::testing::nam(), amount: Amount::native_whole(1).native_denominated(), - shielded: None, }, None, None, diff --git a/crates/core/src/address.rs b/crates/core/src/address.rs index bdda98c56e..409622d747 100644 --- a/crates/core/src/address.rs +++ b/crates/core/src/address.rs @@ -9,6 +9,7 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use data_encoding::HEXUPPER; +use ibc::primitives::Signer; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; @@ -16,7 +17,6 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use crate::ethereum_events::EthAddress; -use crate::ibc::primitives::Signer; use crate::ibc::IbcTokenHash; use crate::key::PublicKeyHash; use crate::{impl_display_and_from_str_via_format, key, string_encoding}; diff --git a/crates/core/src/ibc.rs b/crates/core/src/ibc.rs index 115ef5b017..fe29f61fe7 100644 --- a/crates/core/src/ibc.rs +++ b/crates/core/src/ibc.rs @@ -9,32 +9,8 @@ use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; use serde::{Deserialize, Serialize}; -use thiserror::Error; -use super::address::{Address, InternalAddress, HASH_LEN}; -use crate::ibc::apps::nft_transfer::context::{NftClassContext, NftContext}; -use crate::ibc::apps::nft_transfer::types::error::NftTransferError; -use crate::ibc::apps::nft_transfer::types::msgs::transfer::MsgTransfer as IbcMsgNftTransfer; -use crate::ibc::apps::nft_transfer::types::{ - ClassData, ClassId, ClassUri, PrefixedClassId, TokenData, TokenId, - TokenUri, TracePath as NftTracePath, -}; -use crate::ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; -use crate::ibc::apps::transfer::types::{PrefixedDenom, TracePath}; -use crate::ibc::core::channel::types::msgs::{ - MsgAcknowledgement as IbcMsgAcknowledgement, - MsgRecvPacket as IbcMsgRecvPacket, MsgTimeout as IbcMsgTimeout, -}; -use crate::ibc::core::handler::types::msgs::MsgEnvelope; -use crate::ibc::primitives::proto::Protobuf; -use crate::token::Transfer; - -/// The event type defined in ibc-rs for receiving a token -pub const EVENT_TYPE_PACKET: &str = "fungible_token_packet"; -/// The event type defined in ibc-rs for receiving an NFT -pub const EVENT_TYPE_NFT_PACKET: &str = "non_fungible_token_packet"; -/// The escrow address for IBC transfer -pub const IBC_ESCROW_ADDRESS: Address = Address::Internal(InternalAddress::Ibc); +use super::address::HASH_LEN; /// IBC token hash derived from a denomination. #[derive( @@ -71,422 +47,3 @@ impl FromStr for IbcTokenHash { Ok(IbcTokenHash(output)) } } - -/// The different variants of an Ibc message -pub enum IbcMessage { - /// Ibc Envelop - Envelope(Box), - /// Ibc transaprent transfer - Transfer(MsgTransfer), - /// NFT transfer - NftTransfer(MsgNftTransfer), - /// Receiving a packet - RecvPacket(MsgRecvPacket), - /// Acknowledgement - AckPacket(MsgAcknowledgement), - /// Timeout - Timeout(MsgTimeout), -} - -/// IBC transfer message with `Transfer` -#[derive(Debug, Clone)] -pub struct MsgTransfer { - /// IBC transfer message - pub message: IbcMsgTransfer, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgTransfer { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgTransfer { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgTransfer::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -/// IBC NFT transfer message with `Transfer` -#[derive(Debug, Clone)] -pub struct MsgNftTransfer { - /// IBC NFT transfer message - pub message: IbcMsgNftTransfer, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgNftTransfer { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgNftTransfer { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgNftTransfer::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -/// IBC shielded transfer -#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, BorshDeserializer)] -pub struct IbcShieldedTransfer { - /// The IBC event type - pub transfer: Transfer, - /// The attributes of the IBC event - pub masp_tx: masp_primitives::transaction::Transaction, -} - -/// IBC receiving packet message with `Transfer` -#[derive(Debug, Clone)] -pub struct MsgRecvPacket { - /// IBC receiving packet message - pub message: IbcMsgRecvPacket, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgRecvPacket { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgRecvPacket { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgRecvPacket::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -/// IBC acknowledgement message with `Transfer` for refunding to a shielded -/// address -#[derive(Debug, Clone)] -pub struct MsgAcknowledgement { - /// IBC acknowledgement message - pub message: IbcMsgAcknowledgement, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgAcknowledgement { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgAcknowledgement { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgAcknowledgement::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -/// IBC timeout packet message with `Transfer` for refunding to a shielded -/// address -#[derive(Debug, Clone)] -pub struct MsgTimeout { - /// IBC timeout message - pub message: IbcMsgTimeout, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgTimeout { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgTimeout { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgTimeout::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -#[allow(missing_docs)] -#[derive(Error, Debug)] -pub enum Error { - #[error("IBC transfer memo HEX decoding error: {0}")] - DecodingHex(data_encoding::DecodeError), - #[error("IBC transfer memo decoding error: {0}")] - DecodingShieldedTransfer(std::io::Error), -} - -/// Returns the trace path and the token string if the denom is an IBC -/// denom. -pub fn is_ibc_denom(denom: impl AsRef) -> Option<(TracePath, String)> { - let prefixed_denom = PrefixedDenom::from_str(denom.as_ref()).ok()?; - let base_denom = prefixed_denom.base_denom.to_string(); - if prefixed_denom.trace_path.is_empty() || base_denom.contains('/') { - // The denom is just a token or an NFT trace - return None; - } - // The base token isn't decoded because it could be non Namada token - Some((prefixed_denom.trace_path, base_denom)) -} - -/// Returns the trace path and the token string if the trace is an NFT one -pub fn is_nft_trace( - trace: impl AsRef, -) -> Option<(NftTracePath, String, String)> { - // The trace should be {port}/{channel}/.../{class_id}/{token_id} - if let Some((class_id, token_id)) = trace.as_ref().rsplit_once('/') { - let prefixed_class_id = PrefixedClassId::from_str(class_id).ok()?; - // The base token isn't decoded because it could be non Namada token - Some(( - prefixed_class_id.trace_path, - prefixed_class_id.base_class_id.to_string(), - token_id.to_string(), - )) - } else { - None - } -} - -/// NFT class -#[derive(Clone, Debug)] -pub struct NftClass { - /// NFT class ID - pub class_id: PrefixedClassId, - /// NFT class URI - pub class_uri: Option, - /// NFT class data - pub class_data: Option, -} - -impl BorshSerialize for NftClass { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - BorshSerialize::serialize(&self.class_id.to_string(), writer)?; - match &self.class_uri { - Some(uri) => { - BorshSerialize::serialize(&true, writer)?; - BorshSerialize::serialize(&uri.to_string(), writer)?; - } - None => BorshSerialize::serialize(&false, writer)?, - } - match &self.class_data { - Some(data) => { - BorshSerialize::serialize(&true, writer)?; - BorshSerialize::serialize(&data.to_string(), writer) - } - None => BorshSerialize::serialize(&false, writer), - } - } -} - -impl BorshDeserialize for NftClass { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let class_id: String = BorshDeserialize::deserialize_reader(reader)?; - let class_id = class_id.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?; - - let is_uri: bool = BorshDeserialize::deserialize_reader(reader)?; - let class_uri = if is_uri { - let uri_str: String = BorshDeserialize::deserialize_reader(reader)?; - Some(uri_str.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?) - } else { - None - }; - - let is_data: bool = BorshDeserialize::deserialize_reader(reader)?; - let class_data = if is_data { - let data_str: String = - BorshDeserialize::deserialize_reader(reader)?; - Some(data_str.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?) - } else { - None - }; - - Ok(Self { - class_id, - class_uri, - class_data, - }) - } -} - -impl NftClassContext for NftClass { - fn get_id(&self) -> &ClassId { - &self.class_id.base_class_id - } - - fn get_uri(&self) -> Option<&ClassUri> { - self.class_uri.as_ref() - } - - fn get_data(&self) -> Option<&ClassData> { - self.class_data.as_ref() - } -} - -/// NFT metadata -#[derive(Clone, Debug)] -pub struct NftMetadata { - /// NFT class ID - pub class_id: PrefixedClassId, - /// NFT ID - pub token_id: TokenId, - /// NFT URI - pub token_uri: Option, - /// NFT data - pub token_data: Option, -} - -impl BorshSerialize for NftMetadata { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - BorshSerialize::serialize(&self.class_id.to_string(), writer)?; - BorshSerialize::serialize(&self.token_id.to_string(), writer)?; - match &self.token_uri { - Some(uri) => { - BorshSerialize::serialize(&true, writer)?; - BorshSerialize::serialize(&uri.to_string(), writer)?; - } - None => BorshSerialize::serialize(&false, writer)?, - } - match &self.token_data { - Some(data) => { - BorshSerialize::serialize(&true, writer)?; - BorshSerialize::serialize(&data.to_string(), writer) - } - None => BorshSerialize::serialize(&false, writer), - } - } -} - -impl BorshDeserialize for NftMetadata { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let class_id: String = BorshDeserialize::deserialize_reader(reader)?; - let class_id = class_id.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?; - - let token_id: String = BorshDeserialize::deserialize_reader(reader)?; - let token_id = token_id.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?; - - let is_uri: bool = BorshDeserialize::deserialize_reader(reader)?; - let token_uri = if is_uri { - let uri_str: String = BorshDeserialize::deserialize_reader(reader)?; - Some(uri_str.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?) - } else { - None - }; - - let is_data: bool = BorshDeserialize::deserialize_reader(reader)?; - let token_data = if is_data { - let data_str: String = - BorshDeserialize::deserialize_reader(reader)?; - Some(data_str.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?) - } else { - None - }; - - Ok(Self { - class_id, - token_id, - token_uri, - token_data, - }) - } -} - -impl NftContext for NftMetadata { - fn get_class_id(&self) -> &ClassId { - &self.class_id.base_class_id - } - - fn get_id(&self) -> &TokenId { - &self.token_id - } - - fn get_uri(&self) -> Option<&TokenUri> { - self.token_uri.as_ref() - } - - fn get_data(&self) -> Option<&TokenData> { - self.token_data.as_ref() - } -} diff --git a/crates/core/src/token.rs b/crates/core/src/token.rs index 616ec87221..69588b9518 100644 --- a/crates/core/src/token.rs +++ b/crates/core/src/token.rs @@ -7,17 +7,15 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use data_encoding::BASE32HEX_NOPAD; use ethabi::ethereum_types::U256; +use ibc::apps::transfer::types::Amount as IbcAmount; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::address::Address; use crate::arith::{self, checked, CheckedAdd, CheckedSub}; use crate::dec::{Dec, POS_DECIMAL_PRECISION}; -use crate::hash::Hash; -use crate::ibc::apps::transfer::types::Amount as IbcAmount; use crate::storage; use crate::storage::{DbKeySeg, KeySeg}; use crate::uint::{self, Uint, I256}; @@ -950,34 +948,6 @@ impl From for IbcAmount { } } -/// A simple bilateral token transfer -#[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - BorshDeserializer, - BorshSchema, - Hash, - Eq, - PartialOrd, - Serialize, - Deserialize, -)] -pub struct Transfer { - /// Source address will spend the tokens - pub source: Address, - /// Target address will receive the tokens - pub target: Address, - /// Token's address - pub token: Address, - /// The amount of tokens - pub amount: DenominatedAmount, - /// Shielded transaction part - pub shielded: Option, -} - #[allow(missing_docs)] #[derive(Error, Debug)] pub enum AmountError { @@ -994,9 +964,6 @@ pub mod testing { use proptest::prelude::*; use super::*; - use crate::address::testing::{ - arb_established_address, arb_non_internal_address, - }; impl std::ops::Add for Amount { type Output = Self; @@ -1078,24 +1045,6 @@ pub mod testing { } } - prop_compose! { - /// Generate a transfer - pub fn arb_transfer()( - source in arb_non_internal_address(), - target in arb_non_internal_address(), - token in arb_established_address().prop_map(Address::Established), - amount in arb_denominated_amount(), - ) -> Transfer { - Transfer { - source, - target, - token, - amount, - shielded: None, - } - } - } - /// Generate an arbitrary token amount pub fn arb_amount() -> impl Strategy { any::().prop_map(|val| Amount::from_uint(val, 0).unwrap()) diff --git a/crates/encoding_spec/src/main.rs b/crates/encoding_spec/src/main.rs index ea5858ae3f..efb5c0c79c 100644 --- a/crates/encoding_spec/src/main.rs +++ b/crates/encoding_spec/src/main.rs @@ -23,14 +23,13 @@ use borsh::{schema, schema_container_of}; use itertools::Itertools; use lazy_static::lazy_static; use madato::types::TableRow; -use namada::account; use namada::core::address::Address; use namada::core::collections::HashSet; use namada::core::key::ed25519::{PublicKey, Signature}; use namada::core::storage::{self, Epoch}; -use namada::core::token; use namada::ledger::parameters::Parameters; use namada::tx::data::{pos, TxType, WrapperTx}; +use namada::{account, token}; /// This generator will write output into this `docs` file. const OUTPUT_PATH: &str = @@ -82,7 +81,14 @@ fn main() -> Result<(), Box> { let signature_schema = schema_container_of::(); let init_account_schema = schema_container_of::(); let init_validator_schema = schema_container_of::(); - let token_transfer_schema = schema_container_of::(); + let transparent_transfer_schema = + schema_container_of::(); + let shielded_transfer_schema = + schema_container_of::(); + let shielding_transfer_schema = + schema_container_of::(); + let unshielding_transfer_schema = + schema_container_of::(); let update_account = schema_container_of::(); let pos_bond_schema = schema_container_of::(); let pos_withdraw_schema = schema_container_of::(); @@ -109,7 +115,10 @@ fn main() -> Result<(), Box> { definitions.extend(btree(&signature_schema)); definitions.extend(btree(&init_account_schema)); definitions.extend(btree(&init_validator_schema)); - definitions.extend(btree(&token_transfer_schema)); + definitions.extend(btree(&transparent_transfer_schema)); + definitions.extend(btree(&shielded_transfer_schema)); + definitions.extend(btree(&shielding_transfer_schema)); + definitions.extend(btree(&unshielding_transfer_schema)); definitions.extend(btree(&update_account)); definitions.extend(btree(&pos_bond_schema)); definitions.extend(btree(&pos_withdraw_schema)); @@ -183,10 +192,10 @@ fn main() -> Result<(), Box> { tables.push(init_validator_table); let token_transfer_definition = definitions - .remove(token_transfer_schema.declaration()) + .remove(transparent_transfer_schema.declaration()) .unwrap(); let token_transfer_table = definition_to_table( - token_transfer_schema.declaration(), + transparent_transfer_schema.declaration(), token_transfer_definition, ).with_rust_doc_link("https://dev.namada.net/master/rustdoc/namada/types/token/struct.Transfer.html"); tables.push(token_transfer_table); diff --git a/crates/ibc/src/actions.rs b/crates/ibc/src/actions.rs index 4676721c49..63696343a0 100644 --- a/crates/ibc/src/actions.rs +++ b/crates/ibc/src/actions.rs @@ -4,13 +4,12 @@ use std::cell::RefCell; use std::collections::BTreeSet; use std::rc::Rc; +use ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; +use ibc::apps::transfer::types::packet::PacketData; +use ibc::apps::transfer::types::PrefixedCoin; +use ibc::core::channel::types::timeout::TimeoutHeight; use namada_core::address::Address; use namada_core::borsh::BorshSerializeExt; -use namada_core::ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; -use namada_core::ibc::apps::transfer::types::packet::PacketData; -use namada_core::ibc::apps::transfer::types::PrefixedCoin; -use namada_core::ibc::core::channel::types::timeout::TimeoutHeight; -use namada_core::ibc::MsgTransfer; use namada_core::tendermint::Time as TmTime; use namada_core::token::Amount; use namada_events::EmitEvents; @@ -26,6 +25,7 @@ use token::DenominatedAmount; use crate::event::IbcEvent; use crate::{ storage as ibc_storage, IbcActions, IbcCommonContext, IbcStorageContext, + MsgTransfer, }; /// IBC protocol context diff --git a/crates/ibc/src/context/client.rs b/crates/ibc/src/context/client.rs index 702a1b5e4b..ab34d71832 100644 --- a/crates/ibc/src/context/client.rs +++ b/crates/ibc/src/context/client.rs @@ -1,17 +1,17 @@ //! AnyClientState and AnyConsensusState for IBC context +use ibc::clients::tendermint::client_state::ClientState as TmClientState; +use ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; +use ibc::clients::tendermint::types::{ + ClientState as TmClientStateType, ConsensusState as TmConsensusStateType, +}; +use ibc::core::client::types::error::ClientError; +use ibc::primitives::proto::Any; use ibc_derive::{IbcClientState, IbcConsensusState}; #[cfg(feature = "testing")] use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; #[cfg(feature = "testing")] use ibc_testkit::testapp::ibc::clients::mock::consensus_state::MockConsensusState; -use namada_core::ibc::clients::tendermint::client_state::ClientState as TmClientState; -use namada_core::ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; -use namada_core::ibc::clients::tendermint::types::{ - ClientState as TmClientStateType, ConsensusState as TmConsensusStateType, -}; -use namada_core::ibc::core::client::types::error::ClientError; -use namada_core::ibc::primitives::proto::Any; use prost::Message; use super::common::IbcCommonContext; diff --git a/crates/ibc/src/context/common.rs b/crates/ibc/src/context/common.rs index e536bb75ee..bc0e1d92b7 100644 --- a/crates/ibc/src/context/common.rs +++ b/crates/ibc/src/context/common.rs @@ -2,30 +2,27 @@ use core::time::Duration; -use namada_core::address::Address; -use namada_core::ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId}; -use namada_core::ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; -use namada_core::ibc::clients::tendermint::types::ConsensusState as TmConsensusStateType; -use namada_core::ibc::core::channel::types::channel::ChannelEnd; -use namada_core::ibc::core::channel::types::commitment::{ +use ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId}; +use ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; +use ibc::clients::tendermint::types::ConsensusState as TmConsensusStateType; +use ibc::core::channel::types::channel::ChannelEnd; +use ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use namada_core::ibc::core::channel::types::error::{ - ChannelError, PacketError, -}; -use namada_core::ibc::core::channel::types::packet::Receipt; -use namada_core::ibc::core::channel::types::timeout::TimeoutHeight; -use namada_core::ibc::core::client::types::error::ClientError; -use namada_core::ibc::core::client::types::Height; -use namada_core::ibc::core::connection::types::error::ConnectionError; -use namada_core::ibc::core::connection::types::ConnectionEnd; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::host::types::identifiers::{ +use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::packet::Receipt; +use ibc::core::channel::types::timeout::TimeoutHeight; +use ibc::core::client::types::error::ClientError; +use ibc::core::client::types::Height; +use ibc::core::connection::types::error::ConnectionError; +use ibc::core::connection::types::ConnectionEnd; +use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::identifiers::{ ChannelId, ClientId, ConnectionId, PortId, Sequence, }; -use namada_core::ibc::primitives::proto::{Any, Protobuf}; -use namada_core::ibc::primitives::Timestamp; -use namada_core::ibc::{NftClass, NftMetadata}; +use ibc::primitives::proto::{Any, Protobuf}; +use ibc::primitives::Timestamp; +use namada_core::address::Address; use namada_core::storage::{BlockHeight, Key}; use namada_core::tendermint::Time as TmTime; use namada_core::time::DurationSecs; @@ -37,7 +34,7 @@ use sha2::Digest; use super::client::{AnyClientState, AnyConsensusState}; use super::storage::IbcStorageContext; -use crate::storage; +use crate::{storage, NftClass, NftMetadata}; /// Result of IBC common function call pub type Result = std::result::Result; diff --git a/crates/ibc/src/context/execution.rs b/crates/ibc/src/context/execution.rs index 955228edfe..c081d519f7 100644 --- a/crates/ibc/src/context/execution.rs +++ b/crates/ibc/src/context/execution.rs @@ -1,25 +1,23 @@ //! ExecutionContext implementation for IBC -use namada_core::ibc::core::channel::types::channel::ChannelEnd; -use namada_core::ibc::core::channel::types::commitment::{ +use ibc::core::channel::types::channel::ChannelEnd; +use ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use namada_core::ibc::core::channel::types::packet::Receipt; -use namada_core::ibc::core::client::context::ClientExecutionContext; -use namada_core::ibc::core::client::types::Height; -use namada_core::ibc::core::connection::types::ConnectionEnd; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::handler::types::events::IbcEvent; -use namada_core::ibc::core::host::types::identifiers::{ - ClientId, ConnectionId, Sequence, -}; -use namada_core::ibc::core::host::types::path::{ +use ibc::core::channel::types::packet::Receipt; +use ibc::core::client::context::ClientExecutionContext; +use ibc::core::client::types::Height; +use ibc::core::connection::types::ConnectionEnd; +use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::events::IbcEvent; +use ibc::core::host::types::identifiers::{ClientId, ConnectionId, Sequence}; +use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use namada_core::ibc::core::host::ExecutionContext; -use namada_core::ibc::primitives::Timestamp; +use ibc::core::host::ExecutionContext; +use ibc::primitives::Timestamp; use super::client::AnyClientState; use super::common::IbcCommonContext; diff --git a/crates/ibc/src/context/mod.rs b/crates/ibc/src/context/mod.rs index be3190813e..7bba1137b9 100644 --- a/crates/ibc/src/context/mod.rs +++ b/crates/ibc/src/context/mod.rs @@ -16,9 +16,9 @@ use std::fmt::Debug; use std::rc::Rc; use std::time::Duration; +use ibc::core::commitment_types::specs::ProofSpecs; +use ibc::core::host::types::identifiers::ChainId as IbcChainId; use namada_core::hash::Sha256Hasher; -use namada_core::ibc::core::commitment_types::specs::ProofSpecs; -use namada_core::ibc::core::host::types::identifiers::ChainId as IbcChainId; use namada_state::merkle_tree::ics23_specs::proof_specs; /// IBC context to handle IBC-related data diff --git a/crates/ibc/src/context/nft_transfer.rs b/crates/ibc/src/context/nft_transfer.rs index 2ac019bf6f..85d9aad44e 100644 --- a/crates/ibc/src/context/nft_transfer.rs +++ b/crates/ibc/src/context/nft_transfer.rs @@ -3,22 +3,21 @@ use std::cell::RefCell; use std::rc::Rc; -use namada_core::address::Address; -use namada_core::ibc::apps::nft_transfer::context::{ +use ibc::apps::nft_transfer::context::{ NftTransferExecutionContext, NftTransferValidationContext, }; -use namada_core::ibc::apps::nft_transfer::types::error::NftTransferError; -use namada_core::ibc::apps::nft_transfer::types::{ +use ibc::apps::nft_transfer::types::error::NftTransferError; +use ibc::apps::nft_transfer::types::{ ClassData, ClassUri, Memo, PrefixedClassId, TokenData, TokenId, TokenUri, PORT_ID_STR, }; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; -use namada_core::ibc::{NftClass, NftMetadata, IBC_ESCROW_ADDRESS}; +use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::identifiers::{ChannelId, PortId}; +use namada_core::address::Address; use namada_core::token::Amount; use super::common::IbcCommonContext; -use crate::storage; +use crate::{storage, NftClass, NftMetadata, IBC_ESCROW_ADDRESS}; /// NFT transfer context to handle tokens #[derive(Debug)] diff --git a/crates/ibc/src/context/nft_transfer_mod.rs b/crates/ibc/src/context/nft_transfer_mod.rs index e8af60b523..1d94056425 100644 --- a/crates/ibc/src/context/nft_transfer_mod.rs +++ b/crates/ibc/src/context/nft_transfer_mod.rs @@ -4,8 +4,8 @@ use std::cell::RefCell; use std::fmt::Debug; use std::rc::Rc; -use namada_core::ibc::apps::nft_transfer::context::NftTransferValidationContext; -use namada_core::ibc::apps::nft_transfer::module::{ +use ibc::apps::nft_transfer::context::NftTransferValidationContext; +use ibc::apps::nft_transfer::module::{ on_acknowledgement_packet_execute, on_acknowledgement_packet_validate, on_chan_close_confirm_execute, on_chan_close_confirm_validate, on_chan_close_init_execute, on_chan_close_init_validate, @@ -16,21 +16,17 @@ use namada_core::ibc::apps::nft_transfer::module::{ on_recv_packet_execute, on_timeout_packet_execute, on_timeout_packet_validate, }; -use namada_core::ibc::apps::nft_transfer::types::error::NftTransferError; -use namada_core::ibc::apps::nft_transfer::types::MODULE_ID_STR; -use namada_core::ibc::core::channel::types::acknowledgement::Acknowledgement; -use namada_core::ibc::core::channel::types::channel::{Counterparty, Order}; -use namada_core::ibc::core::channel::types::error::{ - ChannelError, PacketError, -}; -use namada_core::ibc::core::channel::types::packet::Packet; -use namada_core::ibc::core::channel::types::Version; -use namada_core::ibc::core::host::types::identifiers::{ - ChannelId, ConnectionId, PortId, -}; -use namada_core::ibc::core::router::module::Module; -use namada_core::ibc::core::router::types::module::{ModuleExtras, ModuleId}; -use namada_core::ibc::primitives::Signer; +use ibc::apps::nft_transfer::types::error::NftTransferError; +use ibc::apps::nft_transfer::types::MODULE_ID_STR; +use ibc::core::channel::types::acknowledgement::Acknowledgement; +use ibc::core::channel::types::channel::{Counterparty, Order}; +use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::packet::Packet; +use ibc::core::channel::types::Version; +use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc::core::router::module::Module; +use ibc::core::router::types::module::{ModuleExtras, ModuleId}; +use ibc::primitives::Signer; use super::common::IbcCommonContext; use super::nft_transfer::NftTransferContext; @@ -332,10 +328,8 @@ fn into_packet_error(error: NftTransferError) -> PacketError { pub mod testing { use std::str::FromStr; - use namada_core::ibc::apps::nft_transfer::types::{ - ack_success_b64, PORT_ID_STR, - }; - use namada_core::ibc::core::channel::types::acknowledgement::AcknowledgementStatus; + use ibc::apps::nft_transfer::types::{ack_success_b64, PORT_ID_STR}; + use ibc::core::channel::types::acknowledgement::AcknowledgementStatus; use super::*; diff --git a/crates/ibc/src/context/router.rs b/crates/ibc/src/context/router.rs index 0833a6282a..61fc6e24d9 100644 --- a/crates/ibc/src/context/router.rs +++ b/crates/ibc/src/context/router.rs @@ -2,11 +2,11 @@ use std::rc::Rc; +use ibc::core::host::types::identifiers::PortId; +use ibc::core::router::module::Module; +use ibc::core::router::router::Router; +use ibc::core::router::types::module::ModuleId; use namada_core::collections::HashMap; -use namada_core::ibc::core::host::types::identifiers::PortId; -use namada_core::ibc::core::router::module::Module; -use namada_core::ibc::core::router::router::Router; -use namada_core::ibc::core::router::types::module::ModuleId; use super::super::ModuleWrapper; diff --git a/crates/ibc/src/context/token_transfer.rs b/crates/ibc/src/context/token_transfer.rs index 1fc9700f93..4d9b5e7b80 100644 --- a/crates/ibc/src/context/token_transfer.rs +++ b/crates/ibc/src/context/token_transfer.rs @@ -4,23 +4,20 @@ use std::cell::RefCell; use std::collections::BTreeSet; use std::rc::Rc; -use namada_core::address::{Address, InternalAddress}; -use namada_core::ibc::apps::transfer::context::{ +use ibc::apps::transfer::context::{ TokenTransferExecutionContext, TokenTransferValidationContext, }; -use namada_core::ibc::apps::transfer::types::error::TokenTransferError; -use namada_core::ibc::apps::transfer::types::{ - Memo, PrefixedCoin, PrefixedDenom, -}; -use namada_core::ibc::core::channel::types::error::ChannelError; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; -use namada_core::ibc::IBC_ESCROW_ADDRESS; +use ibc::apps::transfer::types::error::TokenTransferError; +use ibc::apps::transfer::types::{Memo, PrefixedCoin, PrefixedDenom}; +use ibc::core::channel::types::error::ChannelError; +use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::identifiers::{ChannelId, PortId}; +use namada_core::address::{Address, InternalAddress}; use namada_core::uint::Uint; use namada_token::{read_denom, Amount, Denomination}; use super::common::IbcCommonContext; -use crate::storage; +use crate::{storage, IBC_ESCROW_ADDRESS}; /// Token transfer context to handle tokens #[derive(Debug)] diff --git a/crates/ibc/src/context/transfer_mod.rs b/crates/ibc/src/context/transfer_mod.rs index 4b88220213..9a1075e280 100644 --- a/crates/ibc/src/context/transfer_mod.rs +++ b/crates/ibc/src/context/transfer_mod.rs @@ -5,9 +5,8 @@ use std::collections::BTreeSet; use std::fmt::Debug; use std::rc::Rc; -use namada_core::address::Address; -use namada_core::ibc::apps::transfer::context::TokenTransferValidationContext; -use namada_core::ibc::apps::transfer::module::{ +use ibc::apps::transfer::context::TokenTransferValidationContext; +use ibc::apps::transfer::module::{ on_acknowledgement_packet_execute, on_acknowledgement_packet_validate, on_chan_close_confirm_execute, on_chan_close_confirm_validate, on_chan_close_init_execute, on_chan_close_init_validate, @@ -18,21 +17,18 @@ use namada_core::ibc::apps::transfer::module::{ on_recv_packet_execute, on_timeout_packet_execute, on_timeout_packet_validate, }; -use namada_core::ibc::apps::transfer::types::error::TokenTransferError; -use namada_core::ibc::apps::transfer::types::MODULE_ID_STR; -use namada_core::ibc::core::channel::types::acknowledgement::Acknowledgement; -use namada_core::ibc::core::channel::types::channel::{Counterparty, Order}; -use namada_core::ibc::core::channel::types::error::{ - ChannelError, PacketError, -}; -use namada_core::ibc::core::channel::types::packet::Packet; -use namada_core::ibc::core::channel::types::Version; -use namada_core::ibc::core::host::types::identifiers::{ - ChannelId, ConnectionId, PortId, -}; -use namada_core::ibc::core::router::module::Module; -use namada_core::ibc::core::router::types::module::{ModuleExtras, ModuleId}; -use namada_core::ibc::primitives::Signer; +use ibc::apps::transfer::types::error::TokenTransferError; +use ibc::apps::transfer::types::MODULE_ID_STR; +use ibc::core::channel::types::acknowledgement::Acknowledgement; +use ibc::core::channel::types::channel::{Counterparty, Order}; +use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::packet::Packet; +use ibc::core::channel::types::Version; +use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc::core::router::module::Module; +use ibc::core::router::types::module::{ModuleExtras, ModuleId}; +use ibc::primitives::Signer; +use namada_core::address::Address; use super::common::IbcCommonContext; use super::token_transfer::TokenTransferContext; @@ -351,10 +347,8 @@ fn into_packet_error(error: TokenTransferError) -> PacketError { pub mod testing { use std::str::FromStr; - use namada_core::ibc::apps::transfer::types::{ - ack_success_b64, PORT_ID_STR, - }; - use namada_core::ibc::core::channel::types::acknowledgement::AcknowledgementStatus; + use ibc::apps::transfer::types::{ack_success_b64, PORT_ID_STR}; + use ibc::core::channel::types::acknowledgement::AcknowledgementStatus; use super::*; diff --git a/crates/ibc/src/context/validation.rs b/crates/ibc/src/context/validation.rs index e063ccc772..5cb60fcd12 100644 --- a/crates/ibc/src/context/validation.rs +++ b/crates/ibc/src/context/validation.rs @@ -1,31 +1,31 @@ //! ValidationContext implementation for IBC -#[cfg(feature = "testing")] -use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; -use namada_core::ibc::clients::tendermint::client_state::ClientState as TmClientState; -use namada_core::ibc::core::channel::types::channel::ChannelEnd; -use namada_core::ibc::core::channel::types::commitment::{ +use ibc::clients::tendermint::client_state::ClientState as TmClientState; +use ibc::core::channel::types::channel::ChannelEnd; +use ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use namada_core::ibc::core::channel::types::packet::Receipt; -use namada_core::ibc::core::client::context::{ +use ibc::core::channel::types::packet::Receipt; +use ibc::core::client::context::{ ClientValidationContext, ExtClientValidationContext, }; -use namada_core::ibc::core::client::types::Height; -use namada_core::ibc::core::commitment_types::commitment::CommitmentPrefix; -use namada_core::ibc::core::commitment_types::specs::ProofSpecs; -use namada_core::ibc::core::connection::types::ConnectionEnd; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::host::types::identifiers::{ +use ibc::core::client::types::Height; +use ibc::core::commitment_types::commitment::CommitmentPrefix; +use ibc::core::commitment_types::specs::ProofSpecs; +use ibc::core::connection::types::ConnectionEnd; +use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::identifiers::{ ChainId, ClientId, ConnectionId, Sequence, }; -use namada_core::ibc::core::host::types::path::{ +use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use namada_core::ibc::core::host::ValidationContext; -use namada_core::ibc::cosmos_host::ValidateSelfClientContext; -use namada_core::ibc::primitives::{Signer, Timestamp}; +use ibc::core::host::ValidationContext; +use ibc::cosmos_host::ValidateSelfClientContext; +use ibc::primitives::{Signer, Timestamp}; +#[cfg(feature = "testing")] +use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; use super::client::{AnyClientState, AnyConsensusState}; use super::common::IbcCommonContext; diff --git a/crates/ibc/src/event.rs b/crates/ibc/src/event.rs index 5e19292686..5d340aee25 100644 --- a/crates/ibc/src/event.rs +++ b/crates/ibc/src/event.rs @@ -3,20 +3,20 @@ use std::cmp::Ordering; use std::str::FromStr; -use namada_core::borsh::*; -use namada_core::collections::HashMap; -use namada_core::ibc::core::channel::types::packet::Packet; -use namada_core::ibc::core::channel::types::timeout::TimeoutHeight as IbcTimeoutHeight; -use namada_core::ibc::core::client::types::events::{ +use ibc::core::channel::types::packet::Packet; +use ibc::core::channel::types::timeout::TimeoutHeight as IbcTimeoutHeight; +use ibc::core::client::types::events::{ CLIENT_ID_ATTRIBUTE_KEY, CONSENSUS_HEIGHTS_ATTRIBUTE_KEY, }; -use namada_core::ibc::core::client::types::{Height as IbcHeight, HeightError}; -use namada_core::ibc::core::handler::types::events::IbcEvent as RawIbcEvent; -use namada_core::ibc::core::host::types::identifiers::{ +use ibc::core::client::types::{Height as IbcHeight, HeightError}; +use ibc::core::handler::types::events::IbcEvent as RawIbcEvent; +use ibc::core::host::types::identifiers::{ ChannelId as IbcChannelId, ClientId as IbcClientId, ConnectionId as IbcConnectionId, PortId, Sequence, }; -use namada_core::ibc::primitives::Timestamp; +use ibc::primitives::Timestamp; +use namada_core::borsh::*; +use namada_core::collections::HashMap; use namada_core::tendermint::abci::Event as AbciEvent; use namada_events::extend::{ event_domain_of, AttributesMap, EventAttributeEntry, @@ -36,7 +36,7 @@ pub const TOKEN_EVENT_DESCRIPTOR: &str = IbcEvent::DOMAIN; pub mod types { //! IBC event types. - use namada_core::ibc::core::client::types::events::UPDATE_CLIENT_EVENT; + use ibc::core::client::types::events::UPDATE_CLIENT_EVENT; use namada_events::{event_type, EventType}; use super::IbcEvent; @@ -331,7 +331,7 @@ impl FromStr for TimeoutHeight { type Err = HeightError; fn from_str(s: &str) -> Result { - namada_core::ibc::core::client::types::Height::from_str(s).map_or_else( + ibc::core::client::types::Height::from_str(s).map_or_else( |err| match err { HeightError::ZeroHeight => { Ok(TimeoutHeight(IbcTimeoutHeight::Never)) diff --git a/crates/ibc/src/lib.rs b/crates/ibc/src/lib.rs index 65be208679..15a673c9c6 100644 --- a/crates/ibc/src/lib.rs +++ b/crates/ibc/src/lib.rs @@ -20,6 +20,8 @@ mod actions; pub mod context; pub mod event; +mod msg; +mod nft; pub mod parameters; pub mod storage; @@ -27,6 +29,7 @@ use std::cell::RefCell; use std::collections::BTreeSet; use std::fmt::Debug; use std::rc::Rc; +use std::str::FromStr; pub use actions::transfer_over_ibc; use borsh::BorshDeserialize; @@ -39,42 +42,52 @@ pub use context::token_transfer::TokenTransferContext; pub use context::transfer_mod::{ModuleWrapper, TransferModule}; use context::IbcContext; pub use context::ValidationParams; -use namada_core::address::Address; -use namada_core::ibc::apps::nft_transfer::handler::{ +use ibc::apps::nft_transfer::handler::{ send_nft_transfer_execute, send_nft_transfer_validate, }; -use namada_core::ibc::apps::nft_transfer::types::error::NftTransferError; -use namada_core::ibc::apps::nft_transfer::types::{ - is_receiver_chain_source as is_nft_receiver_chain_source, PrefixedClassId, - TokenId, TracePrefix as NftTracePrefix, +use ibc::apps::nft_transfer::types::error::NftTransferError; +use ibc::apps::nft_transfer::types::{ + ack_success_b64, is_receiver_chain_source as is_nft_receiver_chain_source, + PrefixedClassId, TokenId, TracePath as NftTracePath, + TracePrefix as NftTracePrefix, }; -use namada_core::ibc::apps::transfer::handler::{ +use ibc::apps::transfer::handler::{ send_transfer_execute, send_transfer_validate, }; -use namada_core::ibc::apps::transfer::types::error::TokenTransferError; -use namada_core::ibc::apps::transfer::types::{ - ack_success_b64, is_receiver_chain_source, TracePrefix, +use ibc::apps::transfer::types::error::TokenTransferError; +use ibc::apps::transfer::types::{ + is_receiver_chain_source, PrefixedDenom, TracePath, TracePrefix, }; -use namada_core::ibc::core::channel::types::acknowledgement::{ +use ibc::core::channel::types::acknowledgement::{ Acknowledgement, AcknowledgementStatus, }; -use namada_core::ibc::core::channel::types::commitment::compute_ack_commitment; -use namada_core::ibc::core::channel::types::msgs::{ +use ibc::core::channel::types::commitment::compute_ack_commitment; +use ibc::core::channel::types::msgs::{ MsgRecvPacket as IbcMsgRecvPacket, PacketMsg, }; -use namada_core::ibc::core::entrypoint::{execute, validate}; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::handler::types::events::Error as RawIbcEventError; -use namada_core::ibc::core::handler::types::msgs::MsgEnvelope; -use namada_core::ibc::core::host::types::error::IdentifierError; -use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; -use namada_core::ibc::core::router::types::error::RouterError; -use namada_core::ibc::primitives::proto::Any; -pub use namada_core::ibc::*; -use namada_token::Transfer; +use ibc::core::entrypoint::{execute, validate}; +use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::events::Error as RawIbcEventError; +use ibc::core::handler::types::msgs::MsgEnvelope; +use ibc::core::host::types::error::IdentifierError; +use ibc::core::host::types::identifiers::{ChannelId, PortId}; +use ibc::core::router::types::error::RouterError; +use ibc::primitives::proto::Any; +pub use ibc::*; +pub use msg::*; +use namada_core::address::{self, Address}; +use namada_token::ShieldingTransfer; +pub use nft::*; use prost::Message; use thiserror::Error; +/// The event type defined in ibc-rs for receiving a token +pub const EVENT_TYPE_PACKET: &str = "fungible_token_packet"; +/// The event type defined in ibc-rs for receiving an NFT +pub const EVENT_TYPE_NFT_PACKET: &str = "non_fungible_token_packet"; +/// The escrow address for IBC transfer +pub const IBC_ESCROW_ADDRESS: Address = address::IBC; + #[allow(missing_docs)] #[derive(Error, Debug)] pub enum Error { @@ -139,7 +152,7 @@ where pub fn execute( &mut self, tx_data: &[u8], - ) -> Result, Error> { + ) -> Result, Error> { let message = decode_message(tx_data)?; match &message { IbcMessage::Transfer(msg) => { @@ -428,6 +441,37 @@ pub fn received_ibc_token( } } +/// Returns the trace path and the token string if the denom is an IBC +/// denom. +pub fn is_ibc_denom(denom: impl AsRef) -> Option<(TracePath, String)> { + let prefixed_denom = PrefixedDenom::from_str(denom.as_ref()).ok()?; + let base_denom = prefixed_denom.base_denom.to_string(); + if prefixed_denom.trace_path.is_empty() || base_denom.contains('/') { + // The denom is just a token or an NFT trace + return None; + } + // The base token isn't decoded because it could be non Namada token + Some((prefixed_denom.trace_path, base_denom)) +} + +/// Returns the trace path and the token string if the trace is an NFT one +pub fn is_nft_trace( + trace: impl AsRef, +) -> Option<(NftTracePath, String, String)> { + // The trace should be {port}/{channel}/.../{class_id}/{token_id} + if let Some((class_id, token_id)) = trace.as_ref().rsplit_once('/') { + let prefixed_class_id = PrefixedClassId::from_str(class_id).ok()?; + // The base token isn't decoded because it could be non Namada token + Some(( + prefixed_class_id.trace_path, + prefixed_class_id.base_class_id.to_string(), + token_id.to_string(), + )) + } else { + None + } +} + #[cfg(any(test, feature = "testing"))] /// Testing helpers ans strategies for IBC pub mod testing { diff --git a/crates/ibc/src/msg.rs b/crates/ibc/src/msg.rs new file mode 100644 index 0000000000..7502cf1e31 --- /dev/null +++ b/crates/ibc/src/msg.rs @@ -0,0 +1,193 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use ibc::apps::nft_transfer::types::msgs::transfer::MsgTransfer as IbcMsgNftTransfer; +use ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; +use ibc::core::channel::types::msgs::{ + MsgAcknowledgement as IbcMsgAcknowledgement, + MsgRecvPacket as IbcMsgRecvPacket, MsgTimeout as IbcMsgTimeout, +}; +use ibc::core::handler::types::msgs::MsgEnvelope; +use ibc::primitives::proto::Protobuf; +use namada_token::ShieldingTransfer; + +/// The different variants of an Ibc message +pub enum IbcMessage { + /// Ibc Envelop + Envelope(Box), + /// Ibc transaprent transfer + Transfer(MsgTransfer), + /// NFT transfer + NftTransfer(MsgNftTransfer), + /// Receiving a packet + RecvPacket(MsgRecvPacket), + /// Acknowledgement + AckPacket(MsgAcknowledgement), + /// Timeout + Timeout(MsgTimeout), +} + +/// IBC transfer message with `Transfer` +#[derive(Debug, Clone)] +pub struct MsgTransfer { + /// IBC transfer message + pub message: IbcMsgTransfer, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgTransfer { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgTransfer { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgTransfer::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} + +/// IBC NFT transfer message with `Transfer` +#[derive(Debug, Clone)] +pub struct MsgNftTransfer { + /// IBC NFT transfer message + pub message: IbcMsgNftTransfer, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgNftTransfer { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgNftTransfer { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgNftTransfer::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} + +/// IBC receiving packet message with `Transfer` +#[derive(Debug, Clone)] +pub struct MsgRecvPacket { + /// IBC receiving packet message + pub message: IbcMsgRecvPacket, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgRecvPacket { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgRecvPacket { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgRecvPacket::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} + +/// IBC acknowledgement message with `Transfer` for refunding to a shielded +/// address +#[derive(Debug, Clone)] +pub struct MsgAcknowledgement { + /// IBC acknowledgement message + pub message: IbcMsgAcknowledgement, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgAcknowledgement { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgAcknowledgement { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgAcknowledgement::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} + +/// IBC timeout packet message with `Transfer` for refunding to a shielded +/// address +#[derive(Debug, Clone)] +pub struct MsgTimeout { + /// IBC timeout message + pub message: IbcMsgTimeout, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgTimeout { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgTimeout { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgTimeout::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} diff --git a/crates/ibc/src/nft.rs b/crates/ibc/src/nft.rs new file mode 100644 index 0000000000..a1f05502a9 --- /dev/null +++ b/crates/ibc/src/nft.rs @@ -0,0 +1,193 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use ibc::apps::nft_transfer::context::{NftClassContext, NftContext}; +use ibc::apps::nft_transfer::types::error::NftTransferError; +use ibc::apps::nft_transfer::types::{ + ClassData, ClassId, ClassUri, PrefixedClassId, TokenData, TokenId, TokenUri, +}; + +/// NFT class +#[derive(Clone, Debug)] +pub struct NftClass { + /// NFT class ID + pub class_id: PrefixedClassId, + /// NFT class URI + pub class_uri: Option, + /// NFT class data + pub class_data: Option, +} + +impl BorshSerialize for NftClass { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + BorshSerialize::serialize(&self.class_id.to_string(), writer)?; + match &self.class_uri { + Some(uri) => { + BorshSerialize::serialize(&true, writer)?; + BorshSerialize::serialize(&uri.to_string(), writer)?; + } + None => BorshSerialize::serialize(&false, writer)?, + } + match &self.class_data { + Some(data) => { + BorshSerialize::serialize(&true, writer)?; + BorshSerialize::serialize(&data.to_string(), writer) + } + None => BorshSerialize::serialize(&false, writer), + } + } +} + +impl BorshDeserialize for NftClass { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let class_id: String = BorshDeserialize::deserialize_reader(reader)?; + let class_id = class_id.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?; + + let is_uri: bool = BorshDeserialize::deserialize_reader(reader)?; + let class_uri = if is_uri { + let uri_str: String = BorshDeserialize::deserialize_reader(reader)?; + Some(uri_str.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?) + } else { + None + }; + + let is_data: bool = BorshDeserialize::deserialize_reader(reader)?; + let class_data = if is_data { + let data_str: String = + BorshDeserialize::deserialize_reader(reader)?; + Some(data_str.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?) + } else { + None + }; + + Ok(Self { + class_id, + class_uri, + class_data, + }) + } +} + +impl NftClassContext for NftClass { + fn get_id(&self) -> &ClassId { + &self.class_id.base_class_id + } + + fn get_uri(&self) -> Option<&ClassUri> { + self.class_uri.as_ref() + } + + fn get_data(&self) -> Option<&ClassData> { + self.class_data.as_ref() + } +} + +/// NFT metadata +#[derive(Clone, Debug)] +pub struct NftMetadata { + /// NFT class ID + pub class_id: PrefixedClassId, + /// NFT ID + pub token_id: TokenId, + /// NFT URI + pub token_uri: Option, + /// NFT data + pub token_data: Option, +} + +impl BorshSerialize for NftMetadata { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + BorshSerialize::serialize(&self.class_id.to_string(), writer)?; + BorshSerialize::serialize(&self.token_id.to_string(), writer)?; + match &self.token_uri { + Some(uri) => { + BorshSerialize::serialize(&true, writer)?; + BorshSerialize::serialize(&uri.to_string(), writer)?; + } + None => BorshSerialize::serialize(&false, writer)?, + } + match &self.token_data { + Some(data) => { + BorshSerialize::serialize(&true, writer)?; + BorshSerialize::serialize(&data.to_string(), writer) + } + None => BorshSerialize::serialize(&false, writer), + } + } +} + +impl BorshDeserialize for NftMetadata { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let class_id: String = BorshDeserialize::deserialize_reader(reader)?; + let class_id = class_id.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?; + + let token_id: String = BorshDeserialize::deserialize_reader(reader)?; + let token_id = token_id.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?; + + let is_uri: bool = BorshDeserialize::deserialize_reader(reader)?; + let token_uri = if is_uri { + let uri_str: String = BorshDeserialize::deserialize_reader(reader)?; + Some(uri_str.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?) + } else { + None + }; + + let is_data: bool = BorshDeserialize::deserialize_reader(reader)?; + let token_data = if is_data { + let data_str: String = + BorshDeserialize::deserialize_reader(reader)?; + Some(data_str.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?) + } else { + None + }; + + Ok(Self { + class_id, + token_id, + token_uri, + token_data, + }) + } +} + +impl NftContext for NftMetadata { + fn get_class_id(&self) -> &ClassId { + &self.class_id.base_class_id + } + + fn get_id(&self) -> &TokenId { + &self.token_id + } + + fn get_uri(&self) -> Option<&TokenUri> { + self.token_uri.as_ref() + } + + fn get_data(&self) -> Option<&TokenData> { + self.token_data.as_ref() + } +} diff --git a/crates/ibc/src/storage.rs b/crates/ibc/src/storage.rs index c9fa19839a..b187b2e41c 100644 --- a/crates/ibc/src/storage.rs +++ b/crates/ibc/src/storage.rs @@ -2,17 +2,17 @@ use std::str::FromStr; -use namada_core::address::{Address, InternalAddress, HASH_LEN, SHA_HASH_LEN}; -use namada_core::ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId}; -use namada_core::ibc::core::client::types::Height; -use namada_core::ibc::core::host::types::identifiers::{ +use ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId}; +use ibc::core::client::types::Height; +use ibc::core::host::types::identifiers::{ ChannelId, ClientId, ConnectionId, PortId, Sequence, }; -use namada_core::ibc::core::host::types::path::{ +use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, Path, PortPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; +use namada_core::address::{Address, InternalAddress, HASH_LEN, SHA_HASH_LEN}; use namada_core::ibc::IbcTokenHash; use namada_core::storage::{DbKeySeg, Key, KeySeg}; use namada_core::token::Amount; diff --git a/crates/light_sdk/src/transaction/transfer.rs b/crates/light_sdk/src/transaction/transfer.rs index 3275447ac7..84475660ea 100644 --- a/crates/light_sdk/src/transaction/transfer.rs +++ b/crates/light_sdk/src/transaction/transfer.rs @@ -1,43 +1,98 @@ -use borsh_ext::BorshSerializeExt; use namada_sdk::address::Address; use namada_sdk::hash::Hash; use namada_sdk::key::common; use namada_sdk::token::DenominatedAmount; use namada_sdk::tx::data::GasLimit; -use namada_sdk::tx::{Authorization, Tx, TxError}; +use namada_sdk::tx::{ + Authorization, Tx, TxError, TX_SHIELDED_TRANSFER_WASM, + TX_SHIELDING_TRANSFER_WASM, TX_TRANSPARENT_TRANSFER_WASM, + TX_UNSHIELDING_TRANSFER_WASM, +}; use super::{attach_fee, attach_fee_signature, GlobalArgs}; use crate::transaction; -const TX_TRANSFER_WASM: &str = "tx_transfer.wasm"; - /// A transfer transaction #[derive(Debug, Clone)] pub struct Transfer(Tx); impl Transfer { - /// Build a raw Transfer transaction from the given parameters - pub fn new( + /// Build a transparent transfer transaction from the given parameters + pub fn transparent( source: Address, target: Address, token: Address, amount: DenominatedAmount, - // TODO(namada#2596): handle masp here - shielded: Option, args: GlobalArgs, ) -> Self { - let init_proposal = namada_sdk::token::Transfer { + let data = namada_sdk::token::TransparentTransfer { + source, + target, + token, + amount, + }; + + Self(transaction::build_tx( + args, + data, + TX_TRANSPARENT_TRANSFER_WASM.to_string(), + )) + } + + /// Build a shielded transfer transaction from the given parameters + pub fn shielded(shielded_section_hash: Hash, args: GlobalArgs) -> Self { + let data = namada_sdk::token::ShieldedTransfer { + section_hash: shielded_section_hash, + }; + + Self(transaction::build_tx( + args, + data, + TX_SHIELDED_TRANSFER_WASM.to_string(), + )) + } + + /// Build a shielding transfer transaction from the given parameters + pub fn shielding( + source: Address, + token: Address, + amount: DenominatedAmount, + shielded_section_hash: Hash, + args: GlobalArgs, + ) -> Self { + let data = namada_sdk::token::ShieldingTransfer { source, + token, + amount, + shielded_section_hash, + }; + + Self(transaction::build_tx( + args, + data, + TX_SHIELDING_TRANSFER_WASM.to_string(), + )) + } + + /// Build an unshielding transfer transaction from the given parameters + pub fn unshielding( + target: Address, + token: Address, + amount: DenominatedAmount, + shielded_section_hash: Hash, + args: GlobalArgs, + ) -> Self { + let data = namada_sdk::token::UnshieldingTransfer { target, token, amount, - shielded, + shielded_section_hash, }; Self(transaction::build_tx( args, - init_proposal.serialize_to_vec(), - TX_TRANSFER_WASM.to_string(), + data, + TX_UNSHIELDING_TRANSFER_WASM.to_string(), )) } diff --git a/crates/namada/src/ledger/native_vp/ibc/mod.rs b/crates/namada/src/ledger/native_vp/ibc/mod.rs index a0e1f41bbd..485b4ea81c 100644 --- a/crates/namada/src/ledger/native_vp/ibc/mod.rs +++ b/crates/namada/src/ledger/native_vp/ibc/mod.rs @@ -419,7 +419,6 @@ mod tests { use crate::core::address::testing::{ established_address_1, established_address_2, nam, }; - use crate::core::ibc::{MsgNftTransfer, MsgTransfer}; use crate::core::storage::Epoch; use crate::ibc::apps::nft_transfer::types::events::{ RecvEvent as NftRecvEvent, TokenTraceEvent, @@ -499,7 +498,7 @@ mod tests { next_sequence_recv_key, next_sequence_send_key, nft_class_key, nft_metadata_key, receipt_key, }; - use crate::ibc::{NftClass, NftMetadata}; + use crate::ibc::{MsgNftTransfer, MsgTransfer, NftClass, NftMetadata}; use crate::key::testing::keypair_1; use crate::ledger::gas::VpGasMeter; use crate::ledger::parameters::storage::{ diff --git a/crates/namada/src/ledger/protocol/mod.rs b/crates/namada/src/ledger/protocol/mod.rs index 3b481da6a6..b19098e18d 100644 --- a/crates/namada/src/ledger/protocol/mod.rs +++ b/crates/namada/src/ledger/protocol/mod.rs @@ -7,13 +7,11 @@ use borsh_ext::BorshSerializeExt; use eyre::{eyre, WrapErr}; use namada_core::booleans::BoolResultUnitExt; use namada_core::hash::Hash; -use namada_core::storage::Key; use namada_events::extend::{ ComposeEvent, Height as HeightAttr, TxHash as TxHashAttr, }; use namada_events::EventLevel; use namada_gas::TxGasMeter; -use namada_sdk::tx::TX_TRANSFER_WASM; use namada_state::StorageWrite; use namada_token::event::{TokenEvent, TokenOperation, UserAccount}; use namada_tx::data::protocol::{ProtocolTx, ProtocolTxType}; @@ -396,22 +394,6 @@ where Ok(extended_tx_result) } -/// Load the wasm hash for a transfer from storage. -/// -/// # Panics -/// If the transaction hash is not found in storage -pub fn get_transfer_hash_from_storage(storage: &S) -> Hash -where - S: StorageRead, -{ - let transfer_code_name_key = - Key::wasm_code_name(TX_TRANSFER_WASM.to_string()); - storage - .read(&transfer_code_name_key) - .expect("Could not read the storage") - .expect("Expected tx transfer hash in storage") -} - /// Performs the required operation on a wrapper transaction: /// - replay protection /// - fee payment diff --git a/crates/node/src/bench_utils.rs b/crates/node/src/bench_utils.rs index e49c1d184b..ba4074517b 100644 --- a/crates/node/src/bench_utils.rs +++ b/crates/node/src/bench_utils.rs @@ -26,7 +26,6 @@ use namada::core::masp::{ }; use namada::core::storage::{BlockHeight, Epoch, Key, KeySeg, TxIndex}; use namada::core::time::DateTimeUtc; -use namada::core::token::{Amount, DenominatedAmount, Transfer}; use namada::events::extend::{ComposeEvent, MaspTxBatchRefs, MaspTxBlockIndex}; use namada::events::Event; use namada::governance::storage::proposal::ProposalType; @@ -76,6 +75,10 @@ use namada::ledger::queries::{ }; use namada::masp::MaspTxRefs; use namada::state::StorageRead; +use namada::token::{ + Amount, DenominatedAmount, ShieldedTransfer, ShieldingTransfer, + UnshieldingTransfer, +}; use namada::tx::data::pos::Bond; use namada::tx::data::{ BatchResults, BatchedTxResult, Fee, TxResult, VpsResult, @@ -91,7 +94,7 @@ use namada_apps_lib::cli::context::FromContext; use namada_apps_lib::cli::Context; use namada_apps_lib::wallet::{defaults, CliWalletUtils}; use namada_sdk::masp::{ - self, ContextSyncStatus, ShieldedContext, ShieldedTransfer, ShieldedUtils, + self, ContextSyncStatus, ShieldedContext, ShieldedUtils, }; pub use namada_sdk::tx::{ TX_BECOME_VALIDATOR_WASM, TX_BOND_WASM, TX_BRIDGE_POOL_WASM, @@ -101,10 +104,11 @@ pub use namada_sdk::tx::{ TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL as TX_INIT_PROPOSAL_WASM, TX_REACTIVATE_VALIDATOR_WASM, TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, - TX_REVEAL_PK as TX_REVEAL_PK_WASM, TX_TRANSFER_WASM, TX_UNBOND_WASM, - TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, - TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL as TX_VOTE_PROPOSAL_WASM, - TX_WITHDRAW_WASM, VP_USER_WASM, + TX_REVEAL_PK as TX_REVEAL_PK_WASM, TX_SHIELDED_TRANSFER_WASM, + TX_SHIELDING_TRANSFER_WASM, TX_TRANSPARENT_TRANSFER_WASM, TX_UNBOND_WASM, + TX_UNJAIL_VALIDATOR_WASM, TX_UNSHIELDING_TRANSFER_WASM, + TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, + TX_VOTE_PROPOSAL as TX_VOTE_PROPOSAL_WASM, TX_WITHDRAW_WASM, VP_USER_WASM, }; use namada_sdk::wallet::Wallet; use namada_sdk::{Namada, NamadaImpl}; @@ -1085,43 +1089,61 @@ impl BenchShieldedCtx { ) .unwrap() .map( - |ShieldedTransfer { + |masp::ShieldedTransfer { builder: _, masp_tx, metadata: _, epoch: _, }| masp_tx, - ); + ) + .expect("MASP must have shielded part"); let mut hasher = Sha256::new(); - let shielded_section_hash = shielded.clone().map(|transaction| { - namada::core::hash::Hash( - Section::MaspTx(transaction) - .hash(&mut hasher) - .finalize_reset() - .into(), + let shielded_section_hash = namada::core::hash::Hash( + Section::MaspTx(shielded.clone()) + .hash(&mut hasher) + .finalize_reset() + .into(), + ); + let tx = if source.effective_address() == MASP + && target.effective_address() == MASP + { + namada.client().generate_tx( + TX_SHIELDED_TRANSFER_WASM, + ShieldedTransfer { + section_hash: shielded_section_hash, + }, + Some(shielded), + None, + vec![&defaults::albert_keypair()], ) - }); - - let tx = namada.client().generate_tx( - TX_TRANSFER_WASM, - Transfer { - source: source.effective_address(), - target: target.effective_address(), - token: address::testing::nam(), - amount: if source.effective_address().eq(&MASP) - && target.effective_address().eq(&MASP) - { - DenominatedAmount::native(0.into()) - } else { - DenominatedAmount::native(amount) + } else if target.effective_address() == MASP { + namada.client().generate_tx( + TX_SHIELDING_TRANSFER_WASM, + ShieldingTransfer { + source: source.effective_address(), + token: address::testing::nam(), + amount: DenominatedAmount::native(amount), + shielded_section_hash, }, - shielded: shielded_section_hash, - }, - shielded, - None, - vec![&defaults::albert_keypair()], - ); + Some(shielded), + None, + vec![&defaults::albert_keypair()], + ) + } else { + namada.client().generate_tx( + TX_UNSHIELDING_TRANSFER_WASM, + UnshieldingTransfer { + target: target.effective_address(), + token: address::testing::nam(), + amount: DenominatedAmount::native(amount), + shielded_section_hash, + }, + Some(shielded), + None, + vec![&defaults::albert_keypair()], + ) + }; let NamadaImpl { client, wallet, @@ -1180,12 +1202,13 @@ impl BenchShieldedCtx { timeout_timestamp_on_b: timeout_timestamp, }; - let transfer = - Transfer::deserialize(&mut tx.tx.data(&tx.cmt).unwrap().as_slice()) - .unwrap(); + let transfer = ShieldingTransfer::deserialize( + &mut tx.tx.data(&tx.cmt).unwrap().as_slice(), + ) + .unwrap(); let masp_tx = tx .tx - .get_section(&transfer.shielded.unwrap()) + .get_section(&transfer.shielded_section_hash) .unwrap() .masp_tx() .unwrap(); diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index c408e74085..6a3244a914 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -46,6 +46,7 @@ testing = [ "namada_ibc/testing", "namada_proof_of_stake/testing", "namada_storage/testing", + "namada_token/testing", "namada_tx/testing", "async-client", "proptest", @@ -159,6 +160,7 @@ namada_proof_of_stake = { path = "../proof_of_stake", default-features = false, namada_state = { path = "../state", features = ["testing"] } namada_storage = { path = "../storage", features = ["testing"] } namada_test_utils = { path = "../test_utils" } +namada_token = { path = "../token", features = ["testing"] } namada_tx = { path = "../tx", features = ["testing"]} namada_vote_ext = {path = "../vote_ext"} diff --git a/crates/sdk/src/args.rs b/crates/sdk/src/args.rs index 91b028a8e0..f672b1d4ff 100644 --- a/crates/sdk/src/args.rs +++ b/crates/sdk/src/args.rs @@ -59,10 +59,12 @@ pub trait NamadaTypes: Clone + std::fmt::Debug { + From; /// Represents the address of an Ethereum endpoint type EthereumAddress: Clone + std::fmt::Debug; - /// Represents a viewing key + /// Represents a shielded viewing key type ViewingKey: Clone + std::fmt::Debug; - /// Represents a spending key + /// Represents a shielded spending key type SpendingKey: Clone + std::fmt::Debug; + /// Represents a shielded payment address + type PaymentAddress: Clone + std::fmt::Debug; /// Represents the owner of a balance type BalanceOwner: Clone + std::fmt::Debug; /// Represents a public key @@ -101,6 +103,7 @@ impl NamadaTypes for SdkTypes { type Data = Vec; type EthereumAddress = (); type Keypair = namada_core::key::common::SecretKey; + type PaymentAddress = namada_core::masp::PaymentAddress; type PublicKey = namada_core::key::common::PublicKey; type SpendingKey = namada_core::masp::ExtendedSpendingKey; type TendermintAddress = tendermint_rpc::Url; @@ -226,15 +229,15 @@ impl From for InputAmount { } } -/// Transfer transaction arguments +/// Transparent transfer transaction arguments #[derive(Clone, Debug)] -pub struct TxTransfer { +pub struct TxTransparentTransfer { /// Common tx arguments pub tx: Tx, /// Transfer source address - pub source: C::TransferSource, + pub source: C::Address, /// Transfer target address - pub target: C::TransferTarget, + pub target: C::Address, /// Transferred token address pub token: C::Address, /// Transferred token amount @@ -243,26 +246,26 @@ pub struct TxTransfer { pub tx_code_path: PathBuf, } -impl TxBuilder for TxTransfer { +impl TxBuilder for TxTransparentTransfer { fn tx(self, func: F) -> Self where F: FnOnce(Tx) -> Tx, { - TxTransfer { + TxTransparentTransfer { tx: func(self.tx), ..self } } } -impl TxTransfer { +impl TxTransparentTransfer { /// Transfer source address - pub fn source(self, source: C::TransferSource) -> Self { + pub fn source(self, source: C::Address) -> Self { Self { source, ..self } } /// Transfer target address - pub fn receiver(self, target: C::TransferTarget) -> Self { + pub fn receiver(self, target: C::Address) -> Self { Self { target, ..self } } @@ -285,14 +288,94 @@ impl TxTransfer { } } -impl TxTransfer { +impl TxTransparentTransfer { /// Build a transaction from this builder pub async fn build( &mut self, context: &impl Namada, - ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, Option)> - { - tx::build_transfer(context, self).await + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData)> { + tx::build_transparent_transfer(context, self).await + } +} + +/// Shielded transfer transaction arguments +#[derive(Clone, Debug)] +pub struct TxShieldedTransfer { + /// Common tx arguments + pub tx: Tx, + /// Transfer source spending key + pub source: C::SpendingKey, + /// Transfer target address + pub target: C::PaymentAddress, + /// Transferred token address + pub token: C::Address, + /// Transferred token amount + pub amount: InputAmount, + /// Path to the TX WASM code file + pub tx_code_path: PathBuf, +} + +impl TxShieldedTransfer { + /// Build a transaction from this builder + pub async fn build( + &mut self, + context: &impl Namada, + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, Epoch)> { + tx::build_shielded_transfer(context, self).await + } +} + +/// Shielding transfer transaction arguments +#[derive(Clone, Debug)] +pub struct TxShieldingTransfer { + /// Common tx arguments + pub tx: Tx, + /// Transfer source address + pub source: C::Address, + /// Transfer target address + pub target: C::PaymentAddress, + /// Transferred token address + pub token: C::Address, + /// Transferred token amount + pub amount: InputAmount, + /// Path to the TX WASM code file + pub tx_code_path: PathBuf, +} + +impl TxShieldingTransfer { + /// Build a transaction from this builder + pub async fn build( + &mut self, + context: &impl Namada, + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, Epoch)> { + tx::build_shielding_transfer(context, self).await + } +} + +/// Unshielding transfer transaction arguments +#[derive(Clone, Debug)] +pub struct TxUnshieldingTransfer { + /// Common tx arguments + pub tx: Tx, + /// Transfer source spending key + pub source: C::SpendingKey, + /// Transfer target address + pub target: C::Address, + /// Transferred token address + pub token: C::Address, + /// Transferred token amount + pub amount: InputAmount, + /// Path to the TX WASM code file + pub tx_code_path: PathBuf, +} + +impl TxUnshieldingTransfer { + /// Build a transaction from this builder + pub async fn build( + &mut self, + context: &impl Namada, + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, Epoch)> { + tx::build_unshielding_transfer(context, self).await } } diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 2d6c060c4d..7832b23d33 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -21,7 +21,7 @@ pub use { bip39, masp_primitives, masp_proofs, namada_account as account, namada_gas as gas, namada_governance as governance, namada_proof_of_stake as proof_of_stake, namada_state as state, - namada_storage as storage, zeroize, + namada_storage as storage, namada_token as token, zeroize, }; pub mod eth_bridge; @@ -51,36 +51,35 @@ use std::path::PathBuf; use std::str::FromStr; use args::{InputAmount, SdkTypes}; +use io::Io; +use masp::{ShieldedContext, ShieldedUtils}; use namada_core::address::Address; use namada_core::collections::HashSet; use namada_core::dec::Dec; use namada_core::ethereum_events::EthAddress; use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::key::*; -use namada_core::masp::{TransferSource, TransferTarget}; +use namada_core::masp::{ExtendedSpendingKey, PaymentAddress, TransferSource}; use namada_tx::data::wrapper::GasLimit; use namada_tx::Tx; +use rpc::{denominate_amount, format_denominated_amount, query_native_token}; +use signing::SigningTxData; +use token::{DenominatedAmount, NATIVE_MAX_DECIMAL_PLACES}; use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; - -use crate::io::Io; -use crate::masp::{ShieldedContext, ShieldedUtils}; -use crate::rpc::{ - denominate_amount, format_denominated_amount, query_native_token, -}; -use crate::signing::SigningTxData; -use crate::token::{DenominatedAmount, NATIVE_MAX_DECIMAL_PLACES}; -use crate::tx::{ +use tx::{ ProcessTxResponse, TX_BECOME_VALIDATOR_WASM, TX_BOND_WASM, TX_BRIDGE_POOL_WASM, TX_CHANGE_COMMISSION_WASM, TX_CHANGE_CONSENSUS_KEY_WASM, TX_CHANGE_METADATA_WASM, TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL, TX_REACTIVATE_VALIDATOR_WASM, - TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_TRANSFER_WASM, - TX_UNBOND_WASM, TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, + TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, TX_REVEAL_PK, + TX_SHIELDED_TRANSFER_WASM, TX_SHIELDING_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_UNBOND_WASM, TX_UNJAIL_VALIDATOR_WASM, + TX_UNSHIELDING_TRANSFER_WASM, TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, VP_USER_WASM, }; -use crate::wallet::{Wallet, WalletIo, WalletStorage}; +use wallet::{Wallet, WalletIo, WalletStorage}; /// Default gas-limit pub const DEFAULT_GAS_LIMIT: u64 = 25_000; @@ -172,20 +171,78 @@ pub trait Namada: Sized + MaybeSync + MaybeSend { } } - /// Make a TxTransfer builder from the given minimum set of arguments - fn new_transfer( + /// Make a TxTransparentTransfer builder from the given minimum set of + /// arguments + fn new_transparent_transfer( &self, - source: TransferSource, - target: TransferTarget, + source: Address, + target: Address, + token: Address, + amount: InputAmount, + ) -> args::TxTransparentTransfer { + args::TxTransparentTransfer { + source, + target, + token, + amount, + tx_code_path: PathBuf::from(TX_TRANSPARENT_TRANSFER_WASM), + tx: self.tx_builder(), + } + } + + /// Make a TxShieldedTransfer builder from the given minimum set of + /// arguments + fn new_shielded_transfer( + &self, + source: ExtendedSpendingKey, + target: PaymentAddress, token: Address, amount: InputAmount, - ) -> args::TxTransfer { - args::TxTransfer { + ) -> args::TxShieldedTransfer { + args::TxShieldedTransfer { source, target, token, amount, - tx_code_path: PathBuf::from(TX_TRANSFER_WASM), + tx_code_path: PathBuf::from(TX_SHIELDED_TRANSFER_WASM), + tx: self.tx_builder(), + } + } + + /// Make a TxShieldingTransfer builder from the given minimum set of + /// arguments + fn new_shielding_transfer( + &self, + source: Address, + target: PaymentAddress, + token: Address, + amount: InputAmount, + ) -> args::TxShieldingTransfer { + args::TxShieldingTransfer { + source, + target, + token, + amount, + tx_code_path: PathBuf::from(TX_SHIELDING_TRANSFER_WASM), + tx: self.tx_builder(), + } + } + + /// Make a TxUnshieldingTransfer builder from the given minimum set of + /// arguments + fn new_unshielding_transfer( + &self, + source: ExtendedSpendingKey, + target: Address, + token: Address, + amount: InputAmount, + ) -> args::TxUnshieldingTransfer { + args::TxUnshieldingTransfer { + source, + target, + token, + amount, + tx_code_path: PathBuf::from(TX_UNSHIELDING_TRANSFER_WASM), tx: self.tx_builder(), } } @@ -807,17 +864,21 @@ pub mod testing { use namada_core::address::testing::{ arb_established_address, arb_non_internal_address, }; - use namada_core::address::MASP; use namada_core::eth_bridge_pool::PendingTransfer; use namada_core::hash::testing::arb_hash; use namada_core::key::testing::arb_common_keypair; - use namada_core::token::testing::{arb_denominated_amount, arb_transfer}; - use namada_core::token::Transfer; use namada_governance::storage::proposal::testing::{ arb_init_proposal, arb_vote_proposal, }; use namada_governance::{InitProposalData, VoteProposalData}; use namada_ibc::testing::arb_ibc_any; + use namada_token::testing::{ + arb_denominated_amount, arb_transparent_transfer, + }; + use namada_token::{ + ShieldedTransfer, ShieldingTransfer, TransparentTransfer, + UnshieldingTransfer, + }; use namada_tx::data::pgf::UpdateStewardCommission; use namada_tx::data::pos::{ BecomeValidator, Bond, CommissionChange, ConsensusKeyChange, @@ -870,8 +931,10 @@ pub mod testing { UpdateAccount(UpdateAccount), VoteProposal(VoteProposalData), Withdraw(Withdraw), - Transfer(Transfer), - MaspTransfer(Transfer, (StoredBuildParams, String)), + TransparentTransfer(TransparentTransfer), + ShieldedTransfer(ShieldedTransfer, (StoredBuildParams, String)), + ShieldingTransfer(ShieldingTransfer, (StoredBuildParams, String)), + UnshieldingTransfer(UnshieldingTransfer, (StoredBuildParams, String)), Bond(Bond), Redelegation(Redelegation), UpdateStewardCommission(UpdateStewardCommission), @@ -1027,17 +1090,17 @@ pub mod testing { prop_compose! { /// Generate an arbitrary transfer transaction - pub fn arb_transfer_tx()( + pub fn arb_transparent_transfer_tx()( mut header in arb_header(), wrapper in arb_wrapper_tx(), - transfer in arb_transfer(), + transfer in arb_transparent_transfer(), code_hash in arb_hash(), ) -> (Tx, TxData) { header.tx_type = TxType::Wrapper(Box::new(wrapper)); let mut tx = Tx { header, sections: vec![] }; tx.add_data(transfer.clone()); - tx.add_code_from_hash(code_hash, Some(TX_TRANSFER_WASM.to_owned())); - (tx, TxData::Transfer(transfer)) + tx.add_code_from_hash(code_hash, Some(TX_TRANSPARENT_TRANSFER_WASM.to_owned())); + (tx, TxData::TransparentTransfer(transfer)) } } @@ -1059,56 +1122,62 @@ pub mod testing { Shielded, // Shielding transaction Shielding, - // Deshielding transaction - Deshielding, + // Unshielding transaction + Unshielding, } prop_compose! { /// Generate an arbitrary transfer transaction - pub fn arb_masp_transfer_tx()(transfer in arb_transfer())( + pub fn arb_masp_transfer_tx()(transfer in arb_transparent_transfer())( mut header in arb_header(), wrapper in arb_wrapper_tx(), code_hash in arb_hash(), (masp_tx_type, (shielded_transfer, asset_types, build_params)) in prop_oneof![ (Just(MaspTxType::Shielded), arb_shielded_transfer(0..MAX_ASSETS)), (Just(MaspTxType::Shielding), arb_shielding_transfer(encode_address(&transfer.source), 1)), - (Just(MaspTxType::Deshielding), arb_deshielding_transfer(encode_address(&transfer.target), 1)), + (Just(MaspTxType::Unshielding), arb_deshielding_transfer(encode_address(&transfer.target), 1)), ], - mut transfer in Just(transfer), + transfer in Just(transfer), ) -> (Tx, TxData) { header.tx_type = TxType::Wrapper(Box::new(wrapper)); let mut tx = Tx { header, sections: vec![] }; - match masp_tx_type { + let shielded_section_hash = tx.add_masp_tx_section(shielded_transfer.masp_tx).1; + let build_param_bytes = + data_encoding::HEXLOWER.encode(&build_params.serialize_to_vec()); + let tx_data = match masp_tx_type { MaspTxType::Shielded => { - transfer.source = MASP; - transfer.target = MASP; - transfer.amount = token::Amount::zero().into(); + tx.add_code_from_hash(code_hash, Some(TX_SHIELDED_TRANSFER_WASM.to_owned())); + let data = ShieldedTransfer { section_hash: shielded_section_hash }; + tx.add_data(data.clone()); + TxData::ShieldedTransfer(data, (build_params, build_param_bytes)) }, MaspTxType::Shielding => { - transfer.target = MASP; // Set the transparent amount and token let (decoded, value) = asset_types.iter().next().unwrap(); - transfer.amount = DenominatedAmount::new( + let token = decoded.token.clone(); + let amount = DenominatedAmount::new( token::Amount::from_masp_denominated(*value, decoded.position), decoded.denom, ); - transfer.token = decoded.token.clone(); + tx.add_code_from_hash(code_hash, Some(TX_SHIELDING_TRANSFER_WASM.to_owned())); + let data = ShieldingTransfer {source: transfer.source, token, amount, shielded_section_hash }; + tx.add_data(data.clone()); + TxData::ShieldingTransfer(data, (build_params, build_param_bytes)) }, - MaspTxType::Deshielding => { - transfer.source = MASP; + MaspTxType::Unshielding => { // Set the transparent amount and token let (decoded, value) = asset_types.iter().next().unwrap(); - transfer.amount = DenominatedAmount::new( + let token = decoded.token.clone(); + let amount = DenominatedAmount::new( token::Amount::from_masp_denominated(*value, decoded.position), decoded.denom, ); - transfer.token = decoded.token.clone(); + tx.add_code_from_hash(code_hash, Some(TX_UNSHIELDING_TRANSFER_WASM.to_owned())); + let data = UnshieldingTransfer {target: transfer.target, token, amount, shielded_section_hash }; + tx.add_data(data.clone()); + TxData::UnshieldingTransfer(data, (build_params, build_param_bytes)) }, - } - let masp_tx_hash = tx.add_masp_tx_section(shielded_transfer.masp_tx).1; - transfer.shielded = Some(masp_tx_hash); - tx.add_data(transfer.clone()); - tx.add_code_from_hash(code_hash, Some(TX_TRANSFER_WASM.to_owned())); + }; tx.add_masp_builder(MaspBuilder { asset_types: asset_types.into_keys().collect(), // Store how the Info objects map to Descriptors/Outputs @@ -1116,11 +1185,9 @@ pub mod testing { // Store the data that was used to construct the Transaction builder: shielded_transfer.builder, // Link the Builder to the Transaction by hash code - target: masp_tx_hash, + target: shielded_section_hash, }); - let build_param_bytes = - data_encoding::HEXLOWER.encode(&build_params.serialize_to_vec()); - (tx, TxData::MaspTransfer(transfer, (build_params, build_param_bytes))) + (tx, tx_data) } } @@ -1499,7 +1566,7 @@ pub mod testing { /// Generate an arbitrary tx pub fn arb_tx() -> impl Strategy { prop_oneof![ - arb_transfer_tx(), + arb_transparent_transfer_tx(), arb_masp_transfer_tx(), arb_bond_tx(), arb_unbond_tx(), diff --git a/crates/sdk/src/signing.rs b/crates/sdk/src/signing.rs index f6c5e4f840..a6e1ef5f44 100644 --- a/crates/sdk/src/signing.rs +++ b/crates/sdk/src/signing.rs @@ -17,15 +17,13 @@ use namada_core::collections::{HashMap, HashSet}; use namada_core::key::*; use namada_core::masp::{AssetData, ExtendedViewingKey, PaymentAddress}; use namada_core::sign::SignatureIndex; -use namada_core::token; -use namada_core::token::Transfer; -// use namada_core::storage::Key; use namada_core::token::{Amount, DenominatedAmount}; use namada_governance::storage::proposal::{ InitProposalData, ProposalType, VoteProposalData, }; use namada_governance::storage::vote::ProposalVote; use namada_parameters::storage as parameter_storage; +use namada_token as token; use namada_token::storage_key::balance_key; use namada_tx::data::pgf::UpdateStewardCommission; use namada_tx::data::pos::BecomeValidator; @@ -50,10 +48,11 @@ use crate::tx::{ TX_CHANGE_METADATA_WASM, TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL, TX_REACTIVATE_VALIDATOR_WASM, TX_REDELEGATE_WASM, - TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_TRANSFER_WASM, TX_UNBOND_WASM, - TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, - TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, - VP_USER_WASM, + TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_SHIELDED_TRANSFER_WASM, + TX_SHIELDING_TRANSFER_WASM, TX_TRANSPARENT_TRANSFER_WASM, TX_UNBOND_WASM, + TX_UNJAIL_VALIDATOR_WASM, TX_UNSHIELDING_TRANSFER_WASM, + TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, + TX_WITHDRAW_WASM, VP_USER_WASM, }; pub use crate::wallet::store::AddressVpType; use crate::wallet::{Wallet, WalletIo}; @@ -703,25 +702,61 @@ fn format_outputs(output: &mut Vec) { } } +enum TokenTransfer<'a> { + Transparent(&'a token::TransparentTransfer), + Shielded, + Shielding(&'a token::ShieldingTransfer), + Unshielding(&'a token::UnshieldingTransfer), +} + +impl TokenTransfer<'_> { + fn source(&self) -> Option<&Address> { + match self { + TokenTransfer::Transparent(transfer) => Some(&transfer.source), + TokenTransfer::Shielded => None, + TokenTransfer::Shielding(transfer) => Some(&transfer.source), + TokenTransfer::Unshielding(_) => None, + } + } + + fn target(&self) -> Option<&Address> { + match self { + TokenTransfer::Transparent(transfer) => Some(&transfer.target), + TokenTransfer::Shielded => None, + TokenTransfer::Shielding(_) => None, + TokenTransfer::Unshielding(transfer) => Some(&transfer.target), + } + } + + fn token_and_amount(&self) -> Option<(&Address, DenominatedAmount)> { + match self { + TokenTransfer::Transparent(transfer) => { + Some((&transfer.token, transfer.amount)) + } + TokenTransfer::Shielded => None, + TokenTransfer::Shielding(transfer) => { + Some((&transfer.token, transfer.amount)) + } + TokenTransfer::Unshielding(transfer) => { + Some((&transfer.token, transfer.amount)) + } + } + } +} + /// Adds a Ledger output for the sender and destination for transparent and MASP /// transactions -pub async fn make_ledger_masp_endpoints( +async fn make_ledger_token_transfer_endpoints( tokens: &HashMap, output: &mut Vec, - transfer: &Transfer, + transfer: TokenTransfer<'_>, builder: Option<&MaspBuilder>, assets: &HashMap, ) { - if transfer.source != MASP { - output.push(format!("Sender : {}", transfer.source)); - if transfer.target == MASP { - make_ledger_amount_addr( - tokens, - output, - transfer.amount, - &transfer.token, - "Sending ", - ); + if let Some(source) = transfer.source() { + output.push(format!("Sender : {}", source)); + if let Some((token, amount)) = transfer.token_and_amount() { + make_ledger_amount_addr(tokens, output, amount, token, "Sending "); } } else if let Some(builder) = builder { for sapling_input in builder.builder.sapling_inputs() { @@ -738,14 +773,14 @@ pub async fn make_ledger_masp_endpoints( .await; } } - if transfer.target != MASP { - output.push(format!("Destination : {}", transfer.target)); - if transfer.source == MASP { + if let Some(target) = transfer.target() { + output.push(format!("Destination : {}", target)); + if let Some((token, amount)) = transfer.token_and_amount() { make_ledger_amount_addr( tokens, output, - transfer.amount, - &transfer.token, + amount, + token, "Receiving ", ); } @@ -764,15 +799,6 @@ pub async fn make_ledger_masp_endpoints( .await; } } - if transfer.source != MASP && transfer.target != MASP { - make_ledger_amount_addr( - tokens, - output, - transfer.amount, - &transfer.token, - "", - ); - } } /// Convert decimal numbers into the format used by Ledger. Specifically remove @@ -1248,8 +1274,37 @@ pub async fn to_ledger_vector( HEXLOWER.encode(&extra_code_hash.0) )]); } - } else if code_sec.tag == Some(TX_TRANSFER_WASM.to_string()) { - let transfer = Transfer::try_from_slice( + } else if code_sec.tag == Some(TX_TRANSPARENT_TRANSFER_WASM.to_string()) + { + let transfer = token::TransparentTransfer::try_from_slice( + &tx.data(cmt) + .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, + ) + .map_err(|err| { + Error::from(EncodingError::Conversion(err.to_string())) + })?; + + tv.name = "Transfer_0".to_string(); + + tv.output.push("Type : TransparentTransfer".to_string()); + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output, + TokenTransfer::Transparent(&transfer), + None, + &HashMap::default(), + ) + .await; + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output_expert, + TokenTransfer::Transparent(&transfer), + None, + &HashMap::default(), + ) + .await; + } else if code_sec.tag == Some(TX_SHIELDED_TRANSFER_WASM.to_string()) { + let transfer = token::ShieldedTransfer::try_from_slice( &tx.data(cmt) .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, ) @@ -1258,43 +1313,134 @@ pub async fn to_ledger_vector( })?; // To facilitate lookups of MASP AssetTypes let mut asset_types = HashMap::new(); - let builder = if let Some(shielded_hash) = transfer.shielded { - tx.sections.iter().find_map(|x| match x { - Section::MaspBuilder(builder) - if builder.target == shielded_hash => - { - for decoded in &builder.asset_types { - match decoded.encode() { - Err(_) => None, - Ok(asset) => { - asset_types.insert(asset, decoded.clone()); - Some(builder) - } - }?; - } - Some(builder) + let builder = tx.sections.iter().find_map(|x| match x { + Section::MaspBuilder(builder) + if builder.target == transfer.section_hash => + { + for decoded in &builder.asset_types { + match decoded.encode() { + Err(_) => None, + Ok(asset) => { + asset_types.insert(asset, decoded.clone()); + Some(builder) + } + }?; } - _ => None, - }) - } else { - None - }; + Some(builder) + } + _ => None, + }); - tv.name = "Transfer_0".to_string(); + tv.name = "ShieldedTransfer_0".to_string(); + + tv.output.push("Type : ShieldedTransfer".to_string()); + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output, + TokenTransfer::Shielded, + builder, + &asset_types, + ) + .await; + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output_expert, + TokenTransfer::Shielded, + builder, + &asset_types, + ) + .await; + } else if code_sec.tag == Some(TX_SHIELDING_TRANSFER_WASM.to_string()) { + let transfer = token::ShieldingTransfer::try_from_slice( + &tx.data(cmt) + .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, + ) + .map_err(|err| { + Error::from(EncodingError::Conversion(err.to_string())) + })?; + // To facilitate lookups of MASP AssetTypes + let mut asset_types = HashMap::new(); + let builder = tx.sections.iter().find_map(|x| match x { + Section::MaspBuilder(builder) + if builder.target == transfer.shielded_section_hash => + { + for decoded in &builder.asset_types { + match decoded.encode() { + Err(_) => None, + Ok(asset) => { + asset_types.insert(asset, decoded.clone()); + Some(builder) + } + }?; + } + Some(builder) + } + _ => None, + }); + + tv.name = "ShieldingTransfer_0".to_string(); + + tv.output.push("Type : ShieldingTransfer".to_string()); + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output, + TokenTransfer::Shielding(&transfer), + builder, + &asset_types, + ) + .await; + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output_expert, + TokenTransfer::Shielding(&transfer), + builder, + &asset_types, + ) + .await; + } else if code_sec.tag == Some(TX_UNSHIELDING_TRANSFER_WASM.to_string()) + { + let transfer = token::UnshieldingTransfer::try_from_slice( + &tx.data(cmt) + .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, + ) + .map_err(|err| { + Error::from(EncodingError::Conversion(err.to_string())) + })?; + // To facilitate lookups of MASP AssetTypes + let mut asset_types = HashMap::new(); + let builder = tx.sections.iter().find_map(|x| match x { + Section::MaspBuilder(builder) + if builder.target == transfer.shielded_section_hash => + { + for decoded in &builder.asset_types { + match decoded.encode() { + Err(_) => None, + Ok(asset) => { + asset_types.insert(asset, decoded.clone()); + Some(builder) + } + }?; + } + Some(builder) + } + _ => None, + }); + + tv.name = "UnshieldingTransfer_0".to_string(); - tv.output.push("Type : Transfer".to_string()); - make_ledger_masp_endpoints( + tv.output.push("Type : UnshieldingTransfer".to_string()); + make_ledger_token_transfer_endpoints( &tokens, &mut tv.output, - &transfer, + TokenTransfer::Unshielding(&transfer), builder, &asset_types, ) .await; - make_ledger_masp_endpoints( + make_ledger_token_transfer_endpoints( &tokens, &mut tv.output_expert, - &transfer, + TokenTransfer::Unshielding(&transfer), builder, &asset_types, ) diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index 5dc90cec70..fe965dde3d 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -35,14 +35,13 @@ use namada_core::ibc::core::channel::types::timeout::TimeoutHeight; use namada_core::ibc::core::client::types::Height as IbcHeight; use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::ibc::primitives::Timestamp as IbcTimestamp; -use namada_core::ibc::{is_nft_trace, MsgNftTransfer, MsgTransfer}; use namada_core::key::{self, *}; use namada_core::masp::{ AssetData, PaymentAddress, TransferSource, TransferTarget, }; +use namada_core::storage; use namada_core::storage::Epoch; use namada_core::time::DateTimeUtc; -use namada_core::{storage, token}; use namada_governance::cli::onchain::{ DefaultProposal, OnChainProposal, PgfFundingProposal, PgfStewardProposal, }; @@ -52,10 +51,12 @@ use namada_governance::storage::proposal::{ }; use namada_governance::storage::vote::ProposalVote; use namada_ibc::storage::{channel_key, ibc_token}; +use namada_ibc::{is_nft_trace, MsgNftTransfer, MsgTransfer}; use namada_proof_of_stake::parameters::{ PosParams, MAX_VALIDATOR_METADATA_LEN, }; use namada_proof_of_stake::types::{CommissionPair, ValidatorState}; +use namada_token as token; use namada_token::storage_key::balance_key; use namada_token::DenominatedAmount; use namada_tx::data::pgf::UpdateStewardCommission; @@ -101,8 +102,14 @@ pub const TX_VOTE_PROPOSAL: &str = "tx_vote_proposal.wasm"; pub const TX_REVEAL_PK: &str = "tx_reveal_pk.wasm"; /// Update validity predicate WASM path pub const TX_UPDATE_ACCOUNT_WASM: &str = "tx_update_account.wasm"; -/// Transfer transaction WASM path -pub const TX_TRANSFER_WASM: &str = "tx_transfer.wasm"; +/// Transparent transfer transaction WASM path +pub const TX_TRANSPARENT_TRANSFER_WASM: &str = "tx_transparent_transfer.wasm"; +/// Shielded transfer transaction WASM path +pub const TX_SHIELDED_TRANSFER_WASM: &str = "tx_shielded_transfer.wasm"; +/// Shielding transfer transaction WASM path +pub const TX_SHIELDING_TRANSFER_WASM: &str = "tx_shielding_transfer.wasm"; +/// Unshielding transfer transaction WASM path +pub const TX_UNSHIELDING_TRANSFER_WASM: &str = "tx_unshielding_transfer.wasm"; /// IBC transaction WASM path pub const TX_IBC_WASM: &str = "tx_ibc.wasm"; /// User validity predicate WASM path @@ -2560,14 +2567,13 @@ pub async fn build_ibc_transfer( let transfer = shielded_parts.map(|(shielded_transfer, asset_types)| { let masp_tx_hash = tx.add_masp_tx_section(shielded_transfer.masp_tx.clone()).1; - let transfer = token::Transfer { - source: source.clone(), + let transfer = token::ShieldingTransfer { // The token will be escrowed to IBC address - target: Address::Internal(InternalAddress::Ibc), + source: source.clone(), token: args.token.clone(), amount: validated_amount, // Link the Transfer to the MASP Transaction by hash code - shielded: Some(masp_tx_hash), + shielded_section_hash: masp_tx_hash, }; tx.add_masp_builder(MaspBuilder { asset_types, @@ -2820,62 +2826,54 @@ pub fn build_batch( Ok((batched_tx, signing_data)) } -/// Submit an ordinary transfer -pub async fn build_transfer( +/// Build a transparent transfer +pub async fn build_transparent_transfer( context: &N, - args: &mut args::TxTransfer, -) -> Result<(Tx, SigningTxData, Option)> { - let default_signer = Some(args.source.effective_address()); + args: &mut args::TxTransparentTransfer, +) -> Result<(Tx, SigningTxData)> { + let source = &args.source; + let target = &args.target; + + let default_signer = Some(source.clone()); let signing_data = signing::aux_signing_data( context, &args.tx, - Some(args.source.effective_address()), + Some(source.clone()), default_signer, ) .await?; + // Transparent fee payment let (fee_amount, updated_balance) = - if let TransferSource::ExtendedSpendingKey(_) = args.source { - // MASP fee payment - (validate_fee(context, &args.tx).await?, None) - } else { - // Transparent fee payment - validate_transparent_fee(context, &args.tx, &signing_data.fee_payer) - .await - .map(|(fee_amount, updated_balance)| { - (fee_amount, Some(updated_balance)) - })? - }; - - // TODO(namada#2596): need multiple source/targets here for masp fee payment - // targets or leave the fees on the MASP balance - let source = args.source.effective_address(); - let target = args.target.effective_address(); + validate_transparent_fee(context, &args.tx, &signing_data.fee_payer) + .await + .map(|(fee_amount, updated_balance)| { + (fee_amount, Some(updated_balance)) + })?; // Check that the source address exists on chain source_exists_or_err(source.clone(), args.tx.force, context).await?; // Check that the target address exists on chain target_exists_or_err(target.clone(), args.tx.force, context).await?; - // validate the amount given + // Validate the amount given let validated_amount = validate_amount(context, args.amount, &args.token, args.tx.force) .await?; - // If source is transparent check the balance (MASP balance is checked when - // constructing the shielded part) + // Check the balance of the source if let Some(updated_balance) = updated_balance { - let check_balance = if updated_balance.source == source + let check_balance = if &updated_balance.source == source && updated_balance.token == args.token { CheckBalance::Balance(updated_balance.post_balance) } else { - CheckBalance::Query(balance_key(&args.token, &source)) + CheckBalance::Query(balance_key(&args.token, source)) }; check_balance_too_low_err( &args.token, - &source, + source, validated_amount.amount(), check_balance, args.tx.force, @@ -2884,60 +2882,272 @@ pub async fn build_transfer( .await?; } - let masp_addr = MASP; + // Construct the corresponding transparent Transfer object + let transfer = token::TransparentTransfer { + source: source.clone(), + target: target.clone(), + token: args.token.clone(), + amount: validated_amount, + }; - // If the transaction is shielded, redact the amount and token - // types by setting the transparent value to 0 and token type to a constant. - // This has no side-effect because transaction is to self. - let (transparent_amount, transparent_token) = - if source == masp_addr && target == masp_addr { - // TODO(namada#1677): Refactor me, we shouldn't rely on any specific - // token here. - (token::Amount::zero().into(), context.native_token()) - } else { - (validated_amount, args.token.clone()) - }; + let tx = build_pow_flag( + context, + &args.tx, + args.tx_code_path.clone(), + transfer, + do_nothing, + fee_amount, + &signing_data.fee_payer, + ) + .await?; + Ok((tx, signing_data)) +} + +/// Build a shielded transfer +pub async fn build_shielded_transfer( + context: &N, + args: &mut args::TxShieldedTransfer, +) -> Result<(Tx, SigningTxData, Epoch)> { + let default_signer = Some(MASP); + let signing_data = signing::aux_signing_data( + context, + &args.tx, + Some(MASP), + default_signer, + ) + .await?; + + // Shielded fee payment + let fee_amount = validate_fee(context, &args.tx).await?; + + // Validate the amount given + let validated_amount = + validate_amount(context, args.amount, &args.token, args.tx.force) + .await?; // TODO(namada#2597): this function should also take another arg as the fees // token and amount let shielded_parts = construct_shielded_parts( context, - &args.source, - &args.target, + &TransferSource::ExtendedSpendingKey(args.source), + &TransferTarget::PaymentAddress(args.target), &args.token, validated_amount, !(args.tx.dry_run || args.tx.dry_run_wrapper), ) - .await?; - let shielded_tx_epoch = shielded_parts.as_ref().map(|trans| trans.0.epoch); + .await? + .expect("Shielded transfer must have shielded parts"); + let shielded_tx_epoch = shielded_parts.0.epoch; + + let add_shielded_parts = + |tx: &mut Tx, data: &mut token::ShieldedTransfer| { + // Add the MASP Transaction and its Builder to facilitate validation + let ( + ShieldedTransfer { + builder, + masp_tx, + metadata, + epoch: _, + }, + asset_types, + ) = shielded_parts; + // Add a MASP Transaction section to the Tx and get the tx hash + let section_hash = tx.add_masp_tx_section(masp_tx).1; - // Construct the corresponding transparent Transfer object - let transfer = token::Transfer { - source: source.clone(), - target: target.clone(), - token: transparent_token.clone(), - amount: transparent_amount, - // Link the Transfer to the MASP Transaction by hash code - shielded: None, + tx.add_masp_builder(MaspBuilder { + asset_types, + // Store how the Info objects map to Descriptors/Outputs + metadata, + // Store the data that was used to construct the Transaction + builder, + // Link the Builder to the Transaction by hash code + target: section_hash, + }); + + data.section_hash = section_hash; + tracing::debug!("Transfer data {data:?}"); + Ok(()) + }; + + // Construct the tx data with a placeholder shielded section hash + let data = token::ShieldedTransfer { + section_hash: Hash::zero(), }; + let tx = build_pow_flag( + context, + &args.tx, + args.tx_code_path.clone(), + data, + add_shielded_parts, + fee_amount, + &signing_data.fee_payer, + ) + .await?; + Ok((tx, signing_data, shielded_tx_epoch)) +} - let add_shielded = |tx: &mut Tx, transfer: &mut token::Transfer| { - // Add the MASP Transaction and its Builder to facilitate validation - if let Some(( - ShieldedTransfer { - builder, - masp_tx, - metadata, - epoch: _, - }, - asset_types, - )) = shielded_parts +/// Build a shielding transfer +pub async fn build_shielding_transfer( + context: &N, + args: &mut args::TxShieldingTransfer, +) -> Result<(Tx, SigningTxData, Epoch)> { + let source = &args.source; + let default_signer = Some(source.clone()); + let signing_data = signing::aux_signing_data( + context, + &args.tx, + Some(source.clone()), + default_signer, + ) + .await?; + + // Transparent fee payment + let (fee_amount, updated_balance) = + validate_transparent_fee(context, &args.tx, &signing_data.fee_payer) + .await + .map(|(fee_amount, updated_balance)| { + (fee_amount, Some(updated_balance)) + })?; + + // Validate the amount given + let validated_amount = + validate_amount(context, args.amount, &args.token, args.tx.force) + .await?; + + // Check the balance of the source + if let Some(updated_balance) = updated_balance { + let check_balance = if &updated_balance.source == source + && updated_balance.token == args.token { + CheckBalance::Balance(updated_balance.post_balance) + } else { + CheckBalance::Query(balance_key(&args.token, source)) + }; + + check_balance_too_low_err( + &args.token, + source, + validated_amount.amount(), + check_balance, + args.tx.force, + context, + ) + .await?; + } + + let shielded_parts = construct_shielded_parts( + context, + &TransferSource::Address(source.clone()), + &TransferTarget::PaymentAddress(args.target), + &args.token, + validated_amount, + !(args.tx.dry_run || args.tx.dry_run_wrapper), + ) + .await? + .expect("Shielding transfer must have shielded parts"); + let shielded_tx_epoch = shielded_parts.0.epoch; + + let add_shielded_parts = + |tx: &mut Tx, data: &mut token::ShieldingTransfer| { + // Add the MASP Transaction and its Builder to facilitate validation + let ( + ShieldedTransfer { + builder, + masp_tx, + metadata, + epoch: _, + }, + asset_types, + ) = shielded_parts; // Add a MASP Transaction section to the Tx and get the tx hash - let masp_tx_hash = tx.add_masp_tx_section(masp_tx).1; - transfer.shielded = Some(masp_tx_hash); + let shielded_section_hash = tx.add_masp_tx_section(masp_tx).1; + + tx.add_masp_builder(MaspBuilder { + asset_types, + // Store how the Info objects map to Descriptors/Outputs + metadata, + // Store the data that was used to construct the Transaction + builder, + // Link the Builder to the Transaction by hash code + target: shielded_section_hash, + }); - tracing::debug!("Transfer data {:?}", transfer); + data.shielded_section_hash = shielded_section_hash; + tracing::debug!("Transfer data {data:?}"); + Ok(()) + }; + + // Construct the tx data with a placeholder shielded section hash + let data = token::ShieldingTransfer { + source: source.clone(), + token: args.token.clone(), + amount: validated_amount, + shielded_section_hash: Hash::zero(), + }; + + let tx = build_pow_flag( + context, + &args.tx, + args.tx_code_path.clone(), + data, + add_shielded_parts, + fee_amount, + &signing_data.fee_payer, + ) + .await?; + Ok((tx, signing_data, shielded_tx_epoch)) +} + +/// Build an unshielding transfer +pub async fn build_unshielding_transfer( + context: &N, + args: &mut args::TxUnshieldingTransfer, +) -> Result<(Tx, SigningTxData, Epoch)> { + let default_signer = Some(MASP); + let signing_data = signing::aux_signing_data( + context, + &args.tx, + Some(MASP), + default_signer, + ) + .await?; + + // Shielded fee payment + let fee_amount = validate_fee(context, &args.tx).await?; + + // Validate the amount given + let validated_amount = + validate_amount(context, args.amount, &args.token, args.tx.force) + .await?; + + // TODO(namada#2597): this function should also take another arg as the fees + // token and amount + let shielded_parts = construct_shielded_parts( + context, + &TransferSource::ExtendedSpendingKey(args.source), + &TransferTarget::Address(args.target.clone()), + &args.token, + validated_amount, + !(args.tx.dry_run || args.tx.dry_run_wrapper), + ) + .await? + .expect("Shielding transfer must have shielded parts"); + let shielded_tx_epoch = shielded_parts.0.epoch; + + let add_shielded_parts = + |tx: &mut Tx, data: &mut token::UnshieldingTransfer| { + // Add the MASP Transaction and its Builder to facilitate validation + let ( + ShieldedTransfer { + builder, + masp_tx, + metadata, + epoch: _, + }, + asset_types, + ) = shielded_parts; + // Add a MASP Transaction section to the Tx and get the tx hash + let shielded_section_hash = tx.add_masp_tx_section(masp_tx).1; tx.add_masp_builder(MaspBuilder { asset_types, @@ -2946,17 +3156,27 @@ pub async fn build_transfer( // Store the data that was used to construct the Transaction builder, // Link the Builder to the Transaction by hash code - target: masp_tx_hash, + target: shielded_section_hash, }); + + data.shielded_section_hash = shielded_section_hash; + tracing::debug!("Transfer data {data:?}"); + Ok(()) }; - Ok(()) + + // Construct the tx data with a placeholder shielded section hash + let data = token::UnshieldingTransfer { + target: args.target.clone(), + token: args.token.clone(), + amount: validated_amount, + shielded_section_hash: Hash::zero(), }; let tx = build_pow_flag( context, &args.tx, args.tx_code_path.clone(), - transfer, - add_shielded, + data, + add_shielded_parts, fee_amount, &signing_data.fee_payer, ) @@ -2993,7 +3213,7 @@ async fn construct_shielded_parts( Err(Build(builder::Error::InsufficientFunds(_))) => { return Err(TxSubmitError::NegativeBalanceAfterTransfer( Box::new(source.effective_address()), - amount.amount().to_string_native(), + amount.to_string(), Box::new(token.clone()), ) .into()); @@ -3265,10 +3485,10 @@ pub async fn build_custom( } /// Generate IBC shielded transfer -pub async fn gen_ibc_shielded_transfer( +pub async fn gen_ibc_shielding_transfer( context: &N, args: args::GenIbcShieldedTransfer, -) -> Result> { +) -> Result> { let source = Address::Internal(InternalAddress::Ibc); let (src_port_id, src_channel_id) = get_ibc_src_port_channel(context, &args.port_id, &args.channel_id) @@ -3323,12 +3543,11 @@ pub async fn gen_ibc_shielded_transfer( if let Some(shielded_transfer) = shielded_transfer { let masp_tx_hash = Section::MaspTx(shielded_transfer.masp_tx.clone()).get_hash(); - let transfer = token::Transfer { + let transfer = token::ShieldingTransfer { source: source.clone(), - target: MASP, token: token.clone(), amount: validated_amount, - shielded: Some(masp_tx_hash), + shielded_section_hash: masp_tx_hash, }; Ok(Some((transfer, shielded_transfer.masp_tx))) } else { diff --git a/crates/sdk/src/wallet/mod.rs b/crates/sdk/src/wallet/mod.rs index 01db64feb8..a664c0fbe4 100644 --- a/crates/sdk/src/wallet/mod.rs +++ b/crates/sdk/src/wallet/mod.rs @@ -16,11 +16,11 @@ use bip39::{Language, Mnemonic, MnemonicType, Seed}; use borsh::{BorshDeserialize, BorshSerialize}; use namada_core::address::Address; use namada_core::collections::{HashMap, HashSet}; -use namada_core::ibc::is_ibc_denom; use namada_core::key::*; use namada_core::masp::{ ExtendedSpendingKey, ExtendedViewingKey, PaymentAddress, }; +use namada_ibc::is_ibc_denom; pub use pre_genesis::gen_key_to_store; use rand::CryptoRng; use rand_core::RngCore; diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index 02236e6f0b..f7d8678876 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -151,7 +151,15 @@ fn run_ledger_ibc() -> Result<()> { // Transfer 50000 received over IBC on Chain B let token = format!("{port_id_b}/{channel_id_b}/nam"); - transfer_on_chain(&test_b, BERTHA, ALBERT, token, 50000, BERTHA_KEY)?; + transfer_on_chain( + &test_b, + "transparent-transfer", + BERTHA, + ALBERT, + token, + 50000, + BERTHA_KEY, + )?; check_balances_after_non_ibc(&port_id_b, &channel_id_b, &test_b)?; // Transfer 50000 back from the origin-specific account on Chain B to Chain @@ -234,7 +242,15 @@ fn run_ledger_ibc_with_hermes() -> Result<()> { // Transfer 50000 received over IBC on Chain B let token = format!("{port_id_b}/{channel_id_b}/nam"); - transfer_on_chain(&test_b, BERTHA, ALBERT, token, 50000, BERTHA_KEY)?; + transfer_on_chain( + &test_b, + "transparent-transfer", + BERTHA, + ALBERT, + token, + 50000, + BERTHA_KEY, + )?; check_balances_after_non_ibc(&port_id_b, &channel_id_b, &test_b)?; // Transfer 50000 back from the origin-specific account on Chain B to Chain @@ -263,6 +279,7 @@ fn run_ledger_ibc_with_hermes() -> Result<()> { // Send a token to the shielded address on Chain A transfer_on_chain( &test_a, + "shield", ALBERT, AA_PAYMENT_ADDRESS, BTC, @@ -466,6 +483,7 @@ fn ibc_namada_gaia() -> Result<()> { // Shielded transfer on Namada transfer_on_chain( &test, + "transfer", A_SPENDING_KEY, AB_PAYMENT_ADDRESS, &ibc_denom, @@ -536,6 +554,7 @@ fn pgf_over_ibc_with_hermes() -> Result<()> { // Transfer to PGF account transfer_on_chain( &test_a, + "transparent-transfer", ALBERT, PGF_ADDRESS.to_string(), NAM, @@ -1656,6 +1675,7 @@ fn try_invalid_transfers( fn transfer_on_chain( test: &Test, + kind: impl AsRef, sender: impl AsRef, receiver: impl AsRef, token: impl AsRef, @@ -1665,7 +1685,7 @@ fn transfer_on_chain( std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); let rpc = get_actor_rpc(test, Who::Validator(0)); let tx_args = [ - "transfer", + kind.as_ref(), "--source", sender.as_ref(), "--target", diff --git a/crates/tests/src/e2e/ledger_tests.rs b/crates/tests/src/e2e/ledger_tests.rs index e0a69364e9..792d700029 100644 --- a/crates/tests/src/e2e/ledger_tests.rs +++ b/crates/tests/src/e2e/ledger_tests.rs @@ -168,7 +168,7 @@ fn test_node_connectivity_and_consensus() -> Result<()> { // 3. Submit a valid token transfer tx let tx_args = [ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -852,7 +852,7 @@ fn pos_init_validator() -> Result<()> { // 3. Submit a delegation to the new validator First, transfer some tokens // to the validator's key for fees: let tx_args = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -892,7 +892,7 @@ fn pos_init_validator() -> Result<()> { // 4. Transfer some NAM to the new validator let validator_stake_str = &validator_stake.to_string_native(); let tx_args = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -994,7 +994,7 @@ fn ledger_many_txs_in_a_block() -> Result<()> { // A token transfer tx args let tx_args = Arc::new(vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -1223,7 +1223,7 @@ fn double_signing_gets_slashed() -> Result<()> { // 5. Submit a valid token transfer tx to validator 0 let validator_one_rpc = get_actor_rpc(&test, Who::Validator(0)); let tx_args = [ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -2264,7 +2264,7 @@ fn rollback() -> Result<()> { // send a few transactions let txs_args = vec![vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", diff --git a/crates/tests/src/integration/ledger_tests.rs b/crates/tests/src/integration/ledger_tests.rs index 23e8acf5a5..d23eb9491d 100644 --- a/crates/tests/src/integration/ledger_tests.rs +++ b/crates/tests/src/integration/ledger_tests.rs @@ -19,7 +19,7 @@ use namada_node::shell::testing::node::NodeResults; use namada_node::shell::testing::utils::{Bin, CapturedOutput}; use namada_sdk::migrations; use namada_sdk::queries::RPC; -use namada_sdk::tx::{TX_TRANSFER_WASM, VP_USER_WASM}; +use namada_sdk::tx::{TX_TRANSPARENT_TRANSFER_WASM, VP_USER_WASM}; use namada_test_utils::TestWasms; use test_log::test; @@ -59,7 +59,7 @@ fn ledger_txs_and_queries() -> Result<()> { let validator_one_rpc = "http://127.0.0.1:26567"; let (node, _services) = setup::setup()?; - let transfer = token::Transfer { + let transfer = token::TransparentTransfer { source: defaults::bertha_address(), target: defaults::albert_address(), token: node.native_token(), @@ -67,7 +67,6 @@ fn ledger_txs_and_queries() -> Result<()> { token::Amount::native_whole(10), token::NATIVE_MAX_DECIMAL_PLACES.into(), ), - shielded: None, } .serialize_to_vec(); let tx_data_path = node.test_dir.path().join("tx.data"); @@ -80,7 +79,7 @@ fn ledger_txs_and_queries() -> Result<()> { let txs_args = vec![ // 2. Submit a token transfer tx (from an established account) vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -96,7 +95,7 @@ fn ledger_txs_and_queries() -> Result<()> { ], // Submit a token transfer tx (from an ed25519 implicit account) vec![ - "transfer", + "transparent-transfer", "--source", DAEWON, "--target", @@ -112,7 +111,7 @@ fn ledger_txs_and_queries() -> Result<()> { ], // Submit a token transfer tx (from a secp256k1 implicit account) vec![ - "transfer", + "transparent-transfer", "--source", ESTER, "--target", @@ -141,7 +140,7 @@ fn ledger_txs_and_queries() -> Result<()> { vec![ "tx", "--code-path", - TX_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, "--data-path", &tx_data_path, "--owner", @@ -358,7 +357,7 @@ fn invalid_transactions() -> Result<()> { // 2. Submit an invalid transaction (trying to transfer tokens should fail // in the user's VP due to the wrong signer) let tx_args = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -387,7 +386,7 @@ fn invalid_transactions() -> Result<()> { let daewon_lower = DAEWON.to_lowercase(); let tx_args = vec![ - "transfer", + "transparent-transfer", "--source", DAEWON, "--signing-keys", @@ -976,7 +975,7 @@ fn proposal_submission() -> Result<()> { // vp and verify that the transaction succeeds, i.e. the non allowlisted // vp can still run let transfer = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -1387,7 +1386,7 @@ fn implicit_account_reveal_pk() -> Result<()> { // A token transfer tx Box::new(|source| { [ - "transfer", + "transparent-transfer", "--source", source, "--target", @@ -1444,7 +1443,7 @@ fn implicit_account_reveal_pk() -> Result<()> { let tx_args = tx_args(&key_alias); // 2b. Send some funds to the implicit account. let credit_args = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", diff --git a/crates/tests/src/integration/masp.rs b/crates/tests/src/integration/masp.rs index 4912e3624a..ab534b0114 100644 --- a/crates/tests/src/integration/masp.rs +++ b/crates/tests/src/integration/masp.rs @@ -43,7 +43,7 @@ fn masp_incentives() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -259,7 +259,7 @@ fn masp_incentives() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -397,7 +397,7 @@ fn masp_incentives() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", B_SPENDING_KEY, "--target", @@ -507,7 +507,7 @@ fn masp_incentives() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", A_SPENDING_KEY, "--target", @@ -677,7 +677,7 @@ fn masp_incentives() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", B_SPENDING_KEY, "--target", @@ -708,7 +708,7 @@ fn masp_incentives() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", A_SPENDING_KEY, "--target", @@ -824,7 +824,7 @@ fn spend_unconverted_asset_type() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -845,7 +845,7 @@ fn spend_unconverted_asset_type() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -993,7 +993,7 @@ fn masp_txs_and_queries() -> Result<()> { // 1. Attempt to spend 15 BTC at SK(A) to Bertha ( vec![ - "transfer", + "unshield", "--source", A_SPENDING_KEY, "--target", @@ -1012,7 +1012,7 @@ fn masp_txs_and_queries() -> Result<()> { // 2. Send 20 BTC from Albert to PA(A) ( vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -1163,7 +1163,7 @@ fn masp_txs_and_queries() -> Result<()> { // 11. Send 20 BTC from SK(B) to Bertha ( vec![ - "transfer", + "unshield", "--source", B_SPENDING_KEY, "--target", @@ -1184,7 +1184,10 @@ fn masp_txs_and_queries() -> Result<()> { for (tx_args, tx_result) in &txs_args { node.assert_success(); // there is no need to dry run balance queries - let dry_run_args = if tx_args[0] == "transfer" { + let dry_run_args = if tx_args[0] == "transfer" + || tx_args[0] == "shield" + || tx_args[0] == "unshield" + { // We ensure transfers don't cross epoch boundaries. node.next_epoch(); vec![true, false] @@ -1198,7 +1201,7 @@ fn masp_txs_and_queries() -> Result<()> { Bin::Client, vec!["shielded-sync", "--node", validator_one_rpc], )?; - let tx_args = if dry_run && tx_args[0] == "transfer" { + let tx_args = if dry_run { [tx_args.clone(), vec!["--dry-run"]].concat() } else { tx_args.clone() @@ -1314,7 +1317,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT_KEY, "--target", @@ -1333,7 +1336,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT_KEY, "--target", @@ -1352,7 +1355,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT_KEY, "--target", @@ -1548,7 +1551,7 @@ fn cross_epoch_unshield() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -1583,7 +1586,7 @@ fn cross_epoch_unshield() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", A_SPENDING_KEY, "--target", @@ -1689,7 +1692,7 @@ fn dynamic_assets() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -1823,7 +1826,7 @@ fn dynamic_assets() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", diff --git a/crates/token/Cargo.toml b/crates/token/Cargo.toml index b06ab6086d..69c663680b 100644 --- a/crates/token/Cargo.toml +++ b/crates/token/Cargo.toml @@ -15,14 +15,21 @@ version.workspace = true [features] default = [] multicore = ["namada_shielded_token/multicore"] -testing = ["namada_core/testing"] +testing = ["namada_core/testing", "proptest"] [dependencies] namada_core = { path = "../core" } namada_events = { path = "../events", default-features = false } +namada_macros = { path = "../macros" } namada_shielded_token = { path = "../shielded_token" } namada_storage = { path = "../storage" } namada_trans_token = { path = "../trans_token" } +borsh.workspace = true +proptest = { workspace = true, optional = true } +serde.workspace = true + [dev-dependencies] namada_core = { path = "../core", features = ["testing"] } + +proptest.workspace = true \ No newline at end of file diff --git a/crates/token/src/lib.rs b/crates/token/src/lib.rs index 2ce15898a5..fb3b58f357 100644 --- a/crates/token/src/lib.rs +++ b/crates/token/src/lib.rs @@ -18,8 +18,12 @@ clippy::print_stderr )] +use namada_core::borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use namada_core::hash::Hash; +use namada_macros::BorshDeserializer; pub use namada_shielded_token::*; pub use namada_trans_token::*; +use serde::{Deserialize, Serialize}; /// Token storage keys pub mod storage_key { @@ -28,8 +32,6 @@ pub mod storage_key { } use namada_core::address::Address; -#[cfg(any(test, feature = "testing"))] -pub use namada_core::token::testing; use namada_events::EmitEvents; use namada_storage::{Result, StorageRead, StorageWrite}; @@ -64,3 +66,134 @@ where } Ok(()) } + +/// Arguments for a transparent token transfer +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Hash, + Eq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct TransparentTransfer { + /// Source address will spend the tokens + pub source: Address, + /// Target address will receive the tokens + pub target: Address, + /// Token's address + pub token: Address, + /// The amount of tokens + pub amount: DenominatedAmount, +} + +/// Arguments for a shielded token transfer +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Hash, + Eq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct ShieldedTransfer { + /// Hash of tx section that contains the MASP transaction + pub section_hash: Hash, +} + +/// Arguments for a shielding transfer (from a transparent token to a shielded +/// token) +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Hash, + Eq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct ShieldingTransfer { + /// Source address will spend the tokens + pub source: Address, + /// Token's address + pub token: Address, + /// The amount of tokens + pub amount: DenominatedAmount, + /// Hash of tx section that contains the MASP transaction + pub shielded_section_hash: Hash, +} + +/// Arguments for an unshielding transfer (from a shielded token to a +/// transparent token) +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Hash, + Eq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct UnshieldingTransfer { + /// Target address will receive the tokens + pub target: Address, + /// Token's address + pub token: Address, + /// The amount of tokens + pub amount: DenominatedAmount, + /// Hash of tx section that contains the MASP transaction + pub shielded_section_hash: Hash, +} + +#[cfg(any(test, feature = "testing"))] +/// Testing helpers and strategies for tokens +pub mod testing { + use namada_core::address::testing::{ + arb_established_address, arb_non_internal_address, + }; + use namada_core::address::Address; + pub use namada_core::token::*; + pub use namada_trans_token::testing::*; + use proptest::prelude::*; + + use super::TransparentTransfer; + + prop_compose! { + /// Generate a transparent transfer + pub fn arb_transparent_transfer()( + source in arb_non_internal_address(), + target in arb_non_internal_address(), + token in arb_established_address().prop_map(Address::Established), + amount in arb_denominated_amount(), + ) -> TransparentTransfer { + TransparentTransfer { + source, + target, + token, + amount, + } + } + } +} diff --git a/crates/tx_prelude/src/lib.rs b/crates/tx_prelude/src/lib.rs index eb0f6a3be9..3b737c8157 100644 --- a/crates/tx_prelude/src/lib.rs +++ b/crates/tx_prelude/src/lib.rs @@ -37,7 +37,7 @@ use namada_core::storage::TxIndex; pub use namada_core::storage::{ self, BlockHash, BlockHeight, Epoch, Header, BLOCK_HASH_LENGTH, }; -pub use namada_core::{encode, eth_bridge_pool, *}; +pub use namada_core::{address, encode, eth_bridge_pool, *}; use namada_events::{EmitEvents, Event, EventToEmit, EventType}; pub use namada_governance::storage as gov_storage; pub use namada_macros::transaction; diff --git a/crates/tx_prelude/src/token.rs b/crates/tx_prelude/src/token.rs index b30954aa1c..ab9ecaf571 100644 --- a/crates/tx_prelude/src/token.rs +++ b/crates/tx_prelude/src/token.rs @@ -5,13 +5,14 @@ use namada_events::{EmitEvents, EventLevel}; #[cfg(any(test, feature = "testing"))] pub use namada_token::testing; pub use namada_token::{ - storage_key, utils, Amount, DenominatedAmount, Transfer, + storage_key, utils, Amount, DenominatedAmount, ShieldedTransfer, + ShieldingTransfer, TransparentTransfer, UnshieldingTransfer, }; use namada_tx_env::TxEnv; use crate::{Ctx, TxResult}; -/// A token transfer that can be used in a transaction. +/// A transparent token transfer that can be used in a transaction. pub fn transfer( ctx: &mut Ctx, src: &Address, diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 99bb9183e2..21c7a95a9e 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -43,7 +43,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", ] @@ -54,7 +54,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "once_cell", "version_check", ] @@ -83,55 +83,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - [[package]] name = "anyhow" version = "1.0.75" @@ -350,10 +301,10 @@ checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", - "cfg-if", + "cfg-if 1.0.0", "libc", "miniz_oxide", - "object", + "object 0.32.1", "rustc-demangle", ] @@ -533,7 +484,7 @@ dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if", + "cfg-if 1.0.0", "constant_time_eq", ] @@ -710,15 +661,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bytesize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" -dependencies = [ - "serde", -] - [[package]] name = "camino" version = "1.1.6" @@ -769,6 +711,12 @@ dependencies = [ "libc", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -787,7 +735,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", ] @@ -839,46 +787,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "clap" -version = "4.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - [[package]] name = "clru" version = "0.5.0" @@ -936,12 +844,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "colorchoice" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" - [[package]] name = "concat-idents" version = "1.1.5" @@ -952,19 +854,13 @@ dependencies = [ "syn 2.0.52", ] -[[package]] -name = "const-default" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" - [[package]] name = "const-hex" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "hex", "proptest", @@ -1012,7 +908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80128832c58ea9cbd041d2a759ec449224487b2c1e400453d99d244eead87a8e" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.0", "libc", "scopeguard", "windows-sys 0.33.0", @@ -1098,74 +994,56 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.91.1" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2ab4512dfd3a6f4be184403a195f76e81a8a9f9e6c898e19d2dc3ce20e0115" +checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.91.1" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98b022ed2a5913a38839dfbafe6cf135342661293b08049843362df4301261dc" +checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" dependencies = [ - "arrayvec", - "bumpalo", "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", - "cranelift-egraph", "cranelift-entity", - "cranelift-isle", "gimli 0.26.2", "log", - "regalloc2", + "regalloc", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.91.1" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "639307b45434ad112a98f8300c0f0ab085cbefcd767efcdef9ef19d4c0756e74" +checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.91.1" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278e52e29c53fcf32431ef08406c295699a70306d05a0715c5b1bf50e33a9ab7" - -[[package]] -name = "cranelift-egraph" -version = "0.91.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624b54323b06e675293939311943ba82d323bb340468ce1889be5da7932c8d73" -dependencies = [ - "cranelift-entity", - "fxhash", - "hashbrown 0.12.3", - "indexmap 1.9.3", - "log", - "smallvec", -] +checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" [[package]] name = "cranelift-entity" -version = "0.91.1" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a59bcbca89c3f1b70b93ab3cbba5e5e0cbf3e63dadb23c7525cb142e21a9d4c" +checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" [[package]] name = "cranelift-frontend" -version = "0.91.1" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d70abacb8cfef3dc8ff7e8836e9c1d70f7967dfdac824a4cd5e30223415aca6" +checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" dependencies = [ "cranelift-codegen", "log", @@ -1173,19 +1051,13 @@ dependencies = [ "target-lexicon", ] -[[package]] -name = "cranelift-isle" -version = "0.91.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "393bc73c451830ff8dbb3a07f61843d6cb41a084f9996319917c0b291ed785bb" - [[package]] name = "crc32fast" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1194,7 +1066,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-epoch", "crossbeam-utils", ] @@ -1206,21 +1078,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", - "memoffset", + "memoffset 0.9.0", "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -1317,38 +1180,14 @@ dependencies = [ "serde", ] -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core 0.14.4", - "darling_macro 0.14.4", -] - [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core 0.20.3", - "darling_macro 0.20.3", -] - -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.109", + "darling_core", + "darling_macro", ] [[package]] @@ -1364,41 +1203,17 @@ dependencies = [ "syn 2.0.52", ] -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core 0.14.4", - "quote", - "syn 1.0.109", -] - [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core 0.20.3", + "darling_core", "quote", "syn 2.0.52", ] -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.3", - "lock_api", - "once_cell", - "parking_lot_core", -] - [[package]] name = "data-encoding" version = "2.5.0" @@ -1441,37 +1256,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_builder" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" -dependencies = [ - "darling 0.14.4", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_builder_macro" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" -dependencies = [ - "derive_builder_core", - "syn 1.0.109", -] - [[package]] name = "derive_more" version = "0.99.17" @@ -1535,15 +1319,6 @@ dependencies = [ "syn 2.0.52", ] -[[package]] -name = "document-features" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" -dependencies = [ - "litrs", -] - [[package]] name = "dunce" version = "1.0.4" @@ -1593,7 +1368,7 @@ checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" dependencies = [ "byteorder", "dynasm", - "memmap2 0.5.10", + "memmap2", ] [[package]] @@ -1683,7 +1458,7 @@ version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1739,7 +1514,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ - "darling 0.20.3", + "darling", "proc-macro2", "quote", "syn 2.0.52", @@ -2102,7 +1877,7 @@ version = "3.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "rustix", "windows-sys 0.48.0", ] @@ -2124,7 +1899,7 @@ version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "windows-sys 0.52.0", @@ -2343,7 +2118,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", @@ -2352,11 +2127,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -2436,7 +2211,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.2.6", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -2444,10 +2219,13 @@ dependencies = [ ] [[package]] -name = "half" -version = "1.8.3" +name = "hashbrown" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] [[package]] name = "hashbrown" @@ -3309,21 +3087,20 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.4" -source = "git+https://github.com/heliaxdev/indexmap?tag=2.2.4-heliax-1#b5b5b547bd6ab04bbb16e060326a50ddaeb6c909" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ - "borsh 1.4.0", "equivalent", "hashbrown 0.14.3", - "serde", ] [[package]] name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +version = "2.2.4" +source = "git+https://github.com/heliaxdev/indexmap?tag=2.2.4-heliax-1#b5b5b547bd6ab04bbb16e060326a50ddaeb6c909" dependencies = [ + "borsh 1.4.0", "equivalent", "hashbrown 0.14.3", "serde", @@ -3364,7 +3141,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -3382,12 +3159,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - [[package]] name = "itertools" version = "0.11.0" @@ -3455,7 +3226,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "ecdsa", "elliptic-curve", "once_cell", @@ -3511,6 +3282,16 @@ version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + [[package]] name = "libm" version = "0.2.8" @@ -3554,12 +3335,6 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" -[[package]] -name = "litrs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" - [[package]] name = "lock_api" version = "0.4.11" @@ -3576,6 +3351,27 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "loupe" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" +dependencies = [ + "indexmap 1.9.3", + "loupe-derive", + "rustversion", +] + +[[package]] +name = "loupe-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "mach" version = "0.3.2" @@ -3588,7 +3384,7 @@ dependencies = [ [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" +source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" dependencies = [ "borsh 1.4.0", "chacha20", @@ -3601,7 +3397,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" +source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" dependencies = [ "aes", "bip0039", @@ -3633,13 +3429,13 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" +source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" dependencies = [ "bellman", "blake2b_simd", "bls12_381", "directories", - "getrandom 0.2.15", + "getrandom 0.2.11", "group", "itertools 0.11.0", "jubjub", @@ -3682,12 +3478,12 @@ dependencies = [ ] [[package]] -name = "memmap2" -version = "0.6.2" +name = "memoffset" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "libc", + "autocfg", ] [[package]] @@ -3699,6 +3495,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + [[package]] name = "memuse" version = "0.2.1" @@ -3764,16 +3566,25 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.38.1" +version = "0.37.0" dependencies = [ "async-trait", + "bimap", "borsh 1.4.0", "borsh-ext", + "circular-queue", "clru", + "data-encoding", + "derivation-path", + "derivative", + "ethbridge-bridge-contract", "ethers", "eyre", + "futures", "itertools 0.12.1", + "konst", "linkme", + "loupe", "masp_primitives", "masp_proofs", "namada_account", @@ -3783,6 +3594,7 @@ dependencies = [ "namada_gas", "namada_governance", "namada_ibc", + "namada_macros", "namada_migrations", "namada_parameters", "namada_proof_of_stake", @@ -3794,33 +3606,48 @@ dependencies = [ "namada_tx_env", "namada_vote_ext", "namada_vp_env", + "num-traits 0.2.17", + "num256", + "orion", + "owo-colors", "parity-wasm", + "paste", "proptest", "prost", "rand 0.8.5", + "rand_core 0.6.4", "rayon", + "regex", "ripemd", + "serde", "serde_json", "sha2 0.9.9", + "slip10_ed25519", "smooth-operator", "tempfile", "thiserror", "tiny-bip39", + "tiny-hderive", "tokio", + "toml 0.5.11", "tracing", "uint", "wasm-instrument", "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", + "wasmer-engine-dylib", + "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.107.0", "wasmtimer", + "wat", + "zeroize", ] [[package]] name = "namada_account" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "linkme", @@ -3834,7 +3661,7 @@ dependencies = [ [[package]] name = "namada_controller" -version = "0.38.1" +version = "0.37.0" dependencies = [ "namada_core", "smooth-operator", @@ -3843,7 +3670,7 @@ dependencies = [ [[package]] name = "namada_core" -version = "0.38.1" +version = "0.37.0" dependencies = [ "bech32 0.8.1", "borsh 1.4.0", @@ -3890,9 +3717,10 @@ dependencies = [ [[package]] name = "namada_ethereum_bridge" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", + "ethabi", "ethers", "eyre", "itertools 0.12.1", @@ -3910,14 +3738,18 @@ dependencies = [ "namada_trans_token", "namada_tx", "namada_vote_ext", + "rand 0.8.5", "serde", + "serde_json", + "tendermint 0.36.0", + "tendermint-proto 0.36.0", "thiserror", "tracing", ] [[package]] name = "namada_events" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "linkme", @@ -3932,7 +3764,7 @@ dependencies = [ [[package]] name = "namada_gas" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "linkme", @@ -3946,7 +3778,7 @@ dependencies = [ [[package]] name = "namada_governance" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "itertools 0.12.1", @@ -3969,7 +3801,7 @@ dependencies = [ [[package]] name = "namada_ibc" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "ibc", @@ -3980,12 +3812,14 @@ dependencies = [ "masp_primitives", "namada_core", "namada_events", + "namada_gas", "namada_governance", "namada_macros", "namada_parameters", "namada_state", "namada_storage", "namada_token", + "namada_tx", "primitive-types", "proptest", "prost", @@ -3998,7 +3832,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.38.1" +version = "0.37.0" dependencies = [ "data-encoding", "proc-macro2", @@ -4009,7 +3843,7 @@ dependencies = [ [[package]] name = "namada_merkle_tree" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "eyre", @@ -4023,7 +3857,7 @@ dependencies = [ [[package]] name = "namada_migrations" -version = "0.38.1" +version = "0.37.0" dependencies = [ "lazy_static", "linkme", @@ -4032,8 +3866,9 @@ dependencies = [ [[package]] name = "namada_parameters" -version = "0.38.1" +version = "0.37.0" dependencies = [ + "borsh 1.4.0", "namada_core", "namada_macros", "namada_storage", @@ -4042,9 +3877,10 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", + "data-encoding", "konst", "linkme", "namada_account", @@ -4057,6 +3893,7 @@ dependencies = [ "namada_parameters", "namada_storage", "namada_trans_token", + "num-traits 0.2.17", "once_cell", "proptest", "serde", @@ -4067,14 +3904,14 @@ dependencies = [ [[package]] name = "namada_replay_protection" -version = "0.38.1" +version = "0.37.0" dependencies = [ "namada_core", ] [[package]] name = "namada_sdk" -version = "0.38.1" +version = "0.37.0" dependencies = [ "async-trait", "bimap", @@ -4129,6 +3966,7 @@ dependencies = [ "sha2 0.9.9", "slip10_ed25519", "smooth-operator", + "tendermint-config", "tendermint-rpc", "thiserror", "tiny-bip39", @@ -4142,7 +3980,7 @@ dependencies = [ [[package]] name = "namada_shielded_token" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "masp_primitives", @@ -4151,6 +3989,7 @@ dependencies = [ "namada_parameters", "namada_storage", "namada_trans_token", + "namada_tx", "serde", "smooth-operator", "tracing", @@ -4158,9 +3997,10 @@ dependencies = [ [[package]] name = "namada_state" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", + "ics23", "itertools 0.12.1", "linkme", "namada_core", @@ -4175,14 +4015,17 @@ dependencies = [ "namada_tx", "patricia_tree", "proptest", + "sha2 0.9.9", "smooth-operator", + "sparse-merkle-tree", "thiserror", + "tiny-keccak", "tracing", ] [[package]] name = "namada_storage" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "itertools 0.12.1", @@ -4201,7 +4044,7 @@ dependencies = [ [[package]] name = "namada_test_utils" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "namada_core", @@ -4210,45 +4053,57 @@ dependencies = [ [[package]] name = "namada_tests" -version = "0.38.1" +version = "0.37.0" dependencies = [ + "async-trait", + "chrono", "concat-idents", "derivative", + "flate2", "hyper", "ibc-testkit", "ics23", "itertools 0.12.1", + "lazy_static", "namada", "namada_core", "namada_sdk", "namada_test_utils", "namada_tx_prelude", "namada_vp_prelude", + "num-traits 0.2.17", "proptest", "prost", "regex", "serde", "serde_json", "sha2 0.9.9", + "tar", "tempfile", "test-log", "tokio", -] + "tracing", + "tracing-subscriber", +] [[package]] name = "namada_token" -version = "0.38.1" +version = "0.37.0" dependencies = [ + "borsh 1.4.0", "namada_core", "namada_events", + "namada_macros", "namada_shielded_token", "namada_storage", "namada_trans_token", + "proptest", + "serde", ] [[package]] name = "namada_trans_token" -version = "0.38.1" +version = "0.37.0" dependencies = [ "konst", "namada_core", @@ -4258,7 +4113,7 @@ dependencies = [ [[package]] name = "namada_tx" -version = "0.38.1" +version = "0.37.0" dependencies = [ "ark-bls12-381", "bitflags 2.5.0", @@ -4286,7 +4141,7 @@ dependencies = [ [[package]] name = "namada_tx_env" -version = "0.38.1" +version = "0.37.0" dependencies = [ "namada_core", "namada_events", @@ -4295,7 +4150,7 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "masp_primitives", @@ -4312,11 +4167,13 @@ dependencies = [ "namada_tx", "namada_tx_env", "namada_vm_env", + "sha2 0.9.9", + "thiserror", ] [[package]] name = "namada_vm_env" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "masp_primitives", @@ -4325,7 +4182,7 @@ dependencies = [ [[package]] name = "namada_vote_ext" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "linkme", @@ -4338,7 +4195,7 @@ dependencies = [ [[package]] name = "namada_vp_env" -version = "0.38.1" +version = "0.37.0" dependencies = [ "derivative", "masp_primitives", @@ -4348,11 +4205,12 @@ dependencies = [ "namada_storage", "namada_tx", "smooth-operator", + "thiserror", ] [[package]] name = "namada_vp_prelude" -version = "0.38.1" +version = "0.37.0" dependencies = [ "borsh 1.4.0", "namada_account", @@ -4369,6 +4227,7 @@ dependencies = [ "namada_vm_env", "namada_vp_env", "sha2 0.9.9", + "thiserror", ] [[package]] @@ -4529,6 +4388,18 @@ dependencies = [ "syn 2.0.52", ] +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "crc32fast", + "hashbrown 0.11.2", + "indexmap 1.9.3", + "memchr", +] + [[package]] name = "object" version = "0.32.1" @@ -4582,7 +4453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6624905ddd92e460ff0685567539ed1ac985b2dee4c92c7edcd64fce905b00c" dependencies = [ "ct-codecs", - "getrandom 0.2.15", + "getrandom 0.2.11", "subtle", "zeroize", ] @@ -4650,7 +4521,7 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", @@ -4785,7 +4656,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.1.0", ] [[package]] @@ -5131,7 +5002,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", ] [[package]] @@ -5220,20 +5091,19 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "libredox", "thiserror", ] [[package]] -name = "regalloc2" -version = "0.5.1" +name = "regalloc" +version = "0.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" +checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" dependencies = [ - "fxhash", "log", - "slice-group-by", + "rustc-hash", "smallvec", ] @@ -5369,7 +5239,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.15", + "getrandom 0.2.11", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -5394,7 +5264,6 @@ dependencies = [ "bitvec", "bytecheck", "hashbrown 0.12.3", - "indexmap 1.9.3", "ptr_meta", "rend", "rkyv_derive", @@ -5436,18 +5305,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "rlsf" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" -dependencies = [ - "cfg-if", - "const-default", - "libc", - "svgbobdoc", -] - [[package]] name = "rust_decimal" version = "1.35.0" @@ -5577,7 +5434,7 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "derive_more", "parity-scale-codec", "scale-info-derive", @@ -5605,7 +5462,6 @@ dependencies = [ "schemars_derive", "serde", "serde_json", - "url", ] [[package]] @@ -5669,12 +5525,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "self_cell" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" - [[package]] name = "semver" version = "0.11.0" @@ -5716,9 +5566,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.202" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -5741,17 +5591,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde-wasm-bindgen" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - [[package]] name = "serde_bytes" version = "0.11.12" @@ -5761,21 +5600,11 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", @@ -5836,19 +5665,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap 2.2.6", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "serdect" version = "0.2.0" @@ -5866,7 +5682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -5878,7 +5694,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.7", ] @@ -5902,16 +5718,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shared-buffer" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" -dependencies = [ - "bytes", - "memmap2 0.6.2", -] - [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -5964,12 +5770,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "slice-group-by" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" - [[package]] name = "slip10_ed25519" version = "0.1.3" @@ -6029,7 +5829,7 @@ version = "0.3.1-pre" source = "git+https://github.com/heliaxdev/sparse-merkle-tree?rev=bab8cb96872db22cc9a139b2d3dfc4e00521d097#bab8cb96872db22cc9a139b2d3dfc4e00521d097" dependencies = [ "borsh 1.4.0", - "cfg-if", + "cfg-if 1.0.0", "ics23", "itertools 0.12.1", "sha2 0.9.9", @@ -6069,12 +5869,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strum" version = "0.24.1" @@ -6140,19 +5934,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" -[[package]] -name = "svgbobdoc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" -dependencies = [ - "base64 0.13.1", - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-width", -] - [[package]] name = "syn" version = "1.0.109" @@ -6243,7 +6024,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "redox_syscall", "rustix", @@ -6378,7 +6159,7 @@ dependencies = [ "async-trait", "bytes", "flex-error", - "getrandom 0.2.15", + "getrandom 0.2.11", "peg", "pin-project", "rand 0.8.5", @@ -6461,7 +6242,7 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", ] @@ -6622,18 +6403,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.15", -] - [[package]] name = "toml" version = "0.8.2" @@ -6661,9 +6430,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.6", - "serde", - "serde_spanned", + "indexmap 2.1.0", "toml_datetime", "winnow 0.5.25", ] @@ -6674,7 +6441,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -6687,7 +6454,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.1.0", "toml_datetime", "winnow 0.5.25", ] @@ -6770,6 +6537,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -6828,240 +6596,267 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tx_become_validator" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_bond" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", - "rlsf", "test-log", "tracing", "tracing-subscriber", + "wee_alloc", ] [[package]] name = "tx_bridge_pool" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_change_consensus_key" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_change_validator_commission" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", - "rlsf", "test-log", "tracing", "tracing-subscriber", + "wee_alloc", ] [[package]] name = "tx_change_validator_metadata" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_claim_rewards" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_deactivate_validator" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_ibc" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_init_account" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_init_proposal" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_reactivate_validator" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_redelegate" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", - "rlsf", "test-log", "tracing", "tracing-subscriber", + "wee_alloc", ] [[package]] name = "tx_resign_steward" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_reveal_pk" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] -name = "tx_transfer" -version = "0.38.1" +name = "tx_shielded_transfer" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", +] + +[[package]] +name = "tx_shielding_transfer" +version = "0.37.0" +dependencies = [ + "getrandom 0.2.11", + "namada_tx_prelude", + "wee_alloc", +] + +[[package]] +name = "tx_transparent_transfer" +version = "0.37.0" +dependencies = [ + "getrandom 0.2.11", + "namada_tx_prelude", + "wee_alloc", ] [[package]] name = "tx_unbond" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", - "rlsf", "test-log", "tracing", "tracing-subscriber", + "wee_alloc", ] [[package]] name = "tx_unjail_validator" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", +] + +[[package]] +name = "tx_unshielding_transfer" +version = "0.37.0" +dependencies = [ + "getrandom 0.2.11", + "namada_tx_prelude", + "wee_alloc", ] [[package]] name = "tx_update_account" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_update_steward_commission" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_vote_proposal" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada_tx_prelude", - "rlsf", + "wee_alloc", ] [[package]] name = "tx_withdraw" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", - "rlsf", "test-log", "tracing", "tracing-subscriber", + "wee_alloc", ] [[package]] @@ -7172,12 +6967,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "untrusted" version = "0.7.1" @@ -7199,22 +6988,15 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", - "serde", ] -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - [[package]] name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "serde", ] @@ -7232,36 +7014,36 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vp_implicit" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", - "rlsf", "test-log", "tracing", "tracing-subscriber", + "wee_alloc", ] [[package]] name = "vp_user" -version = "0.38.1" +version = "0.37.0" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.11", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", - "rlsf", "test-log", "tracing", "tracing-subscriber", + "wee_alloc", ] [[package]] @@ -7310,7 +7092,7 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -7335,7 +7117,7 @@ version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -7390,38 +7172,46 @@ dependencies = [ [[package]] name = "wasmer" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce4a267a570e121c9375136adefa2c48810273907de9c6817bc19db4d6144bc" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ - "bytes", - "cfg-if", - "derivative", + "cfg-if 1.0.0", "indexmap 1.9.3", "js-sys", + "loupe", "more-asserts", - "rustc-demangle", - "serde", - "serde-wasm-bindgen", - "shared-buffer", "target-lexicon", "thiserror", - "tracing", "wasm-bindgen", + "wasmer-artifact", "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-derive", + "wasmer-engine", + "wasmer-engine-dylib", + "wasmer-engine-universal", "wasmer-types", "wasmer-vm", "wat", "winapi", ] +[[package]] +name = "wasmer-artifact" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +dependencies = [ + "enumset", + "loupe", + "thiserror", + "wasmer-compiler", + "wasmer-types", +] + [[package]] name = "wasmer-cache" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a40804bcc2567f112003182fc5edc29584da5199c4a1f5a8d6a6e4b65feff0" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ "blake3", "hex", @@ -7431,42 +7221,31 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9c23098e86ef1038155684fe50f0c1079a0e2a2e70f115b789df17e6ba98d20" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ - "backtrace", - "bytes", - "cfg-if", - "enum-iterator", "enumset", - "lazy_static", - "leb128", - "memmap2 0.5.10", - "more-asserts", - "region", + "loupe", "rkyv", - "self_cell", - "shared-buffer", + "serde", + "serde_bytes", "smallvec", + "target-lexicon", "thiserror", "wasmer-types", - "wasmer-vm", - "wasmparser 0.121.2", - "winapi", - "xxhash-rust", + "wasmparser 0.83.0", ] [[package]] name = "wasmer-compiler-cranelift" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95287b79973ad5f485215733ef9f0d4bb951a6b7e655585d2bd3d4a4ba1253c9" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", "gimli 0.26.2", + "loupe", "more-asserts", "rayon", "smallvec", @@ -7474,128 +7253,185 @@ dependencies = [ "tracing", "wasmer-compiler", "wasmer-types", + "wasmer-vm", ] [[package]] name = "wasmer-compiler-singlepass" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d78d59be3ce78ad859e176b88f0d5bec0120ece0684922d7c5da1289e251b1" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ "byteorder", "dynasm", "dynasmrt", - "enumset", "gimli 0.26.2", "lazy_static", + "loupe", "more-asserts", "rayon", "smallvec", "wasmer-compiler", "wasmer-types", + "wasmer-vm", ] [[package]] -name = "wasmer-config" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a0f70c177b1c5062cfe0f5308c3317751796fef9403c22a0cd7b4cacd4ccd8" +name = "wasmer-derive" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ - "anyhow", - "bytesize", - "derive_builder", - "hex", - "indexmap 2.2.6", - "schemars", - "semver 1.0.20", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wasmer-engine" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +dependencies = [ + "backtrace", + "enumset", + "lazy_static", + "loupe", + "memmap2", + "more-asserts", + "rustc-demangle", "serde", - "serde_cbor", - "serde_json", - "serde_yaml", + "serde_bytes", + "target-lexicon", "thiserror", - "toml 0.8.2", - "url", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", ] [[package]] -name = "wasmer-derive" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48f36aeeecb655f15fdd358bdf6e4cec27df181468fa4226084157e8462bd5e" +name = "wasmer-engine-dylib" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", + "cfg-if 1.0.0", + "enum-iterator", + "enumset", + "leb128", + "libloading", + "loupe", + "object 0.28.4", + "rkyv", + "serde", + "tempfile", + "tracing", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-engine", + "wasmer-object", + "wasmer-types", + "wasmer-vm", + "which", ] [[package]] -name = "wasmer-types" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83cb97b6b20084757a2a8d548dc0d4179c3fe9e2d711740423a1e6aa3f8b9091" +name = "wasmer-engine-universal" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +dependencies = [ + "cfg-if 1.0.0", + "enumset", + "leb128", + "loupe", + "region", + "rkyv", + "wasmer-compiler", + "wasmer-engine", + "wasmer-engine-universal-artifact", + "wasmer-types", + "wasmer-vm", + "winapi", +] + +[[package]] +name = "wasmer-engine-universal-artifact" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ - "bytecheck", "enum-iterator", "enumset", - "getrandom 0.2.15", - "hex", + "loupe", + "rkyv", + "thiserror", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-object" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +dependencies = [ + "object 0.28.4", + "thiserror", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-types" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +dependencies = [ + "backtrace", + "enum-iterator", "indexmap 1.9.3", - "more-asserts", + "loupe", "rkyv", - "sha2 0.10.8", - "target-lexicon", + "serde", "thiserror", - "webc", - "xxhash-rust", ] [[package]] name = "wasmer-vm" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc1e19d986844b17b927ec8b0c7f3da6a7a2c2cb3b0f8ca5d4cb1a1f71bfb124" +version = "2.3.0" +source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" dependencies = [ "backtrace", "cc", - "cfg-if", + "cfg-if 1.0.0", "corosensei", - "crossbeam-queue", - "dashmap", - "derivative", "enum-iterator", - "fnv", "indexmap 1.9.3", "lazy_static", "libc", + "loupe", "mach", - "memoffset", + "memoffset 0.6.5", "more-asserts", "region", + "rkyv", "scopeguard", + "serde", "thiserror", + "wasmer-artifact", "wasmer-types", "winapi", ] [[package]] name = "wasmparser" -version = "0.107.0" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" -dependencies = [ - "indexmap 1.9.3", - "semver 1.0.20", -] +checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" [[package]] name = "wasmparser" -version = "0.121.2" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" +checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" dependencies = [ - "bitflags 2.5.0", - "indexmap 2.2.6", + "indexmap 1.9.3", "semver 1.0.20", ] @@ -7644,42 +7480,24 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webc" -version = "6.0.0-alpha9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b4e8dd987046eede4348d660404ff990412631b7d493f9e547adcf2862cd5" -dependencies = [ - "anyhow", - "base64 0.21.7", - "bytes", - "cfg-if", - "clap", - "document-features", - "flate2", - "indexmap 1.9.3", - "libc", - "once_cell", - "semver 1.0.20", - "serde", - "serde_cbor", - "serde_json", - "sha2 0.10.8", - "shared-buffer", - "tar", - "tempfile", - "thiserror", - "toml 0.7.8", - "url", - "wasmer-config", -] - [[package]] name = "webpki-roots" version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + [[package]] name = "which" version = "4.4.2" @@ -7931,7 +7749,7 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "windows-sys 0.48.0", ] @@ -7974,12 +7792,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "xxhash-rust" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" - [[package]] name = "zcash_encoding" version = "0.2.0" diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 54cf93dadc..c39334600b 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -16,12 +16,15 @@ members = [ "tx_reactivate_validator", "tx_redelegate", "tx_resign_steward", - "tx_transfer", + "tx_reveal_pk", + "tx_shielded_transfer", + "tx_shielding_transfer", + "tx_transparent_transfer", "tx_unbond", + "tx_unjail_validator", + "tx_unshielding_transfer", "tx_update_account", - "tx_reveal_pk", "tx_update_steward_commission", - "tx_unjail_validator", "tx_vote_proposal", "tx_withdraw", "vp_implicit", diff --git a/wasm/tx_ibc/src/lib.rs b/wasm/tx_ibc/src/lib.rs index a91ef16f91..e131a90c9a 100644 --- a/wasm/tx_ibc/src/lib.rs +++ b/wasm/tx_ibc/src/lib.rs @@ -13,7 +13,7 @@ fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { ibc::ibc_actions(ctx).execute(&data).into_storage_result()?; if let Some(masp_section_ref) = - transfer.and_then(|transfer| transfer.shielded) + transfer.map(|transfer| transfer.shielded_section_hash) { let shielded = tx_data .tx diff --git a/wasm/tx_transfer/Cargo.toml b/wasm/tx_shielded_transfer/Cargo.toml similarity index 92% rename from wasm/tx_transfer/Cargo.toml rename to wasm/tx_shielded_transfer/Cargo.toml index 868a5e6538..8398b69750 100644 --- a/wasm/tx_transfer/Cargo.toml +++ b/wasm/tx_shielded_transfer/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tx_transfer" +name = "tx_shielded_transfer" description = "WASM transaction to transfer tokens" authors.workspace = true edition.workspace = true diff --git a/wasm/tx_shielded_transfer/src/lib.rs b/wasm/tx_shielded_transfer/src/lib.rs new file mode 100644 index 0000000000..cc9e70a638 --- /dev/null +++ b/wasm/tx_shielded_transfer/src/lib.rs @@ -0,0 +1,29 @@ +//! A tx for shielded token transfer. + +use namada_tx_prelude::action::{Action, MaspAction, Write}; +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { + let data = ctx.get_tx_data(&tx_data)?; + let transfer = token::ShieldedTransfer::try_from_slice(&data[..]) + .wrap_err("Failed to decode token::ShieldedTransfer tx data")?; + debug_log!("apply_tx called with transfer: {:#?}", transfer); + + let masp_section_ref = transfer.section_hash; + let shielded = tx_data + .tx + .get_section(&masp_section_ref) + .and_then(|x| x.as_ref().masp_tx()) + .ok_or_err_msg("Unable to find required shielded section in tx data") + .map_err(|err| { + ctx.set_commitment_sentinel(); + err + })?; + token::utils::handle_masp_tx(ctx, &shielded) + .wrap_err("Encountered error while handling MASP transaction")?; + update_masp_note_commitment_tree(&shielded) + .wrap_err("Failed to update the MASP commitment tree")?; + ctx.push_action(Action::Masp(MaspAction { masp_section_ref }))?; + Ok(()) +} diff --git a/wasm/tx_shielding_transfer/Cargo.toml b/wasm/tx_shielding_transfer/Cargo.toml new file mode 100644 index 0000000000..c7e0475434 --- /dev/null +++ b/wasm/tx_shielding_transfer/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "tx_shielding_transfer" +description = "WASM transaction to transfer tokens" +authors.workspace = true +edition.workspace = true +license.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +namada_tx_prelude.workspace = true +wee_alloc.workspace = true +getrandom.workspace = true + +[lib] +crate-type = ["cdylib"] diff --git a/wasm/tx_shielding_transfer/src/lib.rs b/wasm/tx_shielding_transfer/src/lib.rs new file mode 100644 index 0000000000..389942686b --- /dev/null +++ b/wasm/tx_shielding_transfer/src/lib.rs @@ -0,0 +1,39 @@ +//! A tx for shielding token transfer. + +use namada_tx_prelude::action::{Action, MaspAction, Write}; +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { + let data = ctx.get_tx_data(&tx_data)?; + let transfer = token::ShieldingTransfer::try_from_slice(&data[..]) + .wrap_err("Failed to decode token::ShieldingTransfer tx data")?; + debug_log!("apply_tx called with transfer: {:#?}", transfer); + + token::transfer( + ctx, + &transfer.source, + &address::MASP, + &transfer.token, + transfer.amount.amount(), + ) + .wrap_err("Token transfer failed")?; + + let masp_section_ref = transfer.shielded_section_hash; + let shielded = tx_data + .tx + .get_section(&masp_section_ref) + .and_then(|x| x.as_ref().masp_tx()) + .ok_or_err_msg("Unable to find required shielded section in tx data") + .map_err(|err| { + ctx.set_commitment_sentinel(); + err + })?; + token::utils::handle_masp_tx(ctx, &shielded) + .wrap_err("Encountered error while handling MASP transaction")?; + update_masp_note_commitment_tree(&shielded) + .wrap_err("Failed to update the MASP commitment tree")?; + ctx.push_action(Action::Masp(MaspAction { masp_section_ref }))?; + + Ok(()) +} diff --git a/wasm/tx_transfer/src/lib.rs b/wasm/tx_transfer/src/lib.rs deleted file mode 100644 index 62e7adebac..0000000000 --- a/wasm/tx_transfer/src/lib.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! A tx for token transfer. -//! This tx uses `token::Transfer` wrapped inside `SignedTxData` -//! as its input as declared in `namada` crate. - -use namada_tx_prelude::action::{Action, MaspAction, Write}; -use namada_tx_prelude::*; - -#[transaction] -fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { - let data = ctx.get_tx_data(&tx_data)?; - let transfer = token::Transfer::try_from_slice(&data[..]) - .wrap_err("Failed to decode token::Transfer tx data")?; - debug_log!("apply_tx called with transfer: {:#?}", transfer); - - token::transfer( - ctx, - &transfer.source, - &transfer.target, - &transfer.token, - transfer.amount.amount(), - ) - .wrap_err("Token transfer failed")?; - - if let Some(masp_section_ref) = transfer.shielded { - let shielded = tx_data - .tx - .get_section(&masp_section_ref) - .and_then(|x| x.as_ref().masp_tx()) - .ok_or_err_msg( - "Unable to find required shielded section in tx data", - ) - .map_err(|err| { - ctx.set_commitment_sentinel(); - err - })?; - token::utils::handle_masp_tx(ctx, &shielded) - .wrap_err("Encountered error while handling MASP transaction")?; - update_masp_note_commitment_tree(&shielded) - .wrap_err("Failed to update the MASP commitment tree")?; - ctx.push_action(Action::Masp(MaspAction { masp_section_ref }))?; - } - Ok(()) -} diff --git a/wasm/tx_transparent_transfer/Cargo.toml b/wasm/tx_transparent_transfer/Cargo.toml new file mode 100644 index 0000000000..b1b03e76b1 --- /dev/null +++ b/wasm/tx_transparent_transfer/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "tx_transparent_transfer" +description = "WASM transaction to transfer tokens" +authors.workspace = true +edition.workspace = true +license.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +namada_tx_prelude.workspace = true +wee_alloc.workspace = true +getrandom.workspace = true + +[lib] +crate-type = ["cdylib"] diff --git a/wasm/tx_transparent_transfer/src/lib.rs b/wasm/tx_transparent_transfer/src/lib.rs new file mode 100644 index 0000000000..76aacc3891 --- /dev/null +++ b/wasm/tx_transparent_transfer/src/lib.rs @@ -0,0 +1,22 @@ +//! A tx for transparent token transfer. +//! This tx uses `token::TransparentTransfer` wrapped inside `SignedTxData` +//! as its input as declared in `namada` crate. + +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { + let data = ctx.get_tx_data(&tx_data)?; + let transfer = token::TransparentTransfer::try_from_slice(&data[..]) + .wrap_err("Failed to decode token::TransparentTransfer tx data")?; + debug_log!("apply_tx called with transfer: {:#?}", transfer); + + token::transfer( + ctx, + &transfer.source, + &transfer.target, + &transfer.token, + transfer.amount.amount(), + ) + .wrap_err("Token transfer failed") +} diff --git a/wasm/tx_unshielding_transfer/Cargo.toml b/wasm/tx_unshielding_transfer/Cargo.toml new file mode 100644 index 0000000000..5f42ead57c --- /dev/null +++ b/wasm/tx_unshielding_transfer/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "tx_unshielding_transfer" +description = "WASM transaction to transfer tokens" +authors.workspace = true +edition.workspace = true +license.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +namada_tx_prelude.workspace = true +wee_alloc.workspace = true +getrandom.workspace = true + +[lib] +crate-type = ["cdylib"] diff --git a/wasm/tx_unshielding_transfer/src/lib.rs b/wasm/tx_unshielding_transfer/src/lib.rs new file mode 100644 index 0000000000..79bdac0757 --- /dev/null +++ b/wasm/tx_unshielding_transfer/src/lib.rs @@ -0,0 +1,39 @@ +//! A tx for unshielding token transfer. + +use namada_tx_prelude::action::{Action, MaspAction, Write}; +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { + let data = ctx.get_tx_data(&tx_data)?; + let transfer = token::UnshieldingTransfer::try_from_slice(&data[..]) + .wrap_err("Failed to decode token::UnshieldingTransfer tx data")?; + debug_log!("apply_tx called with transfer: {:#?}", transfer); + + token::transfer( + ctx, + &address::MASP, + &transfer.target, + &transfer.token, + transfer.amount.amount(), + ) + .wrap_err("Token transfer failed")?; + + let masp_section_ref = transfer.shielded_section_hash; + let shielded = tx_data + .tx + .get_section(&masp_section_ref) + .and_then(|x| x.as_ref().masp_tx()) + .ok_or_err_msg("Unable to find required shielded section in tx data") + .map_err(|err| { + ctx.set_commitment_sentinel(); + err + })?; + token::utils::handle_masp_tx(ctx, &shielded) + .wrap_err("Encountered error while handling MASP transaction")?; + update_masp_note_commitment_tree(&shielded) + .wrap_err("Failed to update the MASP commitment tree")?; + ctx.push_action(Action::Masp(MaspAction { masp_section_ref }))?; + + Ok(()) +} diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index 330d229b52..34884148da 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -4188,11 +4188,15 @@ dependencies = [ name = "namada_token" version = "0.38.1" dependencies = [ + "borsh 1.2.1", "namada_core", "namada_events", + "namada_macros", "namada_shielded_token", "namada_storage", "namada_trans_token", + "proptest", + "serde", ] [[package]]