From 3b53965402ef7092b9ed54bec772ba71a96db9e4 Mon Sep 17 00:00:00 2001 From: Stan Bondi Date: Fri, 10 Oct 2025 11:20:11 +0400 Subject: [PATCH 1/4] feat!: adds UTXO memos to encrypted data and wallet --- Cargo.lock | 151 ++++++----- Cargo.toml | 2 +- .../processes/minotari_wallet.rs | 13 +- .../src/command/transaction.rs | 9 +- .../tari_walletd/src/handlers/accounts.rs | 24 +- .../tari_walletd/src/handlers/confidential.rs | 8 + .../src/handlers/stealth_utxos.rs | 1 + .../web_ui/src/components/Memo.tsx | 22 ++ .../Tokens/components/SendMoney.tsx | 2 + .../AssetVault/Tokens/steps/FormStep.tsx | 12 + .../StealthUtxoList/StealthUtxoList.tsx | 18 +- .../src/services/api/hooks/useAccounts.ts | 4 + bindings/src/index.ts | 1 + bindings/src/types/Memo.ts | 3 + .../ConfidentialTransferRequest.ts | 2 + .../ProofsGenerateRequest.ts | 2 + .../StealthTransferRequest.ts | 2 + .../types/wallet-daemon-client/UtxoInfo.ts | 2 + clients/wallet_daemon_client/src/types.rs | 21 +- crates/engine_types/src/confidential/claim.rs | 2 +- crates/engine_types/src/crypto/output.rs | 2 +- crates/p2p/src/conversions/transaction.rs | 2 +- crates/template_lib/src/models/mod.rs | 2 - .../template_lib/src/models/unspent_output.rs | 7 +- crates/template_lib/src/prelude.rs | 2 + .../src}/encrypted_data.rs | 34 +-- crates/template_lib_types/src/lib.rs | 6 + crates/template_lib_types/src/max_bytes.rs | 175 +++++++++++++ crates/template_lib_types/src/max_string.rs | 111 ++++++++ crates/template_lib_types/src/memo.rs | 237 ++++++++++++++++++ .../template_lib_types/src/serde_helpers.rs | 13 + .../src/support/confidential.rs | 8 +- .../src/support/stealth.rs | 5 +- crates/wallet/crypto/Cargo.toml | 1 - crates/wallet/crypto/src/confidential.rs | 3 +- crates/wallet/crypto/src/encrypted_data.rs | 195 +++++++++++--- crates/wallet/crypto/src/error.rs | 8 +- crates/wallet/crypto/src/stealth.rs | 6 +- .../wallet/crypto/src/unblinded_statement.rs | 34 ++- .../wallet/crypto/tests/output_statement.rs | 11 +- .../crypto/tests/viewable_balance_proof.rs | 4 +- .../sdk/src/apis/confidential_crypto.rs | 27 +- .../sdk/src/apis/confidential_outputs.rs | 17 +- .../sdk/src/apis/confidential_transfer.rs | 11 +- crates/wallet/sdk/src/apis/stealth_crypto.rs | 19 +- crates/wallet/sdk/src/apis/stealth_outputs.rs | 18 +- .../wallet/sdk/src/apis/stealth_transfer.rs | 20 +- .../sdk/src/models/confidential_output.rs | 5 +- .../wallet/sdk/src/models/stealth_output.rs | 5 +- crates/wallet/sdk/tests/base_layer_compat.rs | 19 ++ .../sdk/tests/confidential_output_api.rs | 3 +- crates/wallet/sdk/tests/crypto_api.rs | 14 +- crates/wallet/sdk/tests/support/harness.rs | 4 +- .../2023-02-08-122514_initial/up.sql | 2 + .../src/models/confidential_output.rs | 8 +- .../src/models/stealth_output.rs | 5 +- crates/wallet/storage_sqlite/src/schema.rs | 4 + crates/wallet/storage_sqlite/src/writer.rs | 6 +- integration_tests/src/wallet_daemon_client.rs | 2 + integration_tests/tests/steps/wallet.rs | 2 +- 60 files changed, 1107 insertions(+), 251 deletions(-) create mode 100644 applications/tari_walletd/web_ui/src/components/Memo.tsx create mode 100644 bindings/src/types/Memo.ts rename crates/{template_lib/src/models => template_lib_types/src}/encrypted_data.rs (69%) create mode 100644 crates/template_lib_types/src/max_bytes.rs create mode 100644 crates/template_lib_types/src/max_string.rs create mode 100644 crates/template_lib_types/src/memo.rs create mode 100644 crates/wallet/sdk/tests/base_layer_compat.rs diff --git a/Cargo.lock b/Cargo.lock index 8d8ad59395..fe9ea940a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,7 +285,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.17", "time", ] @@ -858,7 +858,7 @@ dependencies = [ "mime", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -1187,7 +1187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09dc0086e469182132244e9b8d313a0742e1132da43a08c24b9dd3c18e0faf3a" dependencies = [ "serde", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -4147,7 +4147,7 @@ dependencies = [ "rand 0.9.1", "ring 0.17.14", "socket2 0.5.10", - "thiserror 2.0.12", + "thiserror 2.0.17", "tinyvec", "tokio", "tracing", @@ -4175,7 +4175,7 @@ dependencies = [ "ring 0.17.14", "rustls 0.23.28", "rustls-platform-verifier", - "thiserror 2.0.12", + "thiserror 2.0.17", "tinyvec", "tokio", "tokio-rustls 0.26.2", @@ -4199,7 +4199,7 @@ dependencies = [ "rand 0.9.1", "resolv-conf", "smallvec 1.15.1", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "tracing", ] @@ -4221,7 +4221,7 @@ dependencies = [ "resolv-conf", "rustls 0.23.28", "smallvec 1.15.1", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "tokio-rustls 0.26.2", "tracing", @@ -5545,7 +5545,7 @@ dependencies = [ "multiaddr 0.18.1", "pin-project 1.1.10", "rw-stream-sink", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -5577,7 +5577,7 @@ dependencies = [ "quick-protobuf-codec 0.3.1 (git+https://github.com/tari-project/rust-libp2p.git?rev=debc01257dd979418d7793f2dc91d25471de5c38)", "rand 0.8.5", "rand_core 0.6.4", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", "web-time", ] @@ -5610,7 +5610,7 @@ dependencies = [ "quick-protobuf", "rand 0.8.5", "rw-stream-sink", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", "unsigned-varint 0.8.0", "web-time", @@ -5632,7 +5632,7 @@ dependencies = [ "lru", "quick-protobuf", "quick-protobuf-codec 0.3.1 (git+https://github.com/tari-project/rust-libp2p.git?rev=debc01257dd979418d7793f2dc91d25471de5c38)", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", "web-time", ] @@ -5697,7 +5697,7 @@ dependencies = [ "quick-protobuf", "quick-protobuf-codec 0.3.1 (git+https://github.com/tari-project/rust-libp2p.git?rev=debc01257dd979418d7793f2dc91d25471de5c38)", "smallvec 1.15.1", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", ] @@ -5715,7 +5715,7 @@ dependencies = [ "serde", "sha2", "tari_crypto", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", "zeroize", ] @@ -5786,7 +5786,7 @@ dependencies = [ "rand 0.8.5", "snow", "static_assertions", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", "x25519-dalek", "zeroize", @@ -5816,7 +5816,7 @@ dependencies = [ "prometheus-client", "quick-protobuf", "quick-protobuf-codec 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.69", + "thiserror 2.0.17", "tracing", ] @@ -5851,7 +5851,7 @@ dependencies = [ "ring 0.17.14", "rustls 0.23.28", "socket2 0.5.10", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "tracing", ] @@ -5874,7 +5874,7 @@ dependencies = [ "quick-protobuf-codec 0.3.1 (git+https://github.com/tari-project/rust-libp2p.git?rev=debc01257dd979418d7793f2dc91d25471de5c38)", "rand 0.8.5", "static_assertions", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", "web-time", ] @@ -5896,7 +5896,7 @@ dependencies = [ "quick-protobuf", "quick-protobuf-codec 0.3.1 (git+https://github.com/tari-project/rust-libp2p.git?rev=debc01257dd979418d7793f2dc91d25471de5c38)", "rand 0.8.5", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", "web-time", ] @@ -5986,7 +5986,7 @@ dependencies = [ "ring 0.17.14", "rustls 0.23.28", "rustls-webpki 0.103.3", - "thiserror 2.0.12", + "thiserror 2.0.17", "x509-parser 0.17.0", "yasna", ] @@ -6013,7 +6013,7 @@ dependencies = [ "either", "futures 0.3.31", "libp2p-core", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", "yamux 0.12.1", "yamux 0.13.5", @@ -6236,7 +6236,7 @@ checksum = "656b3b27f8893f7bbf9485148ff9a65f019e3f33bd5cdc87c83cab16b3fd9ec8" dependencies = [ "libc", "neli", - "thiserror 2.0.12", + "thiserror 2.0.17", "windows-sys 0.59.0", ] @@ -6353,7 +6353,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" dependencies = [ - "thiserror 2.0.12", + "thiserror 2.0.17", "zerocopy", "zerocopy-derive", ] @@ -7146,7 +7146,7 @@ dependencies = [ "log", "netlink-packet-core", "netlink-sys", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -7844,7 +7844,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror 2.0.12", + "thiserror 2.0.17", "ucd-trie", ] @@ -8259,7 +8259,7 @@ dependencies = [ "memchr", "parking_lot", "protobuf", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -8574,7 +8574,7 @@ dependencies = [ "asynchronous-codec", "bytes 1.10.1", "quick-protobuf", - "thiserror 2.0.12", + "thiserror 2.0.17", "unsigned-varint 0.8.0", ] @@ -8602,7 +8602,7 @@ dependencies = [ "rustc-hash 2.1.1", "rustls 0.23.28", "socket2 0.5.10", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -8623,7 +8623,7 @@ dependencies = [ "rustls 0.23.28", "rustls-pki-types", "slab", - "thiserror 2.0.12", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -10093,7 +10093,7 @@ checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.12", + "thiserror 2.0.17", "time", ] @@ -10721,7 +10721,7 @@ dependencies = [ "tari_template_lib", "tari_transaction_components", "tari_utilities", - "thiserror 1.0.69", + "thiserror 2.0.17", "tonic 0.13.1", "ts-rs", "url", @@ -10951,7 +10951,7 @@ dependencies = [ "tari_state_tree", "tari_template_lib_types", "tari_transaction", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", ] @@ -11081,7 +11081,7 @@ dependencies = [ "tari_transaction_manifest", "tari_utilities", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "wasmer", "wasmer-middlewares", ] @@ -11109,7 +11109,7 @@ dependencies = [ "tari_hashing", "tari_template_abi", "tari_template_lib", - "thiserror 1.0.69", + "thiserror 2.0.17", "ts-rs", ] @@ -11130,7 +11130,7 @@ dependencies = [ "tari_shutdown", "tari_sidechain", "tari_template_lib_types", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "url", ] @@ -11155,7 +11155,7 @@ dependencies = [ "tari_template_lib", "tari_transaction_components", "tari_utilities", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "url", ] @@ -11232,7 +11232,7 @@ dependencies = [ "tari_template_manager", "tari_transaction", "tari_validator_node_rpc", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "tokio", "tower-http", @@ -11265,7 +11265,7 @@ dependencies = [ "tari_template_abi", "tari_template_lib_types", "tari_transaction", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "ts-rs", "utoipa", @@ -11281,7 +11281,7 @@ dependencies = [ "tari_epoch_manager", "tari_ootle_common_types", "tari_validator_node_rpc", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -11295,7 +11295,7 @@ dependencies = [ "serde", "tari_crypto", "tari_hashing", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -11360,7 +11360,7 @@ dependencies = [ "tari_rpc_framework", "tari_shutdown", "tari_swarm", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", ] @@ -11396,7 +11396,7 @@ dependencies = [ "tari_engine_types", "tari_ootle_common_types", "tari_template_lib_types", - "thiserror 1.0.69", + "thiserror 2.0.17", "ts-rs", ] @@ -11433,7 +11433,7 @@ dependencies = [ "tari_template_manager", "tari_transaction", "tari_transaction_components", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "toml 0.9.6", "url", @@ -11463,7 +11463,7 @@ dependencies = [ "tari_mmr", "tari_template_lib", "tari_template_lib_types", - "thiserror 1.0.69", + "thiserror 2.0.17", "ts-rs", ] @@ -11509,7 +11509,7 @@ dependencies = [ "tari_state_tree", "tari_template_lib", "tari_transaction", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "ts-rs", ] @@ -11531,7 +11531,7 @@ dependencies = [ "tari_ootle_storage", "tari_template_lib", "tari_utilities", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -11556,7 +11556,7 @@ dependencies = [ "tari_transaction_manifest", "tari_utilities", "tari_wallet_daemon_client", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "tokio", "url", @@ -11580,9 +11580,8 @@ dependencies = [ "tari_hashing", "tari_ootle_common_types", "tari_template_lib", - "tari_template_test_tooling", "tari_utilities", - "thiserror 1.0.69", + "thiserror 2.0.17", "zeroize", ] @@ -11613,7 +11612,7 @@ dependencies = [ "tari_transaction", "tari_transaction_components", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "ts-rs", "webauthn-rs", @@ -11640,7 +11639,7 @@ dependencies = [ "tari_template_builtin", "tari_template_lib", "tari_transaction", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "url", ] @@ -11715,7 +11714,7 @@ dependencies = [ "tari_utilities", "tari_wallet_daemon_client", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tower-http", "url", @@ -11771,7 +11770,7 @@ dependencies = [ "proto_builder", "tari_metrics", "tari_shutdown", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tokio-util 0.7.16", "tower 0.5.2", @@ -11804,7 +11803,7 @@ dependencies = [ "tari_state_tree", "tari_template_manager", "tari_validator_node_rpc", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -11876,7 +11875,7 @@ dependencies = [ "tari_hashing", "tari_jellyfish", "tari_utilities", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -11899,7 +11898,7 @@ dependencies = [ "tari_ootle_common_types", "tari_shutdown", "tari_utilities", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tower-http", "webrtc", @@ -11928,7 +11927,7 @@ dependencies = [ "tari_template_lib_types", "tari_transaction", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -11943,7 +11942,7 @@ dependencies = [ "tari_jellyfish", "tari_ootle_common_types", "tari_template_lib", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -11965,7 +11964,7 @@ dependencies = [ "libp2p", "libp2p-messaging", "libp2p-substream", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -12006,7 +12005,7 @@ dependencies = [ "tari_transaction_components", "tari_validator_node_client", "tari_wallet_daemon_client", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "toml 0.9.6", "tonic 0.13.1", @@ -12103,7 +12102,7 @@ dependencies = [ "tari_template_builtin", "tari_template_lib", "tari_validator_node_rpc", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tokio-stream", ] @@ -12126,7 +12125,7 @@ dependencies = [ "tari_template_lib", "tari_transaction", "tari_transaction_manifest", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -12158,7 +12157,7 @@ dependencies = [ "tari_engine_types", "tari_ootle_common_types", "tari_template_lib", - "thiserror 1.0.69", + "thiserror 2.0.17", "ts-rs", ] @@ -12241,7 +12240,7 @@ dependencies = [ "tari_template_builtin", "tari_template_lib", "tari_transaction", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -12319,7 +12318,7 @@ dependencies = [ "tari_transaction_components", "tari_validator_node_client", "tari_validator_node_rpc", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tower-http", "url", @@ -12348,7 +12347,7 @@ dependencies = [ "tari_transaction", "tari_transaction_manifest", "tari_validator_node_client", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "tokio", ] @@ -12372,7 +12371,7 @@ dependencies = [ "tari_template_abi", "tari_template_lib_types", "tari_transaction", - "thiserror 1.0.69", + "thiserror 2.0.17", "ts-rs", ] @@ -12394,7 +12393,7 @@ dependencies = [ "tari_rpc_framework", "tari_rpc_macros", "tari_transaction", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", ] @@ -12412,7 +12411,7 @@ dependencies = [ "tari_template_abi", "tari_template_lib", "tari_transaction", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "ts-rs", "webauthn-rs-proto", @@ -12533,11 +12532,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.17", ] [[package]] @@ -12553,9 +12552,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -13159,7 +13158,7 @@ checksum = "6ef1b7a6d914a34127ed8e1fa927eb7088903787bcded4fa3eef8f85ee1568be" dependencies = [ "chrono", "indexmap 2.11.4", - "thiserror 2.0.12", + "thiserror 2.0.17", "ts-rs-macros", ] @@ -13201,7 +13200,7 @@ dependencies = [ "log", "rand 0.9.1", "sha1 0.10.6", - "thiserror 2.0.12", + "thiserror 2.0.17", "utf-8", ] @@ -14880,7 +14879,7 @@ dependencies = [ "nom", "oid-registry 0.8.1", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.17", "time", ] diff --git a/Cargo.toml b/Cargo.toml index c708c054ff..6adb3aabf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -236,7 +236,7 @@ smallvec = "2.0.0-alpha.11" std-semaphore = "0.1.0" syn = "2.0" tempfile = "3.3.0" -thiserror = "1.0.59" +thiserror = "2.0.17" time = "0.3.15" tokio = { version = "1.47.1", default-features = false } tokio-stream = "0.1.17" diff --git a/applications/tari_swarm_daemon/src/process_manager/processes/minotari_wallet.rs b/applications/tari_swarm_daemon/src/process_manager/processes/minotari_wallet.rs index 2b85a1f3b4..4cdbbac1f1 100644 --- a/applications/tari_swarm_daemon/src/process_manager/processes/minotari_wallet.rs +++ b/applications/tari_swarm_daemon/src/process_manager/processes/minotari_wallet.rs @@ -8,15 +8,10 @@ use minotari_node_grpc_client::grpc; use minotari_wallet_grpc_client::WalletGrpcClient; use serde::Serialize; use tari_crypto::tari_utilities::ByteArray; -use tari_engine_types::{ - confidential::{AbridgedTransactionKernel, EncodedMerkleProof, MinotariBurnClaimProof}, - template_lib_models::EncryptedData, -}; -use tari_template_lib_types::crypto::{ - PedersenCommitmentBytes, - RistrettoPublicKeyBytes, - Scalar32Bytes, - SchnorrSignatureBytes, +use tari_engine_types::confidential::{AbridgedTransactionKernel, EncodedMerkleProof, MinotariBurnClaimProof}; +use tari_template_lib_types::{ + crypto::{PedersenCommitmentBytes, RistrettoPublicKeyBytes, Scalar32Bytes, SchnorrSignatureBytes}, + EncryptedData, }; use tari_transaction_components::transaction_components::{memo_field::TxType, MemoField}; use tari_wallet_daemon_client::types::ClaimBurnProof; diff --git a/applications/tari_wallet_cli/src/command/transaction.rs b/applications/tari_wallet_cli/src/command/transaction.rs index e35f74590a..097beb7844 100644 --- a/applications/tari_wallet_cli/src/command/transaction.rs +++ b/applications/tari_wallet_cli/src/command/transaction.rs @@ -46,7 +46,7 @@ use tari_template_lib::{ constants::STEALTH_TARI_RESOURCE_ADDRESS, models::{BucketId, NonFungibleAddress, NonFungibleId}, prelude::{ResourceAddress, RistrettoPublicKeyBytes}, - types::{Amount, TemplateAddress}, + types::{Amount, Memo, TemplateAddress}, }; use tari_transaction::{ args, @@ -153,6 +153,9 @@ pub struct ConfidentialTransferArgs { /// The address of the resource to send. If not provided, use the default Tari confidential resource #[clap(long)] resource_address: Option, + /// An optional memo to include in the confidential output + #[clap(long, short = 'm')] + memo_message: Option, } #[derive(Debug, Subcommand, Clone)] @@ -416,6 +419,7 @@ pub async fn handle_confidential_transfer( amount, destination_address, common, + memo_message, } = args; // let AccountByNameResponse { account, .. } = client.accounts_get_by_name(&source_account_name).await?; @@ -429,6 +433,9 @@ pub async fn handle_confidential_transfer( max_fee: common.max_fee, output_to_revealed: false, proof_from_badge_resource: None, + memo: memo_message + .map(|s| Memo::new_message(s).ok_or_else(|| anyhow!("Invalid memo length"))) + .transpose()?, dry_run: false, }) .await?; diff --git a/applications/tari_walletd/src/handlers/accounts.rs b/applications/tari_walletd/src/handlers/accounts.rs index e36ab8bbef..8b529720c6 100644 --- a/applications/tari_walletd/src/handlers/accounts.rs +++ b/applications/tari_walletd/src/handlers/accounts.rs @@ -34,7 +34,7 @@ use tari_ootle_wallet_sdk_services::events::TransactionSubmittedEvent; use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS; use tari_template_lib::{ constants::{STEALTH_TARI_RESOURCE_ADDRESS, XTR, XTR_FAUCET_COMPONENT_ADDRESS, XTR_FAUCET_VAULT_ADDRESS}, - types::{Amount, ResourceType}, + types::{Amount, Memo, ResourceType}, }; use tari_transaction::args; use tari_wallet_daemon_client::{ @@ -455,17 +455,18 @@ pub async fn handle_claim_burn( .burn_public_key .try_from_byte_type() .map_err(|e| invalid_params("claim_proof.reciprocal_claim_public_key", Some(e)))?; - let mask_and_value = sdk.stealth_crypto_api().decrypt_value_and_mask( + let decrypted = sdk.stealth_crypto_api().decrypt_value_and_mask( &claimed_encrypted_data, &claim_proof.commitment, claim_nonce_keypair.secret_key(), &reciprocal_claim_public_key_expanded, + true, )?; let mask = sdk.key_manager_api().next_key(KeyBranch::StealthMask)?; - let final_amount = mask_and_value - .value + let final_amount = decrypted + .value() .checked_sub_positive(max_fee.into()) .ok_or_else(|| invalid_params("max_fee", Some("more fees paid than claimed amount")))?; @@ -490,9 +491,13 @@ pub async fn handle_claim_burn( // NOTE: the confidential encryption format and the bullet proofs currently do not support amounts larger than // u64::MAX. Apart from it being insane/basically impossible to have that much XTR in a single UTXO, the L1 emission // will reach this much in many thousands of years. - let encrypted_data = - sdk.stealth_crypto_api() - .encrypt_value_and_mask(final_amount_u64, &mask.key, &view_only_public_key, &nonce)?; + let encrypted_data = sdk.stealth_crypto_api().encrypt_value_and_mask( + final_amount_u64, + &mask.key, + &view_only_public_key, + &nonce, + None, + )?; let tag = sdk.stealth_crypto_api().derive_stealth_output_tag( network, @@ -513,6 +518,7 @@ pub async fn handle_claim_burn( sender_public_nonce: output_public_nonce.clone(), minimum_value_promise: 0, encrypted_data, + memo: Some(Memo::new_message("Claimed burned XTR from L1").expect("valid memo")), resource_view_key: None, }, output_owner_public_key: stealth_output_owner_public_key, @@ -521,7 +527,7 @@ pub async fn handle_claim_burn( // Generate the correct secret to spend the claimed output let input = UnblindedStealthInputStatement { - mask_and_value, + mask_and_value: decrypted.into_mask_and_value(), owner_secret: claim_nonce_keypair.secret_key().clone(), public_nonce: reciprocal_claim_public_key_expanded, }; @@ -904,6 +910,7 @@ pub async fn handle_confidential_transfer( max_fee: req.max_fee.unwrap_or(DEFAULT_FEE), output_to_revealed: req.output_to_revealed, proof_from_resource: req.proof_from_badge_resource, + memo: req.memo, is_dry_run: req.dry_run, }) .await?; @@ -946,6 +953,7 @@ pub async fn handle_stealth_transfer( max_fee: req.max_fee, blinded_output_amount: req.blinded_output_amount, revealed_output_amount: req.revealed_output_amount, + output_memo: req.output_memo, is_dry_run: req.dry_run, }; if let Err(err) = params.validate(network) { diff --git a/applications/tari_walletd/src/handlers/confidential.rs b/applications/tari_walletd/src/handlers/confidential.rs index 7b8c250866..c095536a18 100644 --- a/applications/tari_walletd/src/handlers/confidential.rs +++ b/applications/tari_walletd/src/handlers/confidential.rs @@ -102,6 +102,7 @@ pub async fn handle_create_transfer_proof( &output_mask.key, &public_nonce, &account_key.secret, + req.memo.as_ref(), )?; let resource = sdk.substate_api().fetch_resource(req.resource_address).await?; @@ -120,6 +121,7 @@ pub async fn handle_create_transfer_proof( minimum_value_promise: 0, encrypted_data, resource_view_key: resource_view_key.clone(), + memo: req.memo, }; let spend_amount = req.amount.checked_sub_positive(req.reveal_amount).ok_or_else(|| { @@ -150,6 +152,7 @@ pub async fn handle_create_transfer_proof( &change_mask.key, &public_nonce, &change_mask.key, + None, )?; sdk.confidential_outputs_api().add_output(ConfidentialOutputModel { @@ -163,6 +166,7 @@ pub async fn handle_create_transfer_proof( view_only_key_id: account.view_only_key_id(), owner_key_id: account.owner_key_id(), encrypted_data: encrypted_data.clone(), + memo: None, public_asset_tag: None, status: OutputStatus::LockedUnconfirmed, lock_id: Some(lock_id), @@ -174,6 +178,7 @@ pub async fn handle_create_transfer_proof( sender_public_nonce: public_nonce, encrypted_data, minimum_value_promise: 0, + memo: None, resource_view_key, }) } else { @@ -246,6 +251,8 @@ pub async fn handle_create_output_proof( &output_mask.key, &public_nonce, &output_mask.key, + // TODO: Support memos + None, )?; let statement = UnblindedOutputStatement { @@ -254,6 +261,7 @@ pub async fn handle_create_output_proof( sender_public_nonce: public_nonce, minimum_value_promise: 0, encrypted_data, + memo: None, // TODO: the request must include the resource address so that we can fetch the view key resource_view_key: None, }; diff --git a/applications/tari_walletd/src/handlers/stealth_utxos.rs b/applications/tari_walletd/src/handlers/stealth_utxos.rs index 4236a6873f..1d5c683772 100644 --- a/applications/tari_walletd/src/handlers/stealth_utxos.rs +++ b/applications/tari_walletd/src/handlers/stealth_utxos.rs @@ -46,6 +46,7 @@ pub async fn handle_list( address: o.to_utxo_address(), value: o.value, status: o.status, + memo: o.memo, is_burnt: o.is_burnt, is_frozen: o.is_frozen, is_on_chain: o.is_on_chain, diff --git a/applications/tari_walletd/web_ui/src/components/Memo.tsx b/applications/tari_walletd/web_ui/src/components/Memo.tsx new file mode 100644 index 0000000000..836c7c9707 --- /dev/null +++ b/applications/tari_walletd/web_ui/src/components/Memo.tsx @@ -0,0 +1,22 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause +import { Memo } from "@tari-project/typescript-bindings"; + +export type MemoProps = { + memo?: Memo | null; +}; + +export function Memo({ memo }: MemoProps) { + if (!memo) { + return --; + } + + if ("Message" in memo) { + return {memo ? memo.Message : "No Memo"}; + } + if ("Bytes" in memo) { + return {memo ? Buffer.from(memo.Bytes).toString("hex") : "No Memo"}; + } + + return {JSON.stringify(memo)}; +} diff --git a/applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx b/applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx index fe2edacc9c..d19f088f17 100644 --- a/applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx +++ b/applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx @@ -190,6 +190,7 @@ export function SendMoneyDialog(props: SendMoneyDialogProps) { output_to_revealed: !transferFormState.outputToConfidential, input_selection: transferFormState.inputSelection as ConfidentialTransferInputSelection, badge: transferFormState.badge, + output_memo: transferFormState.memo ? { Message: transferFormState.memo } : undefined, }; const result = await sendIt?.({ ...currentTransfer, dry_run: true, max_fee: 3000 }); @@ -253,6 +254,7 @@ export function SendMoneyDialog(props: SendMoneyDialogProps) { output_to_revealed: !transferFormState.outputToConfidential, input_selection: transferFormState.inputSelection as ConfidentialTransferInputSelection, badge: transferFormState.badge, + output_memo: transferFormState.memo ? { Message: transferFormState.memo } : undefined, }; await sendIt?.({ diff --git a/applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/steps/FormStep.tsx b/applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/steps/FormStep.tsx index 1a91894f95..16a6914d04 100644 --- a/applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/steps/FormStep.tsx +++ b/applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/steps/FormStep.tsx @@ -41,6 +41,7 @@ export interface SendMoneyFormState { amount: string; fee: string; badge: string | null; + memo: string; } interface FormStepProps { @@ -174,6 +175,17 @@ export default function FormStep({ } label="Send Confidential Outputs" /> + {transferFormState.outputToConfidential ? ( + + ) : null} Input Selection