diff --git a/Cargo.lock b/Cargo.lock index 4c67063e70..be60cbc2af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4899,7 +4899,6 @@ dependencies = [ "tari_template_lib", "tari_transaction", "tari_transaction_components", - "tari_transaction_key_manager", "tari_transaction_manifest", "tari_validator_node", "tari_validator_node_cli", @@ -6410,8 +6409,8 @@ dependencies = [ [[package]] name = "minotari_app_grpc" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "argon2 0.4.1", "base64 0.13.1", @@ -6441,8 +6440,8 @@ dependencies = [ [[package]] name = "minotari_app_utilities" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "clap 3.2.25", "dialoguer 0.10.4", @@ -6464,8 +6463,8 @@ dependencies = [ [[package]] name = "minotari_console_wallet" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "blake2", "chrono", @@ -6482,6 +6481,7 @@ dependencies = [ "log4rs", "minotari_app_grpc", "minotari_app_utilities", + "minotari_ledger_wallet_common", "minotari_ledger_wallet_comms", "minotari_wallet", "qrcode", @@ -6507,6 +6507,7 @@ dependencies = [ "tari_script", "tari_shutdown", "tari_transaction_components", + "tari_transaction_key_manager", "tari_utilities", "thiserror 2.0.17", "tokio", @@ -6519,16 +6520,17 @@ dependencies = [ [[package]] name = "minotari_ledger_wallet_common" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "bs58 0.5.1", + "serde", ] [[package]] name = "minotari_ledger_wallet_comms" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "borsh", "dialoguer 0.11.0", @@ -6549,8 +6551,8 @@ dependencies = [ [[package]] name = "minotari_node" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "async-trait", @@ -6603,16 +6605,16 @@ dependencies = [ [[package]] name = "minotari_node_grpc_client" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "minotari_app_grpc", ] [[package]] name = "minotari_node_wallet_client" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "async-trait", @@ -6629,8 +6631,8 @@ dependencies = [ [[package]] name = "minotari_wallet" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "argon2 0.4.1", @@ -6649,6 +6651,7 @@ dependencies = [ "itertools 0.10.5", "libsqlite3-sys", "log", + "minotari_ledger_wallet_common", "minotari_node_wallet_client", "prost 0.13.5", "rand 0.8.5", @@ -6685,7 +6688,7 @@ dependencies = [ [[package]] name = "minotari_wallet_grpc_client" version = "0.1.0" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "minotari_app_grpc", "tari_common", @@ -10598,8 +10601,8 @@ dependencies = [ [[package]] name = "tari_common" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "cargo_toml 0.20.5", @@ -10624,8 +10627,8 @@ dependencies = [ [[package]] name = "tari_common_sqlite" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "diesel", "diesel_migrations", @@ -10641,8 +10644,8 @@ dependencies = [ [[package]] name = "tari_common_types" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "argon2 0.4.1", "base64 0.21.7", @@ -10656,7 +10659,6 @@ dependencies = [ "digest", "getrandom 0.2.16", "js-sys", - "minotari_ledger_wallet_common", "newtype-ops", "once_cell", "primitive-types", @@ -10678,8 +10680,8 @@ dependencies = [ [[package]] name = "tari_comms" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "async-trait", @@ -10725,8 +10727,8 @@ dependencies = [ [[package]] name = "tari_comms_dht" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "bitflags 2.10.0", @@ -10759,8 +10761,8 @@ dependencies = [ [[package]] name = "tari_comms_rpc_macros" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "proc-macro2", "quote", @@ -10809,8 +10811,8 @@ dependencies = [ [[package]] name = "tari_core" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "async-trait", @@ -10862,7 +10864,6 @@ dependencies = [ "tari_storage", "tari_test_utils", "tari_transaction_components", - "tari_transaction_key_manager", "tari_utilities", "thiserror 2.0.17", "tokio", @@ -10998,13 +10999,13 @@ dependencies = [ [[package]] name = "tari_features" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" [[package]] name = "tari_hashing" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "blake2", "borsh", @@ -11123,8 +11124,8 @@ dependencies = [ [[package]] name = "tari_jellyfish" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "borsh", "digest", @@ -11137,8 +11138,8 @@ dependencies = [ [[package]] name = "tari_libtor" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "derivative", "libtor", @@ -11151,8 +11152,8 @@ dependencies = [ [[package]] name = "tari_max_size" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "borsh", "serde", @@ -11162,8 +11163,8 @@ dependencies = [ [[package]] name = "tari_metrics" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "once_cell", "prometheus", @@ -11172,8 +11173,8 @@ dependencies = [ [[package]] name = "tari_mmr" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "borsh", "digest", @@ -11203,8 +11204,8 @@ dependencies = [ [[package]] name = "tari_node_components" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "blake2", "borsh", @@ -11433,12 +11434,14 @@ dependencies = [ "keyring", "log", "passwords", + "rand 0.8.5", "serde", "tari_bor", "tari_common_types", "tari_consensus_types", "tari_crypto", "tari_engine_types", + "tari_hashing", "tari_ootle_address", "tari_ootle_common_types", "tari_ootle_wallet_crypto", @@ -11564,8 +11567,8 @@ dependencies = [ [[package]] name = "tari_p2p" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "futures 0.3.31", @@ -11659,8 +11662,8 @@ dependencies = [ [[package]] name = "tari_script" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "blake2", "borsh", @@ -11677,8 +11680,8 @@ dependencies = [ [[package]] name = "tari_service_framework" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", "async-trait", @@ -11692,16 +11695,16 @@ dependencies = [ [[package]] name = "tari_shutdown" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "futures 0.3.31", ] [[package]] name = "tari_sidechain" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "borsh", "hex", @@ -11784,8 +11787,8 @@ dependencies = [ [[package]] name = "tari_storage" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "bincode 1.3.3", "lmdb-zero", @@ -11935,8 +11938,8 @@ dependencies = [ [[package]] name = "tari_test_utils" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "futures 0.3.31", "rand 0.8.5", @@ -11968,11 +11971,10 @@ dependencies = [ [[package]] name = "tari_transaction_components" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "anyhow", - "async-trait", "bitflags 2.10.0", "blake2", "borsh", @@ -11984,6 +11986,7 @@ dependencies = [ "digest", "integer-encoding", "log", + "minotari_ledger_wallet_common", "minotari_ledger_wallet_comms", "newtype-ops", "num-derive 0.4.2", @@ -11996,7 +11999,6 @@ dependencies = [ "serde_json", "serde_repr", "serde_valid", - "strum 0.22.0", "strum_macros 0.22.0", "tari_common", "tari_common_types", @@ -12004,7 +12006,6 @@ dependencies = [ "tari_hashing", "tari_max_size", "tari_script", - "tari_service_framework", "tari_sidechain", "tari_utilities", "thiserror 2.0.17", @@ -12016,20 +12017,32 @@ dependencies = [ [[package]] name = "tari_transaction_key_manager" -version = "5.2.0-pre.2" -source = "git+https://github.com/tari-project/tari.git?branch=development#63e36e6308d1ec5ff3f1676a06f87560b423ae4c" +version = "5.2.0-pre.4" +source = "git+https://github.com/tari-project/tari.git?branch=development#d1772745dec8d231b54c689fcaf7470ab5ed455c" dependencies = [ "async-trait", + "blake2", "chacha20poly1305", "chrono", + "derivative", "diesel", "diesel_migrations", + "digest", + "futures 0.3.31", "log", "rand 0.8.5", + "serde", + "strum 0.22.0", + "strum_macros 0.22.0", "tari_common_sqlite", "tari_common_types", + "tari_crypto", + "tari_hashing", + "tari_script", + "tari_service_framework", "tari_transaction_components", "tari_utilities", + "thiserror 2.0.17", "tokio", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index 6d1cba3f97..8fafd64e89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,7 +135,6 @@ tari_node_components = { git = "https://github.com/tari-project/tari.git", branc tari_shutdown = { git = "https://github.com/tari-project/tari.git", branch = "development" } tari_sidechain = { git = "https://github.com/tari-project/tari.git", branch = "development" } tari_transaction_components = { git = "https://github.com/tari-project/tari.git", branch = "development" } -tari_transaction_key_manager = { git = "https://github.com/tari-project/tari.git", branch = "development" } tari_crypto = "0.22.0" tari_utilities = "0.8.0" @@ -272,7 +271,6 @@ overflow-checks = true #tari_comms_rpc_macros = { git = "https://github.com/account/tari.git", branch = "my-branch" } #tari_transaction_components = { git = "https://github.com/account/tari.git", branch = "my-branch" } #tari_node_components = { git = "https://github.com/account/tari.git", branch = "my-branch" } -#tari_transaction_key_manager = { git = "https://github.com/account/tari.git", branch = "my-branch" } #tari_mmr = { git = "https://github.com/account/tari.git", branch = "my-branch" } #tari_p2p = { git = "https://github.com/account/tari.git", branch = "my-branch" } #tari_shutdown = { git = "https://github.com/account/tari.git", branch = "my-branch" } @@ -301,7 +299,6 @@ overflow-checks = true #tari_comms_rpc_macros = { path = "../tari/comms/rpc_macros" } #tari_transaction_components = { path = "../tari/base_layer/transaction_components" } #tari_node_components = { path = "../tari/base_layer/node_components" } -#tari_transaction_key_manager = { path = "../tari/base_layer/transaction_key_manager" } #tari_mmr = { path = "../tari/base_layer/mmr" } #tari_p2p = { path = "../tari/base_layer/p2p" } #tari_shutdown = { path = "../tari/infrastructure/shutdown" } diff --git a/applications/tari_app_utilities/src/genesis_resources.rs b/applications/tari_app_utilities/src/genesis_resources.rs new file mode 100644 index 0000000000..090e6e30d7 --- /dev/null +++ b/applications/tari_app_utilities/src/genesis_resources.rs @@ -0,0 +1,54 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use tari_engine_types::resource::Resource; +use tari_ootle_common_types::Network; +use tari_template_lib::{ + auth::{OwnerRule, ResourceAccessRules}, + constants::PUBLIC_IDENTITY_RESOURCE_ADDRESS, + models::{Metadata, ResourceAddress}, + prelude::{ResourceType, STEALTH_TARI_RESOURCE_ADDRESS}, + resource::TOKEN_SYMBOL, + rule, +}; + +pub fn get_public_identity_resource() -> (ResourceAddress, Resource) { + let value = Resource::new( + ResourceType::NonFungible, + None, + OwnerRule::None, + ResourceAccessRules::new(), + Metadata::from([(TOKEN_SYMBOL, "ID".to_string())]), + None, + None, + 0, + false, + ); + (PUBLIC_IDENTITY_RESOURCE_ADDRESS, value) +} + +pub fn get_stealth_tari_resource(network: Network) -> (ResourceAddress, Resource) { + let symbol = if network.is_testnet() { "tXTR" } else { "XTR" }; + let xtr_resource = Resource::new( + ResourceType::Stealth, + None, + OwnerRule::None, + ResourceAccessRules::new() + // These are defaults, but just for explicitness + .mintable(rule!(deny_all)) + .burnable(rule!(deny_all)) + .recallable(rule!(deny_all)) + .freezable(rule!(deny_all)) + .update_access_rules(rule!(deny_all)), + Metadata::from([(TOKEN_SYMBOL, symbol)]), + None, + None, + 6, + // Disable total supply tracking for XTR. This is because it is not feasible to include "the fee exhaust" in + // the tracking (as that would require mutating the resource on every transaction). Tracking supply can + // be done by summing up the total burn claims (ClaimedOutputTombstone) and subtracting the total exhaust in + // fee receipts. + false, + ); + (STEALTH_TARI_RESOURCE_ADDRESS, xtr_resource) +} diff --git a/applications/tari_app_utilities/src/lib.rs b/applications/tari_app_utilities/src/lib.rs index 452012f21f..9fa5712be4 100644 --- a/applications/tari_app_utilities/src/lib.rs +++ b/applications/tari_app_utilities/src/lib.rs @@ -25,6 +25,7 @@ pub mod common; pub mod configuration; pub mod epoch_oracle_config; pub mod fee_tables; +pub mod genesis_resources; pub mod keypair; pub mod p2p_config; pub mod seed_peer; diff --git a/applications/tari_swarm_daemon/webui/vite.config.ts.timestamp-1712311434695-a58d35a3bc145.mjs b/applications/tari_swarm_daemon/webui/vite.config.ts.timestamp-1712311434695-a58d35a3bc145.mjs deleted file mode 100644 index 8ba26efc5e..0000000000 --- a/applications/tari_swarm_daemon/webui/vite.config.ts.timestamp-1712311434695-a58d35a3bc145.mjs +++ /dev/null @@ -1,10 +0,0 @@ -// vite.config.ts -import { defineConfig } from "file:///home/stan/tari/dan/applications/tari_swarm/webui/node_modules/vite/dist/node/index.js"; -import react from "file:///home/stan/tari/dan/applications/tari_swarm/webui/node_modules/@vitejs/plugin-react/dist/index.mjs"; -var vite_config_default = defineConfig({ - plugins: [react()] -}); -export { - vite_config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS9zdGFuL3RhcmkvZGFuL2FwcGxpY2F0aW9ucy90YXJpX3N3YXJtL3dlYnVpXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvaG9tZS9zdGFuL3RhcmkvZGFuL2FwcGxpY2F0aW9ucy90YXJpX3N3YXJtL3dlYnVpL3ZpdGUuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9ob21lL3N0YW4vdGFyaS9kYW4vYXBwbGljYXRpb25zL3Rhcmlfc3dhcm0vd2VidWkvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlJ1xuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xuXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcGx1Z2luczogW3JlYWN0KCldLFxufSlcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBcVUsU0FBUyxvQkFBb0I7QUFDbFcsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K diff --git a/applications/tari_validator_node/src/genesis_state.rs b/applications/tari_validator_node/src/genesis_state.rs index 549d3b22c9..2c021d16ff 100644 --- a/applications/tari_validator_node/src/genesis_state.rs +++ b/applications/tari_validator_node/src/genesis_state.rs @@ -12,7 +12,10 @@ use tari_engine_types::{ substate::{SubstateId, SubstateValue}, vault::Vault, }; -use tari_ootle_app_utilities::shared_consts::TXTR_FAUCET_INITIAL_SUPPLY; +use tari_ootle_app_utilities::{ + genesis_resources::{get_public_identity_resource, get_stealth_tari_resource}, + shared_consts::TXTR_FAUCET_INITIAL_SUPPLY, +}; use tari_ootle_common_types::{ Epoch, Network, @@ -69,41 +72,11 @@ where return Ok(()); } - let value = Resource::new( - ResourceType::NonFungible, - None, - OwnerRule::None, - ResourceAccessRules::new(), - Metadata::from([(TOKEN_SYMBOL, "ID".to_string())]), - None, - None, - 0, - false, - ); - create_substate(tx, num_preshards, PUBLIC_IDENTITY_RESOURCE_ADDRESS, value)?; + let (public_identity_address, resource) = get_public_identity_resource(); + create_substate(tx, num_preshards, public_identity_address, resource)?; - let symbol = if network.is_testnet() { "tXTR" } else { "XTR" }; - let xtr_resource = Resource::new( - ResourceType::Stealth, - None, - OwnerRule::None, - ResourceAccessRules::new() - // These are defaults, but just for explicitness - .mintable(rule!(deny_all)) - .burnable(rule!(deny_all)) - .recallable(rule!(deny_all)) - .freezable(rule!(deny_all)) - .update_access_rules(rule!(deny_all)), - Metadata::from([(TOKEN_SYMBOL, symbol)]), - None, - None, - 6, - // Disable total supply tracking for XTR. This is because it is not feasible to include "the fee exhaust" in - // the tracking (as that would require mutating the resource on every transaction). Tracking supply can - // be done by summing up the total burn claims (ClaimedOutputTombstone) and subtracting the total exhaust in - // fee receipts. - false, - ); + let (xtr_address, xtr_resource) = get_stealth_tari_resource(network); + create_substate(tx, num_preshards, xtr_address, xtr_resource)?; if network.is_testnet() { // Create tXTR faucet @@ -112,8 +85,6 @@ where create_nft_faucet(tx, num_preshards)?; } - create_substate(tx, num_preshards, STEALTH_TARI_RESOURCE_ADDRESS, xtr_resource)?; - Ok(()) } diff --git a/applications/tari_validator_node/web_ui/src/App.tsx b/applications/tari_validator_node/web_ui/src/App.tsx index 83e97ab3ad..ee572c34b3 100644 --- a/applications/tari_validator_node/web_ui/src/App.tsx +++ b/applications/tari_validator_node/web_ui/src/App.tsx @@ -27,7 +27,6 @@ import ValidatorNode from "./routes/VN/ValidatorNode"; import Connections from "./routes/Connections/Connections"; import Fees from "./routes/Fees/Fees"; import Blocks from "./routes/Blocks/Blocks"; -import Templates from "./routes/Templates/Templates"; import ValidatorNodes from "./routes/ValidatorNodes/ValidatorNodes"; import ErrorPage from "./routes/ErrorPage"; import TemplateFunctions from "./routes/VN/Components/TemplateFunctions"; @@ -89,11 +88,6 @@ export const breadcrumbRoutes = [ path: "/blocks/:blockId", dynamic: true, }, - { - label: "Templates", - path: "/templates", - dynamic: false, - }, { label: "Validator Nodes", path: "/vns", @@ -182,7 +176,6 @@ export default function App() { } /> } /> } /> - } /> } /> } /> } /> diff --git a/applications/tari_validator_node/web_ui/src/Components/MenuItems.tsx b/applications/tari_validator_node/web_ui/src/Components/MenuItems.tsx index f7aed9c65a..55d79ca1ff 100644 --- a/applications/tari_validator_node/web_ui/src/Components/MenuItems.tsx +++ b/applications/tari_validator_node/web_ui/src/Components/MenuItems.tsx @@ -94,12 +94,6 @@ const mainItems = [ activeIcon: , link: "mempool", }, - { - title: "Templates", - icon: , - activeIcon: , - link: "templates", - }, { title: "Validator Nodes", icon: , diff --git a/applications/tari_validator_node/web_ui/src/main.tsx b/applications/tari_validator_node/web_ui/src/main.tsx index c374613df0..5984d6988d 100644 --- a/applications/tari_validator_node/web_ui/src/main.tsx +++ b/applications/tari_validator_node/web_ui/src/main.tsx @@ -30,7 +30,6 @@ import Connections from "./routes/Connections/Connections"; import Fees from "./routes/Fees/Fees"; import Mempool from "./routes/Mempool/Mempool"; import Blocks from "./routes/Blocks/Blocks"; -import Templates from "./routes/Templates/Templates"; import ValidatorNodes from "./routes/ValidatorNodes/ValidatorNodes"; import ErrorPage from "./routes/ErrorPage"; import TemplateFunctions from "./routes/VN/Components/TemplateFunctions"; @@ -60,10 +59,6 @@ const router = createBrowserRouter([ path: "blocks/:blockId", element: , }, - { - path: "templates", - element: , - }, { path: "vns", element: , diff --git a/applications/tari_validator_node/web_ui/src/routes/Templates/Templates.tsx b/applications/tari_validator_node/web_ui/src/routes/Templates/Templates.tsx deleted file mode 100644 index bb78915e07..0000000000 --- a/applications/tari_validator_node/web_ui/src/routes/Templates/Templates.tsx +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2022. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import PageHeading from "../../Components/PageHeading"; -import Grid from "@mui/material/Grid"; -import { StyledPaper } from "../../Components/StyledComponents"; -import Templates from "../VN/Components/Templates"; - -function TemplatesLayout() { - return ( - <> - - Templates - - - - - - - - ); -} - -export default TemplatesLayout; diff --git a/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.css b/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.tsx b/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.tsx deleted file mode 100644 index 4c63f2b6e1..0000000000 --- a/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.tsx +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2022. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import { useEffect, useState } from "react"; -import { getTemplates } from "../../../utils/json_rpc"; -import { shortenString } from "./helpers"; -import "./Templates.css"; -import Table from "@mui/material/Table"; -import TableBody from "@mui/material/TableBody"; -import TableCell from "@mui/material/TableCell"; -import TableContainer from "@mui/material/TableContainer"; -import TableHead from "@mui/material/TableHead"; -import TableRow from "@mui/material/TableRow"; -import { BoxHeading2, DataTableCell } from "../../../Components/StyledComponents"; -import { Link } from "react-router-dom"; -import CopyToClipboard from "../../../Components/CopyToClipboard"; -import IconButton from "@mui/material/IconButton"; -import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight"; -import HeadingMenu from "../../../Components/HeadingMenu"; -import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; -import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; -import TablePagination from "@mui/material/TablePagination"; -import SearchFilter from "../../../Components/SearchFilter"; -import Typography from "@mui/material/Typography"; -import Fade from "@mui/material/Fade"; -import { emptyRows } from "../../../utils/helpers"; -import type { VNTemplateMetadata } from "@tari-project/typescript-bindings"; - -type ColumnKey = keyof VNTemplateMetadata; - -function Templates() { - const [templates, setTemplates] = useState([]); - const [lastSort, setLastSort] = useState({ column: "", order: -1 }); - - useEffect(() => { - // TODO: proper pagination with limit+offset. It would require changes in VN backend (and clients) to add the offset parameter - // for now, limit=0 makes the backend return all templates - getTemplates({ limit: 0 }).then((response) => { - setTemplates(response.templates.slice()); - }); - }, []); - - const sort = (column: ColumnKey, order: number) => { - // let order = 1; - // if (lastSort.column === column) { - // order = -lastSort.order; - // } - if (column) { - setTemplates( - [...templates].sort((r0, r1) => (r0[column] > r1[column] ? order : r0[column] < r1[column] ? -order : 0)), - ); - setLastSort({ column, order }); - } - }; - - const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(10); - - // Avoid a layout jump when reaching the last page with empty rows. - const emptyRowsCnt = emptyRows(page, rowsPerPage, templates); - - const handleChangePage = (_event: unknown, newPage: number) => { - setPage(newPage); - }; - - const handleChangeRowsPerPage = (event: React.ChangeEvent) => { - setRowsPerPage(parseInt(event.target.value, 10)); - setPage(0); - }; - - return ( - <> - - - row.address.toLowerCase().includes(value.toLowerCase()), - }, - ]} - placeholder="Search for Templates" - /> - - - - - - - sort("id" as ColumnKey, 1), - icon: , - }, - { - title: "Sort Descending", - fn: () => sort("id" as ColumnKey, -1), - icon: , - }, - ]} - showArrow - lastSort={lastSort} - columnName="id" - sortFunction={sort} - /> - - Name - Status - Functions - - - - {templates - .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) - .map(({ address, name }, i) => ( - - - - template_{shortenString(address)} - - - - {name} - Active - - - - - - - - - ))} - {templates.length === 0 && ( - - - - No results found - - - - )} - {emptyRowsCnt > 0 && ( - - - - )} - -
- -
- - ); -} - -export default Templates; diff --git a/applications/tari_validator_node/web_ui/src/routes/VN/ValidatorNode.tsx b/applications/tari_validator_node/web_ui/src/routes/VN/ValidatorNode.tsx index b72743350b..02f93359d0 100644 --- a/applications/tari_validator_node/web_ui/src/routes/VN/ValidatorNode.tsx +++ b/applications/tari_validator_node/web_ui/src/routes/VN/ValidatorNode.tsx @@ -28,7 +28,6 @@ import Fees from "./Components/Fees"; import Info from "./Components/Info"; import Mempool from "./Components/Mempool"; import Blocks from "./Components/Blocks"; -import Templates from "./Components/Templates"; import "./ValidatorNode.css"; import { StyledPaper } from "../../Components/StyledComponents"; import Grid from "@mui/material/Grid"; @@ -105,14 +104,6 @@ function ValidatorNode() { - - Templates - - - - - - VNs diff --git a/applications/tari_validator_node/web_ui/src/utils/json_rpc.tsx b/applications/tari_validator_node/web_ui/src/utils/json_rpc.tsx index c5867ce57b..632386f6a2 100644 --- a/applications/tari_validator_node/web_ui/src/utils/json_rpc.tsx +++ b/applications/tari_validator_node/web_ui/src/utils/json_rpc.tsx @@ -32,7 +32,6 @@ import type { GetBlocksResponse, GetCommitteeRequest, GetCommitteeResponse, - VNGetCommsStatsResponse, VNGetConnectionsResponse, GetEpochManagerStatsResponse, VNGetIdentityResponse, @@ -47,8 +46,6 @@ import type { VNGetSubstateResponse, GetTemplateRequest, GetTemplateResponse, - GetTemplatesRequest, - GetTemplatesResponse, GetTransactionRequest, GetTransactionResponse, VNGetTransactionResultRequest, @@ -125,8 +122,6 @@ export const getFilteredBlocksCount = (request: GetFilteredBlocksCountRequest): // Template export const getTemplate = (request: GetTemplateRequest): Promise => jsonRpc("get_template", request); -export const getTemplates = (request: GetTemplatesRequest): Promise => - jsonRpc("get_templates", request); // Validator Node export const getIdentity = (): Promise => jsonRpc("get_identity"); diff --git a/applications/tari_wallet_cli/src/command/transaction.rs b/applications/tari_wallet_cli/src/command/transaction.rs index 6ea26378c5..ac246c86d4 100644 --- a/applications/tari_wallet_cli/src/command/transaction.rs +++ b/applications/tari_wallet_cli/src/command/transaction.rs @@ -41,11 +41,7 @@ use tari_engine_types::{ }; use tari_ootle_address::OotleAddress; use tari_ootle_common_types::{Epoch, SubstateAddress, SubstateRequirement}; -use tari_ootle_wallet_sdk::{ - apis::confidential_transfer::UtxoInputSelection, - crypto::memo::Memo, - models::BranchAndKeyId, -}; +use tari_ootle_wallet_sdk::{apis::confidential_transfer::UtxoInputSelection, crypto::memo::Memo}; use tari_template_lib::{ constants::STEALTH_TARI_RESOURCE_ADDRESS, models::{BucketId, NonFungibleAddress, NonFungibleId}, @@ -283,7 +279,7 @@ pub async fn handle_submit(args: SubmitArgs, client: &mut WalletDaemonClient) -> let resp = client .submit_transaction_dry_run(TransactionSubmitDryRunRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: common.detect_inputs.unwrap_or(true), detect_inputs_use_unversioned: true, @@ -294,7 +290,7 @@ pub async fn handle_submit(args: SubmitArgs, client: &mut WalletDaemonClient) -> } else { let request = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: common.detect_inputs.unwrap_or(true), detect_inputs_use_unversioned: true, @@ -352,7 +348,7 @@ async fn handle_submit_manifest( let resp = client .submit_transaction_dry_run(TransactionSubmitDryRunRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: common.detect_inputs.unwrap_or(true), detect_inputs_use_unversioned: true, @@ -363,7 +359,7 @@ async fn handle_submit_manifest( } else { let request = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: common.detect_inputs.unwrap_or(true), detect_inputs_use_unversioned: true, diff --git a/applications/tari_walletd/src/handlers/accounts.rs b/applications/tari_walletd/src/handlers/accounts.rs index 2bd10e29ca..025f8b2edb 100644 --- a/applications/tari_walletd/src/handlers/accounts.rs +++ b/applications/tari_walletd/src/handlers/accounts.rs @@ -30,7 +30,7 @@ use tari_ootle_wallet_sdk::{ stealth_transfer::{StealthTransferParams, TransferOutput}, substate::ValidatorScanResult, }, - models::{BranchAndKeyId, KeyBranch, KeyId, NewAccountData, TransactionSubmittedEvent}, + models::{KeyBranch, NewAccountData, TransactionSubmittedEvent}, }; use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS; use tari_template_lib::{ @@ -483,9 +483,9 @@ pub async fn handle_claim_burn( } let (nonce, output_public_nonce) = RistrettoPublicKey::random_keypair(&mut OsRng); - let account_owner = sdk.key_manager_api().get_account_owner_key(account_owner_key_id)?; + let account_owner = sdk.key_manager_api().get_key(account_owner_key_id)?; let account_owner_public_key = account_owner.to_public_key(); - let view_only = sdk.key_manager_api().get_view_only_key(account.view_only_key_id())?; + let view_only = sdk.key_manager_api().get_key(account.view_only_key_id())?; let view_only_public_key = view_only.to_public_key(); let memo = Memo::new_message("Claimed burned XTR from L1").expect("valid memo"); // NOTE: the confidential encryption format and the bullet proofs currently do not support amounts larger than @@ -556,9 +556,7 @@ pub async fn handle_claim_burn( .add_input(XTR) .build(); - let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Nonce, public_signer_key.key_id, transaction)?; + let transaction = sdk.signer_api().sign(public_signer_key.key_id, transaction)?; let tx_id = context.transaction_service().submit_transaction(transaction).await?; @@ -661,9 +659,7 @@ pub async fn handle_create_free_test_coins( .with_inputs(inputs.into_iter().map(|input| input.into_unversioned())) .build(); - let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Account, account_owner_key_id, transaction)?; + let transaction = sdk.signer_api().sign(account_owner_key_id, transaction)?; info!( target: LOG_TARGET, @@ -853,9 +849,7 @@ pub async fn handle_transfer( .with_inputs(inputs.into_iter().map(|req| req.into_unversioned())) .build(); - let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Account, account_owner_key_id, transaction)?; + let transaction = sdk.signer_api().sign(account_owner_key_id, transaction)?; // If dry run we can return the result immediately if req.dry_run { @@ -1030,19 +1024,14 @@ pub async fn handle_stealth_transfer( let additional_sig = transfer .additional_signer .as_ref() - .map(|s| { - sdk.local_signer_api() - .get_signature(s.branch, s.key_id, &main_pk, &transaction) - }) + .map(|s| sdk.signer_api().get_signature(s.key_id, &main_pk, &transaction)) .transpose()? .map(|sig| TransactionSignature::new(sig.public_key.to_byte_type(), sig.signature.to_byte_type())); let transaction = transaction.build_with_signatures(additional_sig.into_iter().collect()); // Sign and seal the final transaction - let transaction = - sdk.local_signer_api() - .sign(transfer.main_signer.branch, transfer.main_signer.key_id, transaction)?; + let transaction = sdk.signer_api().sign(transfer.main_signer.key_id, transaction)?; if req.dry_run { // Release the lock immediately as dry run does not submit the transaction @@ -1139,16 +1128,13 @@ pub async fn handle_create_stealth_transfer_statement( .transpose()?; let must_sign_with_account_key = inputs.as_ref().is_some_and(|i| i.revealed.is_positive()); - let (signing_key_branch, signing_key_id) = if must_sign_with_account_key { - (KeyBranch::Account, sender_key_id) + let signing_key_id = if must_sign_with_account_key { + sender_key_id } else { - let next_index = sdk.key_manager_api().next_derived_key_index(KeyBranch::Nonce)?; - (KeyBranch::Nonce, KeyId::derived(next_index)) + sdk.key_manager_api().next_derived_key_id(KeyBranch::Nonce)?.into() }; - let required_signer = sdk - .key_manager_api() - .get_public_key(signing_key_branch, signing_key_id)?; + let required_signer = sdk.key_manager_api().get_public_key(signing_key_id)?; let required_signer = required_signer.public_key.to_byte_type(); let outputs = req @@ -1161,7 +1147,6 @@ pub async fn handle_create_stealth_transfer_statement( let statement = sdk .stealth_outputs_api() .generate_transfer_statement(TransferStatementParams { - spend_key_branch: KeyBranch::Account, spend_key_id: sender_key_id, view_only_key_id: sender_account.view_only_key_id(), resource_address: &req.resource_address, @@ -1185,7 +1170,7 @@ pub async fn handle_create_stealth_transfer_statement( required_signer, })?; - required_signers.insert(BranchAndKeyId::new(signing_key_branch, signing_key_id)); + required_signers.insert(signing_key_id); statements.push(statement); } diff --git a/applications/tari_walletd/src/handlers/confidential.rs b/applications/tari_walletd/src/handlers/confidential.rs index 027db14831..a606d6c08a 100644 --- a/applications/tari_walletd/src/handlers/confidential.rs +++ b/applications/tari_walletd/src/handlers/confidential.rs @@ -89,7 +89,7 @@ pub async fn handle_create_transfer_proof( // TODO: Any errors from here need to unlock the outputs, ideally just roll back (refactor required but doable). // TODO: Wrap up key/encrypted data handling in the wallet SDK - let account_key = sdk.key_manager_api().get_account_owner_key(account_owner_key_id)?; + let account_key = sdk.key_manager_api().get_key(account_owner_key_id)?; let output_mask = sdk.key_manager_api().next_key(KeyBranch::ConfidentialMask)?; let (_, public_nonce) = RistrettoPublicKey::random_keypair(&mut OsRng); diff --git a/applications/tari_walletd/src/handlers/helpers.rs b/applications/tari_walletd/src/handlers/helpers.rs index b1123be4db..a24e3f8b3d 100644 --- a/applications/tari_walletd/src/handlers/helpers.rs +++ b/applications/tari_walletd/src/handlers/helpers.rs @@ -4,16 +4,12 @@ use std::{collections::HashSet, fmt::Display}; use tari_engine_types::{component::derive_component_address_from_public_key, ToByteType}; -use tari_ootle_common_types::{ - optional::{IsNotFoundError, Optional}, - SubstateRequirement, -}; +use tari_ootle_common_types::{optional::Optional, SubstateRequirement}; use tari_ootle_wallet_sdk::{ apis::accounts::{AccountsApi, AccountsApiError}, models::{AccountWithAddress, DerivedKeyIndex, TransactionFinalizedEvent, WalletEvent}, - network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, WalletSdk, + WalletSdkSpec, }; use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS; use tari_template_lib::models::ComponentAddress; @@ -88,15 +84,10 @@ pub async fn wait_for_result_and_account( } } -pub fn get_account_with_inputs( +pub fn get_account_with_inputs( account: Option<&ComponentAddressOrName>, - sdk: &WalletSdk, -) -> Result<(AccountWithAddress, HashSet), anyhow::Error> -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, -{ + sdk: &WalletSdk, +) -> Result<(AccountWithAddress, HashSet), anyhow::Error> { let account = get_account_or_default(account, &sdk.accounts_api())?; let inputs = if account.is_confirmed_on_chain() { // Add all versioned account child addresses as inputs @@ -109,41 +100,30 @@ where Ok((account, inputs)) } -pub fn get_account( +pub fn get_account( account: &ComponentAddressOrName, - accounts_api: &AccountsApi<'_, TStore, TNetworkInterface>, -) -> Result -where - TStore: WalletStore, -{ + accounts_api: &AccountsApi<'_, TSpec>, +) -> Result { match account { ComponentAddressOrName::ComponentAddress(address) => Ok(accounts_api.get_account_by_address(address)?), ComponentAddressOrName::Name(name) => Ok(accounts_api.get_account_by_name(name)?), } } -pub(crate) fn get_account_by_key_index( - sdk: &WalletSdk, +pub(crate) fn get_account_by_key_index( + sdk: &WalletSdk, key_index: DerivedKeyIndex, -) -> Result -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, -{ +) -> Result { let key = sdk.key_manager_api().derive_account_address(key_index)?; let address = derive_component_address_from_public_key(&ACCOUNT_TEMPLATE_ADDRESS, &key.address.account_key().to_byte_type()); sdk.accounts_api().get_account_by_address(&address) } -pub fn get_account_or_default( +pub fn get_account_or_default( account: Option<&ComponentAddressOrName>, - accounts_api: &AccountsApi<'_, TStore, TNetworkInterface>, -) -> Result -where - TStore: WalletStore, -{ + accounts_api: &AccountsApi<'_, TSpec>, +) -> Result { let result; if let Some(a) = account { result = get_account(a, accounts_api) diff --git a/applications/tari_walletd/src/handlers/keys.rs b/applications/tari_walletd/src/handlers/keys.rs index 19df372857..3805ab5595 100644 --- a/applications/tari_walletd/src/handlers/keys.rs +++ b/applications/tari_walletd/src/handlers/keys.rs @@ -28,7 +28,7 @@ pub async fn handle_create( let key_manager = sdk.key_manager_api(); let key = req .specific_index - .map(|idx| key_manager.get_public_key(req.branch, KeyId::derived(idx))) + .map(|idx| key_manager.get_public_key(KeyId::derived(req.branch, idx))) .unwrap_or_else(|| key_manager.next_public_key(req.branch))?; Ok(KeysCreateResponse { id: key.key_id.derived_index().expect("Key is derived"), diff --git a/applications/tari_walletd/src/handlers/nfts.rs b/applications/tari_walletd/src/handlers/nfts.rs index eb6aa9c023..d3b764940e 100644 --- a/applications/tari_walletd/src/handlers/nfts.rs +++ b/applications/tari_walletd/src/handlers/nfts.rs @@ -13,7 +13,7 @@ use tari_engine_types::{ ToByteType, }; use tari_ootle_common_types::{optional::Optional, SubstateRequirement}; -use tari_ootle_wallet_sdk::{apis::substate::ValidatorScanResult, models::KeyBranch}; +use tari_ootle_wallet_sdk::apis::substate::ValidatorScanResult; use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS; use tari_template_lib::{ constants::{NFT_FAUCET_COMPONENT_ADDRESS, NFT_FAUCET_RESOURCE_ADDRESS}, @@ -121,9 +121,7 @@ pub async fn handle_mint_faucet( .add_input(NFT_FAUCET_RESOURCE_ADDRESS) .build(); - let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Account, account_owner_key_id, transaction)?; + let transaction = sdk.signer_api().sign(account_owner_key_id, transaction)?; let mut events = context.notifier().subscribe(); let tx_id = context.transaction_service().submit_transaction(transaction).await?; @@ -293,9 +291,7 @@ pub async fn handle_transfer( .call_method(target_account_address, "deposit", args![Workspace(format!("b-{i}"))]); } - let fee_owner_key = sdk - .key_manager_api() - .get_public_key(KeyBranch::Account, fee_payer_key_id)?; + let fee_owner_key = sdk.key_manager_api().get_public_key(fee_payer_key_id)?; let transaction = builder .with_dry_run(req.dry_run) @@ -304,8 +300,7 @@ pub async fn handle_transfer( // Seal signer is the fee payer account .with_authorized_seal_signer() .map(|builder| { - sdk.local_signer_api().sign_with_context( - KeyBranch::Account, + sdk.signer_api().sign_with_context( account_owner_key_id, &fee_owner_key.public_key().to_byte_type(), builder, @@ -313,9 +308,7 @@ pub async fn handle_transfer( })? .build(); - let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Account, account_owner_key_id, transaction)?; + let transaction = sdk.signer_api().sign(account_owner_key_id, transaction)?; // if dry run, we can return the result immediately if req.dry_run { diff --git a/applications/tari_walletd/src/handlers/transaction.rs b/applications/tari_walletd/src/handlers/transaction.rs index 1f45006200..cd802abb62 100644 --- a/applications/tari_walletd/src/handlers/transaction.rs +++ b/applications/tari_walletd/src/handlers/transaction.rs @@ -11,7 +11,7 @@ use tari_engine_types::ToByteType; use tari_ootle_common_types::{optional::Optional, Epoch, Network}; use tari_ootle_wallet_sdk::{ apis::{config::ConfigKey, transaction::TransactionApiError}, - models::{BranchAndKeyId, KeyBranch, WalletEvent}, + models::WalletEvent, network::WalletQueryErrorStatus, }; use tari_ootle_wallet_sdk_services::transaction_service::TransactionServiceError; @@ -93,7 +93,7 @@ pub async fn handle_submit_instruction( let request = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: req.override_inputs.unwrap_or_default(), detect_inputs_use_unversioned: true, @@ -153,16 +153,14 @@ pub async fn handle_submit( .with_unsigned_transaction(req.transaction) .with_inputs(detected_inputs); - let main_signer = sdk - .key_manager_api() - .get_public_key(req.seal_signer.branch, req.seal_signer.key_id)?; + let main_signer = sdk.key_manager_api().get_public_key(req.seal_signer)?; let main_signer_pk = main_signer.public_key.to_byte_type(); - let mut local_signer = sdk.local_signer_api(); - for key in &req.other_signers { - builder = local_signer.sign_with_context(key.branch, key.key_id, &main_signer_pk, builder)?; + let mut local_signer = sdk.signer_api(); + for key in req.other_signers { + builder = local_signer.sign_with_context(key, &main_signer_pk, builder)?; } - let transaction = local_signer.sign(req.seal_signer.branch, req.seal_signer.key_id, builder.build())?; + let transaction = local_signer.sign(req.seal_signer, builder.build())?; let tx_id = transaction.calculate_id(); for lock_id in req.lock_ids { @@ -219,7 +217,7 @@ pub async fn handle_submit_dry_run( let sdk = context.wallet_sdk(); let key_api = sdk.key_manager_api(); // Fetch the key to sign the transaction - let key = key_api.get_public_key(req.seal_signer.branch, req.seal_signer.key_id)?; + let key = key_api.get_public_key(req.seal_signer)?; let detected_inputs = if req.detect_inputs { // If we are not overriding inputs, we will use inputs that we know about in the local substate id db @@ -249,9 +247,7 @@ pub async fn handle_submit_dry_run( .with_inputs(detected_inputs) .with_dry_run(true) .build(); - let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Account, key.key_id, transaction)?; + let transaction = sdk.signer_api().sign(key.key_id, transaction)?; for lock_id in req.lock_ids { // update the proofs table with the corresponding transaction hash @@ -313,9 +309,7 @@ pub async fn handle_submit_manifest( })?; let signing_key_id = req.signing_key_id.unwrap_or(account_owner_key_id); - let key = sdk - .key_manager_api() - .get_key_or_active(KeyBranch::Account, Some(signing_key_id))?; + let key = sdk.key_manager_api().get_key(signing_key_id)?; let network = context.wallet_sdk().config_api().get::(ConfigKey::Network)?; @@ -335,12 +329,8 @@ pub async fn handle_submit_manifest( if signing_key_id == account_owner_key_id { Ok(builder) } else { - sdk.local_signer_api().sign_with_context( - KeyBranch::Account, - signing_key_id, - &key.public_key().to_byte_type(), - builder, - ) + sdk.signer_api() + .sign_with_context(signing_key_id, &key.to_public_key().to_byte_type(), builder) } })?; let signatures = builder.signatures().to_vec(); @@ -356,9 +346,7 @@ pub async fn handle_submit_manifest( .authorized_sealed_signer() .build_with_signatures(signatures); - let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Account, key.key_id, transaction)?; + let transaction = sdk.signer_api().sign(key.key_id, transaction)?; if req.dry_run { let exec_result = context @@ -559,7 +547,7 @@ pub async fn handle_publish_template( if req.dry_run { let request = TransactionSubmitDryRunRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: req.detect_inputs, detect_inputs_use_unversioned: true, @@ -581,7 +569,7 @@ pub async fn handle_publish_template( } let request = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: req.detect_inputs, detect_inputs_use_unversioned: true, diff --git a/applications/tari_walletd/src/handlers/validator.rs b/applications/tari_walletd/src/handlers/validator.rs index 2bdb1b3eea..a6201ebdca 100644 --- a/applications/tari_walletd/src/handlers/validator.rs +++ b/applications/tari_walletd/src/handlers/validator.rs @@ -49,10 +49,9 @@ pub async fn handle_get_validator_fees( let account_key_id = account.owner_key_id().ok_or_else(|| { anyhow!("The specified account does not have an associated owner key to derive the claim key from") })?; - sdk.key_manager_api() - .get_public_key(KeyBranch::Account, account_key_id)? + sdk.key_manager_api().get_public_key(account_key_id)? }, - AccountOrKeyId::KeyId(key_id) => sdk.key_manager_api().get_public_key(KeyBranch::Account, key_id)?, + AccountOrKeyId::KeyId(key_id) => sdk.key_manager_api().get_public_key(key_id)?, }; let claim_public_key = claim_key.public_key().to_byte_type(); @@ -121,7 +120,7 @@ pub async fn handle_claim_validator_fees( let claim_public_key = match req.claim_key_index { Some(index) => sdk .key_manager_api() - .get_public_key(KeyBranch::Account, KeyId::derived(index))? + .get_public_key(KeyId::derived(KeyBranch::Account, index))? .public_key .to_byte_type(), None => *account.address.account_public_key(), @@ -185,9 +184,8 @@ pub async fn handle_claim_validator_fees( Ok(builder) } else { // If the claim key is different from the account secret, we need to sign with both - sdk.local_signer_api().sign_with_context( - KeyBranch::Account, - KeyId::derived(index), + sdk.signer_api().sign_with_context( + KeyId::derived(KeyBranch::Account, index), account.address.account_public_key(), builder.with_authorized_seal_signer(), ) @@ -198,9 +196,7 @@ pub async fn handle_claim_validator_fees( })? .build(); - let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Account, account_key_id, unsigned_transaction)?; + let transaction = sdk.signer_api().sign(account_key_id, unsigned_transaction)?; // send the transaction if req.dry_run { diff --git a/applications/tari_walletd/src/lib.rs b/applications/tari_walletd/src/lib.rs index f871b8071d..907fb86739 100644 --- a/applications/tari_walletd/src/lib.rs +++ b/applications/tari_walletd/src/lib.rs @@ -33,13 +33,16 @@ use std::{fs, panic, pin, process}; use log::*; use tari_common_types::seeds::seed_words::SeedWords; +use tari_ootle_app_utilities::genesis_resources::{get_public_identity_resource, get_stealth_tari_resource}; use tari_ootle_common_types::{optional::Optional, Network, NumPreshards}; use tari_ootle_wallet_sdk::{ apis::config::{ConfigApi, ConfigKey}, cipher_seed::CipherSeedRestore, + local_key_store::LocalKeyStore, models::EpochBirthday, WalletSdk as Sdk, WalletSdkConfig, + WalletSdkSpec, }; use tari_ootle_wallet_sdk_services::{ account_recovery::AccountRecoveryService, @@ -48,7 +51,6 @@ use tari_ootle_wallet_sdk_services::{ }; use tari_ootle_wallet_storage_sqlite::SqliteWalletStore; use tari_shutdown::ShutdownSignal; -use tari_template_lib::constants::XTR; use crate::{ config::ApplicationConfig, @@ -62,7 +64,15 @@ const DEFAULT_FEE: u64 = 1500; // TODO: must match the global network value. All testnets currently have 256 pre-shards. const NUM_PRESHARDS: NumPreshards = NumPreshards::current(); -pub type WalletSdk = Sdk; +pub struct OotleWalletDaemonSpec; + +impl WalletSdkSpec for OotleWalletDaemonSpec { + type KeyStore = LocalKeyStore; + type NetworkInterface = IndexerRestApiNetworkInterface; + type Store = SqliteWalletStore; +} + +pub type WalletSdk = Sdk; pub async fn run_tari_ootle_walletd( config: ApplicationConfig, @@ -73,20 +83,16 @@ pub async fn run_tari_ootle_walletd( // console_subscriber::init(); let wallet_store = init_wallet_store(&config)?; - let mut wallet_sdk = initialize_wallet_sdk(&config, wallet_store.clone())?; + let mut wallet_sdk: WalletSdk = initialize_wallet_sdk(&config, wallet_store.clone())?; let needs_seed_recovery = wallet_sdk.initialize_cipher_seed(seed_words.map(CipherSeedRestore::FromSeedWords).unwrap_or_default())?; - tokio::spawn({ - let wallet_sdk = wallet_sdk.clone(); - async move { - // Ensures that the XTR resource is available in the substate cache - if let Err(err) = wallet_sdk.substate_api().fetch_resource(XTR).await { - error!(target: LOG_TARGET, "Failed to fetch XTR resource: {}", err); - } - } - }); + // Insert genesis resources + let (xtr_addr, xtr_resx) = get_stealth_tari_resource(wallet_sdk.network()); + wallet_sdk.resources_api().upsert_resource(&xtr_addr, &xtr_resx)?; + let (addr, resx) = get_public_identity_resource(); + wallet_sdk.resources_api().upsert_resource(&addr, &resx)?; let notify = Notify::new(100); let services = spawn_services(shutdown_signal.clone(), notify.clone(), wallet_sdk.clone()); @@ -197,7 +203,7 @@ pub fn initialize_wallet_sdk(config: &ApplicationConfig, store: SqliteWalletStor }; let indexer = IndexerRestApiNetworkInterface::new(indexer_endpoint); let birthday = get_epoch_birthday(sdk_config.network); - let sdk = WalletSdk::initialize(store, indexer, sdk_config, birthday)?; + let sdk = WalletSdk::initialize_with_local_key_store(store, indexer, sdk_config, birthday)?; Ok(sdk) } diff --git a/applications/tari_walletd/src/main.rs b/applications/tari_walletd/src/main.rs index 83ef9923dc..8bc7527840 100644 --- a/applications/tari_walletd/src/main.rs +++ b/applications/tari_walletd/src/main.rs @@ -109,7 +109,7 @@ async fn main() -> Result<(), anyhow::Error> { } } - let view_only_secret = km.get_view_only_key(account_address.view_only_key_id)?; + let view_only_secret = km.get_key(account_address.view_only_key_id)?; let json = json!({ "component_address": account_addr, diff --git a/applications/tari_walletd/src/services/mod.rs b/applications/tari_walletd/src/services/mod.rs index a90bf5b668..b72f5018ce 100644 --- a/applications/tari_walletd/src/services/mod.rs +++ b/applications/tari_walletd/src/services/mod.rs @@ -13,13 +13,7 @@ mod template_monitor; use anyhow::anyhow; use futures::{future, future::BoxFuture, FutureExt}; pub use session_store::*; -use tari_ootle_common_types::optional::IsNotFoundError; -use tari_ootle_wallet_sdk::{ - models::WalletEvent, - network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, - WalletSdk, -}; +use tari_ootle_wallet_sdk::{models::WalletEvent, WalletSdk}; use tari_ootle_wallet_sdk_services::{ account_monitor::{AccountMonitor, AccountMonitorHandle}, notify::Notify, @@ -29,18 +23,13 @@ use tari_ootle_wallet_sdk_services::{ use tari_shutdown::ShutdownSignal; use tokio::task::JoinHandle; -use crate::services::template_monitor::TemplateMonitor; +use crate::{services::template_monitor::TemplateMonitor, OotleWalletDaemonSpec}; -pub fn spawn_services( +pub fn spawn_services( shutdown_signal: ShutdownSignal, notify: Notify, - wallet_sdk: WalletSdk, -) -> Services -where - TStore: WalletStore + Clone + Send + Sync + 'static, - TNetworkInterface: WalletNetworkInterface + Clone + Send + Sync + 'static, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, -{ + wallet_sdk: WalletSdk, +) -> Services { let (transaction_service, transaction_service_handle) = TransactionService::new(notify.clone(), wallet_sdk.clone(), shutdown_signal.clone()); let transaction_service_join_handle = tokio::spawn(transaction_service.run()); diff --git a/applications/tari_walletd/src/services/template_monitor.rs b/applications/tari_walletd/src/services/template_monitor.rs index 9e617dc770..7edead4477 100644 --- a/applications/tari_walletd/src/services/template_monitor.rs +++ b/applications/tari_walletd/src/services/template_monitor.rs @@ -5,16 +5,8 @@ use std::{ops::Add, time::Duration}; use anyhow::anyhow; use log::*; -use tari_ootle_common_types::{ - optional::{IsNotFoundError, Optional}, - substate_type::SubstateType, -}; -use tari_ootle_wallet_sdk::{ - models::WalletEvent, - network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, - WalletSdk, -}; +use tari_ootle_common_types::{optional::Optional, substate_type::SubstateType}; +use tari_ootle_wallet_sdk::{models::WalletEvent, network::WalletNetworkInterface, WalletSdk, WalletSdkSpec}; use tari_ootle_wallet_sdk_services::notify::Notify; use tari_shutdown::ShutdownSignal; use tari_template_abi::TemplateDef; @@ -22,23 +14,16 @@ use tari_template_lib::types::TemplateAddress; const LOG_TARGET: &str = "tari::ootle_wallet_daemon::services::template_monitor"; -pub struct TemplateMonitor { +pub struct TemplateMonitor { notify: Notify, - wallet_sdk: WalletSdk, + wallet_sdk: WalletSdk, shutdown_signal: ShutdownSignal, } -impl TemplateMonitor -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, +impl TemplateMonitor +where TSpec: WalletSdkSpec { - pub fn new( - notify: Notify, - wallet_sdk: WalletSdk, - shutdown_signal: ShutdownSignal, - ) -> Self { + pub fn new(notify: Notify, wallet_sdk: WalletSdk, shutdown_signal: ShutdownSignal) -> Self { Self { notify, wallet_sdk, diff --git a/applications/tari_walletd/web_ui/src/routes/AssetVault/Components/ClaimFees.tsx b/applications/tari_walletd/web_ui/src/routes/AssetVault/Components/ClaimFees.tsx index 1e28356be7..3dbb736f47 100644 --- a/applications/tari_walletd/web_ui/src/routes/AssetVault/Components/ClaimFees.tsx +++ b/applications/tari_walletd/web_ui/src/routes/AssetVault/Components/ClaimFees.tsx @@ -95,7 +95,7 @@ export default function ClaimFees() { return; } const selected_account = dataAccountsList?.accounts.find((account: AccountInfo) => - matchesTypeEnum(account.account.owner_key_id, { Derived: { index: BigInt(keyIndex) } }), + matchesTypeEnum(account.account.owner_key_id, { Derived: { key_branch: "account", index: BigInt(keyIndex) } }), ); const account = selected_account?.account.component_address ? substateIdToString(selected_account!.account.component_address) @@ -188,7 +188,7 @@ export default function ClaimFees() { setIsLoading(true); try { const fees = await validatorsGetFees({ - account_or_key: { KeyId: { Derived: { index: BigInt(formState.keyIndex) } } }, + account_or_key: { KeyId: { Derived: { key_branch: "account", index: BigInt(formState.keyIndex) } } }, shard_group: null, }); setScannedFees(fees); diff --git a/applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx b/applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx index 4ef860cc16..74599b6983 100644 --- a/applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx +++ b/applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx @@ -69,7 +69,6 @@ import { ACCOUNT_TEMPLATE_ADDRESS, TESTNET_NFT_FAUCET_ADDRESS, TESTNET_XTR_FAUCET_ADDRESS, - KeyBranch, } from "@tari-project/typescript-bindings"; import { settingsGet, submitTransactionDryRun, transactionsSubmit, transactionsWaitResult } from "@utils/json_rpc"; import { useAccountsList } from "@api/hooks/useAccounts"; @@ -213,7 +212,7 @@ function FlowEditor() { } const request = { transaction: { V1: transaction }, - seal_signer: { branch: "account" as KeyBranch, key_id: account.account.owner_key_id! }, + seal_signer: account.account.owner_key_id!, other_signers: [], detect_inputs: true, detect_inputs_use_unversioned: true, diff --git a/bindings/package.json b/bindings/package.json index 9628a2fa0e..abf7b79e21 100644 --- a/bindings/package.json +++ b/bindings/package.json @@ -1,6 +1,6 @@ { "name": "@tari-project/typescript-bindings", - "version": "1.21.0", + "version": "1.22.0", "description": "TypeScript types synchronized to the Tari Ootle Rust codebase", "homepage": "https://github.com/tari-project/tari-ootle#readme", "bugs": { diff --git a/bindings/src/index.ts b/bindings/src/index.ts index 2c52903d1c..5f38549c8d 100644 --- a/bindings/src/index.ts +++ b/bindings/src/index.ts @@ -68,7 +68,6 @@ export * from "./types/Memo"; export * from "./types/Metadata"; export * from "./types/MinotariBurnClaimProof"; export * from "./types/Network"; -export * from "./types/NewAccountData"; export * from "./types/NodeHeight"; export * from "./types/NonFungibleAddressContents"; export * from "./types/NonFungibleAddress"; diff --git a/bindings/src/types/Instruction.ts b/bindings/src/types/Instruction.ts index d261ed4446..838bf4d0c9 100644 --- a/bindings/src/types/Instruction.ts +++ b/bindings/src/types/Instruction.ts @@ -33,7 +33,7 @@ export type Instruction = | "DropAllProofsInWorkspace" | { AssertBucketContains: { key: WorkspaceOffsetId; resource_address: ResourceAddress; min_amount: Amount } } | { TakeFromBucket: { input_bucket: WorkspaceOffsetId; amount: Amount; output_bucket: number } } - | { PublishTemplate: { binary: Array } } + | { PublishTemplate: { binary: string } } | { AllocateAddress: { allocatable_type: AllocatableAddressType; workspace_id: number } } | { StealthTransfer: { diff --git a/bindings/src/types/PublishedTemplate.ts b/bindings/src/types/PublishedTemplate.ts index 9d6f226707..6b0d694ee3 100644 --- a/bindings/src/types/PublishedTemplate.ts +++ b/bindings/src/types/PublishedTemplate.ts @@ -1,3 +1,16 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type PublishedTemplate = { author: string; binary_hash: string }; +export type PublishedTemplate = { + /** + * Author's public key + */ + author: string; + /** + * Binary of the template + */ + binary: string; + /** + * Epoch at which the template was published + */ + at_epoch: bigint; +}; diff --git a/bindings/src/types/WalletTransaction.ts b/bindings/src/types/WalletTransaction.ts index 11d095d237..83986e03fa 100644 --- a/bindings/src/types/WalletTransaction.ts +++ b/bindings/src/types/WalletTransaction.ts @@ -1,9 +1,9 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { FinalizeResult } from "./FinalizeResult"; -import type { NewAccountData } from "./NewAccountData"; import type { ProposalCertificate } from "./ProposalCertificate"; import type { Transaction } from "./Transaction"; import type { TransactionStatus } from "./TransactionStatus"; +import type { NewAccountData } from "./wallet-daemon-client/NewAccountData"; export type WalletTransaction = { id: string; diff --git a/bindings/src/types/tari-indexer-client/GetTemplateDefinitionResponse.ts b/bindings/src/types/tari-indexer-client/GetTemplateDefinitionResponse.ts index 7f958bba3d..bdce9c49f5 100644 --- a/bindings/src/types/tari-indexer-client/GetTemplateDefinitionResponse.ts +++ b/bindings/src/types/tari-indexer-client/GetTemplateDefinitionResponse.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { TemplateDef } from "../TemplateDef"; -export type GetTemplateDefinitionResponse = { name: string; definition: TemplateDef }; +export type GetTemplateDefinitionResponse = { name: string; definition: TemplateDef; code_size: number }; diff --git a/bindings/src/types/tari-indexer-client/IndexerGetEpochManagerStatsResponse.ts b/bindings/src/types/tari-indexer-client/IndexerGetEpochManagerStatsResponse.ts index 07cdb21447..0e5f7aa3b7 100644 --- a/bindings/src/types/tari-indexer-client/IndexerGetEpochManagerStatsResponse.ts +++ b/bindings/src/types/tari-indexer-client/IndexerGetEpochManagerStatsResponse.ts @@ -4,5 +4,5 @@ import type { Epoch } from "../Epoch"; export type IndexerGetEpochManagerStatsResponse = { current_epoch: Epoch; current_block_height: number; - current_block_hash: number[]; + current_block_hash: string; }; diff --git a/bindings/src/types/tari-indexer-client/IndexerGetIdentityResponse.ts b/bindings/src/types/tari-indexer-client/IndexerGetIdentityResponse.ts index 99db681649..cd3d5752fb 100644 --- a/bindings/src/types/tari-indexer-client/IndexerGetIdentityResponse.ts +++ b/bindings/src/types/tari-indexer-client/IndexerGetIdentityResponse.ts @@ -4,5 +4,5 @@ import type { RistrettoPublicKeyBytes } from "../RistrettoPublicKeyBytes"; export type IndexerGetIdentityResponse = { peer_id: string; public_key: RistrettoPublicKeyBytes; - public_addresses: Array; + public_addresses: string[]; }; diff --git a/bindings/src/types/tari-indexer-client/TemplateMetadata.ts b/bindings/src/types/tari-indexer-client/TemplateMetadata.ts index 47638dcf4a..b4cf3cb186 100644 --- a/bindings/src/types/tari-indexer-client/TemplateMetadata.ts +++ b/bindings/src/types/tari-indexer-client/TemplateMetadata.ts @@ -1,11 +1,13 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Epoch } from "../Epoch"; import type { Hash } from "../Hash"; +import type { RistrettoPublicKeyBytes } from "../RistrettoPublicKeyBytes"; export type TemplateMetadata = { name: string; address: Hash; - /** - * SHA hash of binary - */ - binary_sha: number[]; + binary_sha: string; + author_public_key: RistrettoPublicKeyBytes; + code_size: number; + epoch: Epoch; }; diff --git a/bindings/src/types/validator-node-client/GetTemplateResponse.ts b/bindings/src/types/validator-node-client/GetTemplateResponse.ts index 700fe8be74..cab263bcfb 100644 --- a/bindings/src/types/validator-node-client/GetTemplateResponse.ts +++ b/bindings/src/types/validator-node-client/GetTemplateResponse.ts @@ -2,4 +2,4 @@ import type { TemplateAbi } from "./TemplateAbi"; import type { VNTemplateMetadata } from "./VNTemplateMetadata"; -export type GetTemplateResponse = { registration_metadata: VNTemplateMetadata; abi: TemplateAbi }; +export type GetTemplateResponse = { metadata: VNTemplateMetadata; abi: TemplateAbi }; diff --git a/bindings/src/types/validator-node-client/GetTemplatesRequest.ts b/bindings/src/types/validator-node-client/GetTemplatesRequest.ts deleted file mode 100644 index ab11795aea..0000000000 --- a/bindings/src/types/validator-node-client/GetTemplatesRequest.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. - -export type GetTemplatesRequest = { limit: number }; diff --git a/bindings/src/types/validator-node-client/GetTemplatesResponse.ts b/bindings/src/types/validator-node-client/GetTemplatesResponse.ts deleted file mode 100644 index cea9ab233b..0000000000 --- a/bindings/src/types/validator-node-client/GetTemplatesResponse.ts +++ /dev/null @@ -1,4 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { VNTemplateMetadata } from "./VNTemplateMetadata"; - -export type GetTemplatesResponse = { templates: Array }; diff --git a/bindings/src/types/validator-node-client/VNTemplateMetadata.ts b/bindings/src/types/validator-node-client/VNTemplateMetadata.ts index b45411c2b2..bdb3395e65 100644 --- a/bindings/src/types/validator-node-client/VNTemplateMetadata.ts +++ b/bindings/src/types/validator-node-client/VNTemplateMetadata.ts @@ -1,11 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Hash } from "../Hash"; +import type { RistrettoPublicKeyBytes } from "../RistrettoPublicKeyBytes"; -export type VNTemplateMetadata = { - name: string; - address: Hash; - /** - * SHA hash of binary - */ - binary_sha: Array; -}; +export type VNTemplateMetadata = { name: string; address: Hash; code_size: number; author: RistrettoPublicKeyBytes }; diff --git a/bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts b/bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts index dc1f0558fe..ecce9d6f84 100644 --- a/bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts +++ b/bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts @@ -1,9 +1,9 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { StealthTransferStatement } from "../StealthTransferStatement"; -import type { BranchAndKeyId } from "./BranchAndKeyId"; +import type { KeyId } from "./KeyId"; export type AccountsCreateStealthTransferStatementResponse = { statements: Array; lock_id: number; - signing_keys: Array; + signing_keys: Array; }; diff --git a/bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts b/bindings/src/types/wallet-daemon-client/DerivedKeyId.ts similarity index 59% rename from bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts rename to bindings/src/types/wallet-daemon-client/DerivedKeyId.ts index ff8f22eb86..5b798a574e 100644 --- a/bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts +++ b/bindings/src/types/wallet-daemon-client/DerivedKeyId.ts @@ -1,5 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { KeyBranch } from "./KeyBranch"; -import type { KeyId } from "./KeyId"; -export type BranchAndKeyId = { branch: KeyBranch; key_id: KeyId }; +export type DerivedKeyId = { branch: KeyBranch; index: bigint }; diff --git a/bindings/src/types/wallet-daemon-client/KeyId.ts b/bindings/src/types/wallet-daemon-client/KeyId.ts index 178fa00a3d..8d984be194 100644 --- a/bindings/src/types/wallet-daemon-client/KeyId.ts +++ b/bindings/src/types/wallet-daemon-client/KeyId.ts @@ -1,3 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { KeyBranch } from "./KeyBranch"; -export type KeyId = { Derived: { index: bigint } } | { Imported: { local_key_id: bigint } }; +export type KeyId = { Derived: { key_branch: KeyBranch; index: bigint } } | { Imported: { local_key_id: bigint } }; diff --git a/bindings/src/types/NewAccountData.ts b/bindings/src/types/wallet-daemon-client/NewAccountData.ts similarity index 73% rename from bindings/src/types/NewAccountData.ts rename to bindings/src/types/wallet-daemon-client/NewAccountData.ts index d04133d9c3..1cc573c17c 100644 --- a/bindings/src/types/NewAccountData.ts +++ b/bindings/src/types/wallet-daemon-client/NewAccountData.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ComponentAddress } from "./ComponentAddress"; +import type { ComponentAddress } from "../ComponentAddress"; export type NewAccountData = { address: ComponentAddress }; diff --git a/bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts b/bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts index 89adbe83f7..b4c37a2bdd 100644 --- a/bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts +++ b/bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts @@ -1,11 +1,11 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { UnsignedTransaction } from "../UnsignedTransaction"; -import type { BranchAndKeyId } from "./BranchAndKeyId"; +import type { KeyId } from "./KeyId"; export type TransactionSubmitRequest = { transaction: UnsignedTransaction; - seal_signer: BranchAndKeyId; - other_signers: Array; + seal_signer: KeyId; + other_signers: Array; /** * Attempt to infer inputs and their dependencies from instructions. If false, the provided transaction must * contain the required inputs. diff --git a/bindings/src/validator-node-client.ts b/bindings/src/validator-node-client.ts index 929dc000be..370fba83f0 100644 --- a/bindings/src/validator-node-client.ts +++ b/bindings/src/validator-node-client.ts @@ -13,7 +13,6 @@ export * from "./types/validator-node-client/GetTemplateResponse"; export * from "./types/validator-node-client/GetBlocksCountResponse"; export * from "./types/validator-node-client/VNConnectionDirection"; export * from "./types/validator-node-client/VNAddPeerRequest"; -export * from "./types/validator-node-client/GetTemplatesResponse"; export * from "./types/validator-node-client/PrepareLayerOneTransactionResponse"; export * from "./types/validator-node-client/GetTransactionRequest"; export * from "./types/validator-node-client/GetStateRequest"; @@ -52,7 +51,6 @@ export * from "./types/validator-node-client/GetNetworkCommitteeResponse"; export * from "./types/validator-node-client/VNGetSubstateRequest"; export * from "./types/validator-node-client/GetMempoolStatsResponse"; export * from "./types/validator-node-client/TemplateAbi"; -export * from "./types/validator-node-client/GetTemplatesRequest"; export * from "./types/validator-node-client/VNGetSubstateResponse"; export * from "./types/validator-node-client/VNGetAllVnsResponse"; export * from "./types/validator-node-client/GetEpochManagerStatsResponse"; diff --git a/bindings/src/wallet-daemon-client.ts b/bindings/src/wallet-daemon-client.ts index cd80687a16..3142c9fd01 100644 --- a/bindings/src/wallet-daemon-client.ts +++ b/bindings/src/wallet-daemon-client.ts @@ -47,6 +47,7 @@ export * from "./types/wallet-daemon-client/WebauthnStartRegisterRequest"; export * from "./types/wallet-daemon-client/FeePoolDetails"; export * from "./types/wallet-daemon-client/AccountsTransferRequest"; export * from "./types/wallet-daemon-client/AccountOrKeyId"; +export * from "./types/wallet-daemon-client/DerivedKeyId"; export * from "./types/wallet-daemon-client/SettingsSetResponse"; export * from "./types/wallet-daemon-client/WebauthnFinishAuthRequest"; export * from "./types/wallet-daemon-client/KeysListRequest"; @@ -80,7 +81,6 @@ export * from "./types/wallet-daemon-client/AccountsCreateRequest"; export * from "./types/wallet-daemon-client/TransactionClaimBurnResponse"; export * from "./types/wallet-daemon-client/TransactionWaitResultRequest"; export * from "./types/wallet-daemon-client/ClaimValidatorFeesResponse"; -export * from "./types/wallet-daemon-client/BranchAndKeyId"; export * from "./types/wallet-daemon-client/ConfidentialCreateOutputProofRequest"; export * from "./types/wallet-daemon-client/KeysCreateRequest"; export * from "./types/wallet-daemon-client/WebauthnStartAuthRequest"; @@ -124,6 +124,7 @@ export * from "./types/wallet-daemon-client/TransferNftRequest"; export * from "./types/wallet-daemon-client/KeysSetActiveResponse"; export * from "./types/wallet-daemon-client/ComponentAddressOrName"; export * from "./types/wallet-daemon-client/AuthGetMethodRequest"; +export * from "./types/wallet-daemon-client/NewAccountData"; export * from "./types/wallet-daemon-client/AuthLoginAcceptRequest"; export * from "./types/wallet-daemon-client/KeysSetActiveRequest"; export * from "./types/wallet-daemon-client/ConfidentialViewVaultBalanceRequest"; diff --git a/clients/wallet_daemon_client/src/types.rs b/clients/wallet_daemon_client/src/types.rs index 99936ef34e..c584472494 100644 --- a/clients/wallet_daemon_client/src/types.rs +++ b/clients/wallet_daemon_client/src/types.rs @@ -47,7 +47,6 @@ use tari_ootle_wallet_sdk::{ models::{ Account, AuthoredTemplateModel, - BranchAndKeyId, DerivedKeyIndex, KeyBranch, KeyId, @@ -119,8 +118,8 @@ pub struct CallInstructionRequest { #[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionSubmitRequest { pub transaction: UnsignedTransaction, - pub seal_signer: BranchAndKeyId, - pub other_signers: Vec, + pub seal_signer: KeyId, + pub other_signers: Vec, /// Attempt to infer inputs and their dependencies from instructions. If false, the provided transaction must /// contain the required inputs. pub detect_inputs: bool, @@ -1110,7 +1109,7 @@ impl InputSelection { pub struct AccountsCreateStealthTransferStatementResponse { pub statements: Vec, pub lock_id: WalletLockId, - pub signing_keys: Vec, + pub signing_keys: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/crates/common_types/src/network.rs b/crates/common_types/src/network.rs index 7495783bda..6796d37419 100644 --- a/crates/common_types/src/network.rs +++ b/crates/common_types/src/network.rs @@ -47,7 +47,7 @@ pub enum Network { } impl Network { - pub fn as_byte(self) -> u8 { + pub const fn as_byte(self) -> u8 { self as u8 } @@ -64,7 +64,7 @@ impl Network { } } - pub fn is_testnet(&self) -> bool { + pub const fn is_testnet(&self) -> bool { !matches!(self, Network::MainNet) } } diff --git a/crates/engine_types/src/resource.rs b/crates/engine_types/src/resource.rs index 3637a65ea1..e3060cc06e 100644 --- a/crates/engine_types/src/resource.rs +++ b/crates/engine_types/src/resource.rs @@ -49,7 +49,7 @@ pub struct Resource { } impl Resource { - pub fn new( + pub const fn new( resource_type: ResourceType, owner_key: Option, owner_rule: OwnerRule, @@ -71,7 +71,11 @@ impl Resource { owner_key, access_rules, metadata, - total_supply: Some(0.into()).filter(|_| is_total_supply_tracking_enabled), + total_supply: if is_total_supply_tracking_enabled { + Some(Amount::zero()) + } else { + None + }, divisibility, view_key, auth_hook, diff --git a/crates/template_lib/src/auth/access_rules.rs b/crates/template_lib/src/auth/access_rules.rs index 1a3b6c7b81..e70b5148f9 100644 --- a/crates/template_lib/src/auth/access_rules.rs +++ b/crates/template_lib/src/auth/access_rules.rs @@ -221,7 +221,7 @@ impl ResourceAccessRules { /// * Updating the access rules is disabled for all users (i.e. only the OwnerRule applies) /// * Minting, burning, recalling and freezing are disabled for all users /// * Withdrawals, deposits and non-fungible data updates are allowed for all users - pub fn new() -> Self { + pub const fn new() -> Self { Self { // User should explicitly enable minting, burning etc mintable: AccessRule::DenyAll, diff --git a/crates/template_lib_types/src/resource_type.rs b/crates/template_lib_types/src/resource_type.rs index a798fd6ed4..c346e078d5 100644 --- a/crates/template_lib_types/src/resource_type.rs +++ b/crates/template_lib_types/src/resource_type.rs @@ -35,22 +35,22 @@ pub enum ResourceType { impl ResourceType { /// Returns `true` if the resource type is fungible, otherwise `false`. - pub fn is_public_fungible(&self) -> bool { + pub const fn is_public_fungible(&self) -> bool { matches!(self, Self::Fungible) } /// Returns `true` if the resource type is non-fungible, otherwise `false`. - pub fn is_non_fungible(&self) -> bool { + pub const fn is_non_fungible(&self) -> bool { matches!(self, Self::NonFungible) } /// Returns `true` if the resource type is confidential fungible, otherwise `false`. - pub fn is_confidential(&self) -> bool { + pub const fn is_confidential(&self) -> bool { matches!(self, Self::Confidential) } /// Returns `true` if the resource type is stealth, otherwise `false`. - pub fn is_stealth(&self) -> bool { + pub const fn is_stealth(&self) -> bool { matches!(self, Self::Stealth) } } diff --git a/crates/wallet/sdk/Cargo.toml b/crates/wallet/sdk/Cargo.toml index d955ac7104..64f23ad5f3 100644 --- a/crates/wallet/sdk/Cargo.toml +++ b/crates/wallet/sdk/Cargo.toml @@ -16,11 +16,11 @@ tari_ootle_common_types = { workspace = true } tari_ootle_wallet_crypto = { workspace = true, features = ["serde"] } tari_template_builtin = { workspace = true } tari_consensus_types = { workspace = true } -tari_transaction_components = { workspace = true } tari_transaction = { workspace = true } tari_template_lib = { workspace = true } tari_template_abi = { workspace = true } tari_ootle_address = { workspace = true, features = ["serde"] } +tari_hashing = { workspace = true } anyhow = { workspace = true } blake2 = { workspace = true } @@ -33,11 +33,13 @@ thiserror = { workspace = true } ts-rs = { workspace = true, optional = true } webauthn-rs = { workspace = true } keyring = { version = "3.6.3", features = ["apple-native", "windows-native", "sync-secret-service"] } +rand = { workspace = true } passwords = "3.1.16" zeroize = { workspace = true, features = ["serde", "simd"] } tokio = { workspace = true, default-features = false, features = ["sync", "rt-multi-thread"] } [dev-dependencies] +tari_transaction_components = { workspace = true } tari_ootle_wallet_storage_sqlite = { workspace = true } tempfile = { workspace = true } diff --git a/crates/wallet/sdk/src/apis/accounts.rs b/crates/wallet/sdk/src/apis/accounts.rs index 6a29bd710f..c5bfc6a4ad 100644 --- a/crates/wallet/sdk/src/apis/accounts.rs +++ b/crates/wallet/sdk/src/apis/accounts.rs @@ -40,15 +40,22 @@ use crate::{ VaultModel, WalletOotleAddressWithKeyIds, }, - network::WalletNetworkInterface, - storage::{CommittableStore, WalletStorageError, WalletStore, WalletStoreReader, WalletStoreWriter}, + spec::WalletSdkSpec, + storage::{ + CommittableStore, + ReadableWalletStore, + WalletStorageError, + WalletStoreReader, + WalletStoreWriter, + WriteableWalletStore, + }, }; -pub struct AccountsApi<'a, TStore, TNetworkInterface> { +pub struct AccountsApi<'a, TSpec: WalletSdkSpec> { network: Network, - store: &'a TStore, - substates_api: SubstatesApi<'a, TStore, TNetworkInterface>, - key_manager_api: KeyManagerApi<'a, TStore>, + store: &'a TSpec::Store, + substates_api: SubstatesApi<'a, TSpec::Store, TSpec::NetworkInterface>, + key_manager_api: KeyManagerApi<'a, TSpec>, epoch_birthday: EpochBirthday, } @@ -56,12 +63,12 @@ pub fn derive_account_address_from_public_key(public_key: &RistrettoPublicKeyByt derive_component_address_from_public_key(&ACCOUNT_TEMPLATE_ADDRESS, public_key) } -impl<'a, TStore: WalletStore, TNetworkInterface> AccountsApi<'a, TStore, TNetworkInterface> { +impl<'a, TSpec: WalletSdkSpec> AccountsApi<'a, TSpec> { pub fn new( network: Network, - store: &'a TStore, - substates_api: SubstatesApi<'a, TStore, TNetworkInterface>, - key_manager_api: KeyManagerApi<'a, TStore>, + store: &'a TSpec::Store, + substates_api: SubstatesApi<'a, TSpec::Store, TSpec::NetworkInterface>, + key_manager_api: KeyManagerApi<'a, TSpec>, epoch_birthday: EpochBirthday, ) -> Self { Self { @@ -125,11 +132,7 @@ impl<'a, TStore: WalletStore, TNetworkInterface> AccountsApi<'a, TStore, TNetwor ) -> Result<(), AccountsApiError> { let (owner_pk, owner_key_id) = match owner_key.into() { KeyIdOrPublicKey::KeyId(key_id) => { - let pk = self - .key_manager_api - .get_account_owner_key(key_id)? - .to_public_key() - .to_byte_type(); + let pk = self.key_manager_api.get_key(key_id)?.to_public_key().to_byte_type(); (pk, Some(key_id)) }, KeyIdOrPublicKey::PublicKey(pk) => (pk, None), @@ -237,8 +240,8 @@ impl<'a, TStore: WalletStore, TNetworkInterface> AccountsApi<'a, TStore, TNetwor pub fn get_address_for_account(&self, account: &Account) -> Result { let view_only_key = match account.view_only_key_id { - KeyId::Derived { index } => { - let view_only_key = self.key_manager_api.derive_view_only_key(index)?; + KeyId::Derived { key_branch, index } => { + let view_only_key = self.key_manager_api.derive_key(key_branch, index)?; view_only_key.to_public_key() }, KeyId::Imported { local_key_id } => { @@ -394,11 +397,8 @@ impl<'a, TStore: WalletStore, TNetworkInterface> AccountsApi<'a, TStore, TNetwor } } -impl<'a, TStore, TNetworkInterface> AccountsApi<'a, TStore, TNetworkInterface> -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError, +impl<'a, TSpec> AccountsApi<'a, TSpec> +where TSpec: WalletSdkSpec { pub async fn resolve_account_by_public_key( &self, diff --git a/crates/wallet/sdk/src/apis/confidential_outputs.rs b/crates/wallet/sdk/src/apis/confidential_outputs.rs index 7f2bc801d6..5363a2a3ba 100644 --- a/crates/wallet/sdk/src/apis/confidential_outputs.rs +++ b/crates/wallet/sdk/src/apis/confidential_outputs.rs @@ -15,23 +15,31 @@ use crate::{ key_manager::{KeyManagerApi, KeyManagerApiError}, }, models::{Account, ConfidentialOutputModel, OutputStatus, WalletLockId, WalletSecretKey}, - storage::{CommittableStore, WalletStorageError, WalletStore, WalletStoreReader, WalletStoreWriter}, + storage::{ + CommittableStore, + ReadableWalletStore, + WalletStorageError, + WalletStoreReader, + WalletStoreWriter, + WriteableWalletStore, + }, + WalletSdkSpec, }; const LOG_TARGET: &str = "tari::ootle::wallet_sdk::apis::confidential_outputs"; -pub struct ConfidentialOutputsApi<'a, TStore> { - store: &'a TStore, - key_manager_api: KeyManagerApi<'a, TStore>, +pub struct ConfidentialOutputsApi<'a, TSpec: WalletSdkSpec> { + store: &'a TSpec::Store, + key_manager_api: KeyManagerApi<'a, TSpec>, crypto_api: ConfidentialCryptoApi, } -impl<'a, TStore> ConfidentialOutputsApi<'a, TStore> -where TStore: WalletStore +impl<'a, TSpec> ConfidentialOutputsApi<'a, TSpec> +where TSpec: WalletSdkSpec { pub fn new( - store: &'a TStore, - key_manager_api: KeyManagerApi<'a, TStore>, + store: &'a TSpec::Store, + key_manager_api: KeyManagerApi<'a, TSpec>, crypto_api: ConfidentialCryptoApi, ) -> Self { Self { @@ -123,7 +131,7 @@ where TStore: WalletStore let mut outputs_with_masks = Vec::with_capacity(outputs.len()); for output in outputs { // Encryption is always done with a DH of the account's public key - let encryption_key = self.key_manager_api.get_view_only_key(output.view_only_key_id)?; + let encryption_key = self.key_manager_api.get_key(output.view_only_key_id)?; // Either derive the mask from the sender's public nonce or from the local key manager let shared_decrypt_key = match output.sender_public_nonce { Some(nonce) => { @@ -174,7 +182,7 @@ where TStore: WalletStore vault_id: VaultId, outputs: I, ) -> Result<(), ConfidentialOutputsApiError> { - let view_key = self.key_manager_api.get_view_only_key(account.view_only_key_id)?; + let view_key = self.key_manager_api.get_key(account.view_only_key_id)?; let mut tx = self.store.create_write_tx()?; for (commitment, output) in outputs { diff --git a/crates/wallet/sdk/src/apis/confidential_transfer.rs b/crates/wallet/sdk/src/apis/confidential_transfer.rs index ad753669f0..73226f4709 100644 --- a/crates/wallet/sdk/src/apis/confidential_transfer.rs +++ b/crates/wallet/sdk/src/apis/confidential_transfer.rs @@ -29,38 +29,35 @@ use crate::{ transaction::{TransactionApi, TransactionApiError}, }, models::{ConfidentialOutputModel, KeyBranch, OutputStatus, WalletLockId}, - network::{StatusResponseError, WalletNetworkInterface}, - storage::{WalletStorageError, WalletStore}, + spec::WalletSdkSpec, + storage::WalletStorageError, }; const LOG_TARGET: &str = "tari::ootle::wallet_sdk::apis::confidential_transfers"; -pub struct ConfidentialTransferApi<'a, TStore, TNetworkInterface> { - key_manager_api: KeyManagerApi<'a, TStore>, - locks_api: LocksApi<'a, TStore>, - accounts_api: AccountsApi<'a, TStore, TNetworkInterface>, - confidential_outputs_api: ConfidentialOutputsApi<'a, TStore>, - transaction_api: TransactionApi<'a, TStore, TNetworkInterface>, - substate_api: SubstatesApi<'a, TStore, TNetworkInterface>, +pub struct ConfidentialTransferApi<'a, TSpec: WalletSdkSpec> { + key_manager_api: KeyManagerApi<'a, TSpec>, + locks_api: LocksApi<'a, TSpec::Store>, + accounts_api: AccountsApi<'a, TSpec>, + confidential_outputs_api: ConfidentialOutputsApi<'a, TSpec>, + transaction_api: TransactionApi<'a, TSpec::Store, TSpec::NetworkInterface>, + substate_api: SubstatesApi<'a, TSpec::Store, TSpec::NetworkInterface>, crypto_api: ConfidentialCryptoApi, - config_api: ConfigApi<'a, TStore>, + config_api: ConfigApi<'a, TSpec::Store>, } -impl<'a, TStore, TNetworkInterface> ConfidentialTransferApi<'a, TStore, TNetworkInterface> -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, +impl<'a, TSpec: WalletSdkSpec> ConfidentialTransferApi<'a, TSpec> +where TSpec: WalletSdkSpec { pub fn new( - key_manager_api: KeyManagerApi<'a, TStore>, - accounts_api: AccountsApi<'a, TStore, TNetworkInterface>, - locks_api: LocksApi<'a, TStore>, - confidential_outputs_api: ConfidentialOutputsApi<'a, TStore>, - substate_api: SubstatesApi<'a, TStore, TNetworkInterface>, - transaction_api: TransactionApi<'a, TStore, TNetworkInterface>, + key_manager_api: KeyManagerApi<'a, TSpec>, + accounts_api: AccountsApi<'a, TSpec>, + locks_api: LocksApi<'a, TSpec::Store>, + confidential_outputs_api: ConfidentialOutputsApi<'a, TSpec>, + substate_api: SubstatesApi<'a, TSpec::Store, TSpec::NetworkInterface>, + transaction_api: TransactionApi<'a, TSpec::Store, TSpec::NetworkInterface>, crypto_api: ConfidentialCryptoApi, - config_api: ConfigApi<'a, TStore>, + config_api: ConfigApi<'a, TSpec::Store>, ) -> Self { Self { key_manager_api, @@ -275,7 +272,7 @@ where // Reserve and lock input funds for fees let max_fee = params.max_fee; - let account_key = self.key_manager_api.get_account_owner_key(account_owner_key_id)?; + let account_key = self.key_manager_api.get_key(account_owner_key_id)?; let account_public_key = PublicKey::from_secret_key(&account_key.secret); // Reserve and lock input funds diff --git a/crates/wallet/sdk/src/apis/key_manager.rs b/crates/wallet/sdk/src/apis/key_manager.rs index b5100245cf..265e5b5fd2 100644 --- a/crates/wallet/sdk/src/apis/key_manager.rs +++ b/crates/wallet/sdk/src/apis/key_manager.rs @@ -1,8 +1,7 @@ // Copyright 2023 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use blake2::Blake2b; -use digest::{consts::U64, crypto_common::rand_core::OsRng}; +use rand::rngs::OsRng; use tari_common_types::seeds::cipher_seed; use tari_crypto::{ keys::{PublicKey as _, SecretKey}, @@ -15,14 +14,13 @@ use tari_ootle_common_types::{ Epoch, Network, }; -use tari_ootle_wallet_crypto::encryption::encrypt_with_password; -use tari_transaction_components::key_manager::tari_key_manager::TariKeyManager; +use tari_ootle_wallet_crypto::encryption::{decrypt_with_password, encrypt_with_password, CipherError}; use crate::{ apis::password_manager::{PasswordManagerApi, PasswordManagerApiError}, key_managers::WalletKeyStore, - local_key_store::LocalKeyStore, models::{ + DerivedKeyId, DerivedKeyIndex, DerivedKeyPair, DerivedWalletKey, @@ -37,26 +35,31 @@ use crate::{ WalletPublicKey, WalletSecretKey, }, - storage::{CommittableStore, WalletStorageError, WalletStore, WalletStoreReader, WalletStoreWriter}, + spec::WalletSdkSpec, + storage::{ + CommittableStore, + ReadableWalletStore, + WalletStorageError, + WalletStoreReader, + WalletStoreWriter, + WriteableWalletStore, + }, }; -pub type WalletKeyManager = TariKeyManager>; - -#[derive(Clone)] -pub struct KeyManagerApi<'a, TStore> { +pub struct KeyManagerApi<'a, TSpec: WalletSdkSpec> { network: Network, - store: &'a TStore, - key_store: LocalKeyStore<'a, TStore>, - password_manager: PasswordManagerApi<'a, TStore>, + store: &'a TSpec::Store, + key_store: &'a TSpec::KeyStore, + password_manager: PasswordManagerApi<'a, TSpec::Store>, epoch_birthday: EpochBirthday, } -impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { +impl<'a, TSpec: WalletSdkSpec> KeyManagerApi<'a, TSpec> { pub(crate) fn new( network: Network, - store: &'a TStore, - key_store: LocalKeyStore<'a, TStore>, - password_manager: PasswordManagerApi<'a, TStore>, + store: &'a TSpec::Store, + key_store: &'a TSpec::KeyStore, + password_manager: PasswordManagerApi<'a, TSpec::Store>, epoch_birthday: EpochBirthday, ) -> Self { Self { @@ -68,6 +71,10 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { } } + pub(crate) fn key_store(&self) -> &'a TSpec::KeyStore { + self.key_store + } + pub fn get_all_derived_keys(&self, branch: KeyBranch) -> Result, KeyManagerApiError> { let all_keys = self.store.with_read_tx(|tx| tx.key_manager_get_all(branch.as_str()))?; let mut keys = Vec::with_capacity(all_keys.len()); @@ -79,10 +86,9 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { .map_err(|e| KeyManagerApiError::KeyStoreError { source: e.into() })?; let pk = RistrettoPublicKey::from_secret_key(&key); keys.push(WalletKeyRecord { - key_id: KeyId::derived(index), + key_id: KeyId::derived(branch, index), public_key: pk, secret_key: key, - branch, is_active: active, }); } @@ -90,11 +96,19 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { } pub fn get_imported_key(&self, id: ImportedKeyId) -> Result { - let key = self - .key_store - .get_imported_secret(id) - .map_err(|e| KeyManagerApiError::KeyStoreError { source: e.into() })?; - Ok(ImportedWalletKey { key, import_id: id }) + let password = self.password_manager.get_cipher_seed_password()?; + let (_ty, encrypted) = self.store.with_read_tx(|tx| tx.key_manager_get_raw_imported_key(id))?; + let decrypted = decrypt_with_password(&encrypted, password.reveal())?; + let secret = + RistrettoSecretKey::from_canonical_bytes(&decrypted).map_err(|e| WalletStorageError::DecodingError { + operation: "get_imported_secret", + item: "imported secret key", + details: format!("Imported key at id {id} is non-canonical {e}"), + })?; + Ok(ImportedWalletKey { + key: secret, + import_id: id, + }) } pub fn import_key( @@ -116,43 +130,34 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { Ok(KeyId::imported(id)) } - pub fn get_account_owner_key(&self, key_id: KeyId) -> Result { - self.get_key(KeyBranch::Account, key_id) - } - - pub fn get_view_only_key(&self, key_id: KeyId) -> Result { - self.get_key(KeyBranch::ViewOnlyKey, key_id) - } - - pub(crate) fn get_key(&self, branch: KeyBranch, key_id: KeyId) -> Result { + pub fn get_key(&self, key_id: KeyId) -> Result { match key_id { KeyId::Imported { local_key_id } => { let imported_key = self.get_imported_key(local_key_id)?; Ok(imported_key.into()) }, - KeyId::Derived { index } => { - let derived_key = self.derive_key(branch, index)?; + KeyId::Derived { key_branch, index } => { + let derived_key = self.derive_key(key_branch, index)?; Ok(derived_key.into()) }, } } - pub fn get_public_key(&self, branch: KeyBranch, key_id: KeyId) -> Result { + pub fn get_public_key>(&self, key_id: T) -> Result { + let key_id = key_id.into(); match key_id { KeyId::Imported { local_key_id } => { // TODO: could be implemented without fetching the secret key, if we stored the public key in the DB let imported_key = self.get_imported_key(local_key_id)?; Ok(WalletPublicKey { public_key: imported_key.to_public_key(), - branch, key_id, }) }, - KeyId::Derived { index } => { - let derived_key = self.derive_key(branch, index)?; + KeyId::Derived { key_branch, index } => { + let derived_key = self.derive_key(key_branch, index)?; Ok(WalletPublicKey { public_key: derived_key.to_public_key(), - branch, key_id, }) }, @@ -177,8 +182,7 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { .map_err(|e| KeyManagerApiError::KeyStoreError { source: e.into() })?; Ok(DerivedWalletKey { key: secret, - branch, - key_index: index, + derived_key_id: DerivedKeyId { branch, index }, }) } @@ -202,8 +206,8 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { &self, index: DerivedKeyIndex, ) -> Result { - let key = self.derive_account_key(index)?; - let view_only_key = self.derive_view_only_key(index)?; + let key = self.derive_key(KeyBranch::Account, index)?; + let view_only_key = self.derive_key(KeyBranch::ViewOnlyKey, index)?; Ok(WalletOotleAddressWithKeyIds { address: RistrettoOotleAddress { network: self.network, @@ -211,27 +215,14 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { account_key: RistrettoPublicKey::from_secret_key(&key.key), pay_ref: None, }, - view_only_key_id: key.as_key_id(), - owner_key_id: key.as_key_id(), + view_only_key_id: view_only_key.as_key_id(), + owner_key_id: (*key.derived_key_id()).into(), }) } pub fn next_account_address(&self) -> Result { let key = self.next_key(KeyBranch::Account)?; - self.derive_account_address(key.key_index) - } - - pub fn derive_view_only_key(&self, index: DerivedKeyIndex) -> Result { - self.derive_key(KeyBranch::ViewOnlyKey, index) - } - - pub fn derive_view_only_keypair(&self, index: u64) -> Result { - let key = self.derive_view_only_key(index)?; - let public_key = RistrettoPublicKey::from_secret_key(&key.key); - Ok(DerivedKeyPair { - public_key, - derived_key: key, - }) + self.derive_account_address(key.key_index()) } pub fn derive_account_key_pair(&self, index: u64) -> Result { @@ -252,8 +243,8 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { /// If the branch does not exist, it will be created with index 0 and the first key will be returned. /// TODO: if there is another active DB transaction this function will block until it can acquire it. pub fn next_key(&self, branch: KeyBranch) -> Result { - let next_key_id = self.next_derived_key_index(branch)?; - let key = self.derive_key(branch, next_key_id)?; + let next_key_id = self.next_derived_key_id(branch)?; + let key = self.derive_key(branch, next_key_id.index())?; Ok(key) } @@ -261,16 +252,15 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { /// If the branch does not exist, it will be created with index 0 and the first key will be returned. /// TODO: if there is another active DB transaction this function will block until it can acquire it. pub fn next_public_key(&self, branch: KeyBranch) -> Result { - let next_key_id = self.next_derived_key_index(branch)?; - let key = self.derive_key(branch, next_key_id)?; + let next_key_id = self.next_derived_key_id(branch)?; + let key = self.derive_key(branch, next_key_id.index())?; Ok(WalletPublicKey { public_key: key.to_public_key(), - branch, key_id: key.as_key_id(), }) } - pub fn next_derived_key_index(&self, branch: KeyBranch) -> Result { + pub fn next_derived_key_id(&self, branch: KeyBranch) -> Result { let mut tx = self.store.create_write_tx()?; let next_index = tx .key_manager_get_last_index(branch.as_str()) @@ -283,7 +273,10 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { } tx.key_manager_insert_or_ignore(branch.as_str(), next_index)?; tx.commit()?; - Ok(next_index) + Ok(DerivedKeyId { + branch, + index: next_index, + }) } pub fn create_throwaway_nonce(&self) -> RistrettoSecretKey { @@ -316,24 +309,10 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { self.derive_key(branch, key_index) } - pub fn get_key_or_active( - &self, - branch: KeyBranch, - maybe_key_id: Option, - ) -> Result { - match maybe_key_id { - Some(id) => Ok(self.get_public_key(branch, id)?), - None => { - let key = self.get_active_key(branch)?; - Ok(key.into()) - }, - } - } - pub fn get_cipher_seed_birthday_epoch(&self) -> Result { let birthday = self .key_store - .cipher_seed_birthday() + .key_birthday() .map_err(|e| KeyManagerApiError::KeyStoreError { source: e.into() })?; let Some(birthday) = birthday else { return Ok(Epoch::zero()); @@ -346,6 +325,18 @@ impl<'a, TStore: WalletStore> KeyManagerApi<'a, TStore> { } } +impl Clone for KeyManagerApi<'_, TSpec> { + fn clone(&self) -> Self { + Self { + network: self.network, + store: self.store, + key_store: self.key_store, + password_manager: self.password_manager.clone(), + epoch_birthday: self.epoch_birthday, + } + } +} + #[derive(Debug, thiserror::Error)] pub enum KeyManagerApiError { #[error("Store error: {0}")] @@ -360,6 +351,8 @@ pub enum KeyManagerApiError { PasswordManagerApiError(#[from] PasswordManagerApiError), #[error("Key manager is in read only mode")] ReadOnlyMode, + #[error("Cipher error: {0}")] + CipherError(#[from] CipherError), } impl IsNotFoundError for KeyManagerApiError { diff --git a/crates/wallet/sdk/src/apis/signer.rs b/crates/wallet/sdk/src/apis/signer.rs index 56bf16b07f..0e6d8752fd 100644 --- a/crates/wallet/sdk/src/apis/signer.rs +++ b/crates/wallet/sdk/src/apis/signer.rs @@ -1,62 +1,111 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::fmt; + use tari_ootle_common_types::{IntoSigned, Signable}; use crate::{ - key_managers::{KeyManagerBackend, SignatureOutput}, - models::{KeyBranch, KeyId}, + apis::key_manager::{KeyManagerApi, KeyManagerApiError}, + key_managers::{SignatureOutput, WalletKeyStore}, + models::KeyId, + spec::KeyStoreError, + storage::WalletStorageError, + WalletSdkSpec, }; -#[derive(Debug, Clone)] -pub struct SignerApi { - backend: TKm, +pub struct SignerApi<'a, TSpec: WalletSdkSpec> { + key_manager: KeyManagerApi<'a, TSpec>, } -impl SignerApi { - pub fn new(backend: TKm) -> Self { - Self { backend } +impl<'a, TSpec: WalletSdkSpec> SignerApi<'a, TSpec> { + pub fn new(key_manager: KeyManagerApi<'a, TSpec>) -> Self { + Self { key_manager } } pub fn get_signature( &mut self, - branch: KeyBranch, key_id: KeyId, context: CTX, item: &T, - ) -> Result + ) -> Result> where T: Signable, - TKm: KeyManagerBackend, { - let message = item.as_signing_message(context); - let signature = self.backend.try_sign(branch.as_str(), key_id, message)?; - Ok(signature) + match key_id { + KeyId::Derived { key_branch, index } => { + let output = self + .key_manager + .key_store() + .sign(key_branch.as_str(), index, context, item) + // NOTE: Cannot implement From due to rust bug/limitation + .map_err(SignerApiError::KeyStoreError)?; + Ok(output) + }, + KeyId::Imported { local_key_id } => { + // TODO: do we actually need to support signing from an imported key? Typically these are view-only + // keys. If we removed support for this, we'd just need the key store as a dependency of the signing api + // instead of the key manager api. + let key = self.key_manager.get_key(KeyId::imported(local_key_id))?; + let sig = key.sign(context, item); + Ok(SignatureOutput { + public_key: key.to_public_key(), + signature: sig, + }) + }, + } } pub fn sign_with_context( &mut self, - branch: KeyBranch, key_id: KeyId, context: Ctx, item: T, - ) -> Result + ) -> Result> where T: IntoSigned, - TKm: KeyManagerBackend, { - let output = self.get_signature(branch, key_id, context, &item)?; + let output = self.get_signature(key_id, context, &item)?; let output = item.into_signed(output.public_key, output.signature); Ok(output) } - pub fn sign(&mut self, branch: KeyBranch, key_id: KeyId, item: T) -> Result - where - T: IntoSigned<()>, - TKm: KeyManagerBackend, - { - let output = self.get_signature(branch, key_id, (), &item)?; + pub fn sign(&mut self, key_id: KeyId, item: T) -> Result> + where T: IntoSigned<()> { + let output = self.get_signature(key_id, (), &item)?; let output = item.into_signed(output.public_key, output.signature); Ok(output) } } + +impl Clone for SignerApi<'_, TSpec> +where + TSpec: WalletSdkSpec, + TSpec::KeyStore: Clone, +{ + fn clone(&self) -> Self { + Self { + key_manager: self.key_manager.clone(), + } + } +} + +#[derive(thiserror::Error)] +pub enum SignerApiError { + #[error("Key store error: {0}")] + KeyStoreError(KeyStoreError), + #[error("Wallet storage error: {0}")] + StoreError(#[from] WalletStorageError), + #[error("Key manager API error: {0}")] + KeyManagerError(#[from] KeyManagerApiError), +} + +impl fmt::Debug for SignerApiError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::KeyStoreError(e) => write!(f, "KeyStoreError: {:?}", e), + Self::StoreError(e) => write!(f, "StoreError: {:?}", e), + Self::KeyManagerError(e) => write!(f, "KeyManagerError: {:?}", e), + } + } +} diff --git a/crates/wallet/sdk/src/apis/stealth_outputs.rs b/crates/wallet/sdk/src/apis/stealth_outputs.rs index 71eb679670..4647c0fb38 100644 --- a/crates/wallet/sdk/src/apis/stealth_outputs.rs +++ b/crates/wallet/sdk/src/apis/stealth_outputs.rs @@ -57,24 +57,32 @@ use crate::{ StealthOutputModel, WalletLockId, }, - storage::{CommittableStore, WalletStorageError, WalletStore, WalletStoreReader, WalletStoreWriter}, + storage::{ + CommittableStore, + ReadableWalletStore, + WalletStorageError, + WalletStoreReader, + WalletStoreWriter, + WriteableWalletStore, + }, + WalletSdkSpec, }; const LOG_TARGET: &str = "tari::ootle::wallet::apis::stealth_outputs"; -pub struct StealthOutputsApi<'a, TStore> { - store: &'a TStore, - key_manager_api: KeyManagerApi<'a, TStore>, +pub struct StealthOutputsApi<'a, TSpec: WalletSdkSpec> { + store: &'a TSpec::Store, + key_manager_api: KeyManagerApi<'a, TSpec>, crypto_api: StealthCryptoApi, - config_api: ConfigApi<'a, TStore>, + config_api: ConfigApi<'a, TSpec::Store>, } -impl<'a, TStore: WalletStore> StealthOutputsApi<'a, TStore> { +impl<'a, TSpec: WalletSdkSpec> StealthOutputsApi<'a, TSpec> { pub fn new( - store: &'a TStore, - key_manager_api: KeyManagerApi<'a, TStore>, + store: &'a TSpec::Store, + key_manager_api: KeyManagerApi<'a, TSpec>, crypto_api: StealthCryptoApi, - config_api: ConfigApi<'a, TStore>, + config_api: ConfigApi<'a, TSpec::Store>, ) -> Self { Self { store, @@ -144,7 +152,7 @@ impl<'a, TStore: WalletStore> StealthOutputsApi<'a, TStore> { fn lock_outputs_internal( &self, - tx: &mut TStore::WriteTransaction<'_>, + tx: &mut ::WriteTransaction<'_>, account_address: &ComponentAddress, resource_address: &ResourceAddress, amount: Amount, @@ -247,14 +255,13 @@ impl<'a, TStore: WalletStore> StealthOutputsApi<'a, TStore> { fn resolve_output_masks_for_spending( &self, - spend_key_branch: KeyBranch, owner_key_id: KeyId, view_only_key_id: KeyId, inputs: &[InputSpendData], ) -> Result, StealthOutputsApiError> { let network = self.config_api.get_network()?; - let owner_key_part = self.key_manager_api.get_key(spend_key_branch, owner_key_id)?; + let owner_key_part = self.key_manager_api.get_key(owner_key_id)?; let mut inputs_with_masks = Vec::with_capacity(inputs.len()); for input in inputs { // Derive the decryption key from the DHKE(sender's public nonce, encryption secret key); @@ -271,7 +278,6 @@ impl<'a, TStore: WalletStore> StealthOutputsApi<'a, TStore> { let decrypted = self.decrypt_value_and_mask( &input.encrypted_data, &input.commitment, - KeyBranch::ViewOnlyKey, view_only_key_id, &nonce, // We don't need to decrypt the memo to spend the output @@ -690,12 +696,8 @@ impl<'a, TStore: WalletStore> StealthOutputsApi<'a, TStore> { where I: IntoIterator>, { - let unblinded_inputs = self.resolve_output_masks_for_spending( - params.spend_key_branch, - params.spend_key_id, - params.view_only_key_id, - params.inputs, - )?; + let unblinded_inputs = + self.resolve_output_masks_for_spending(params.spend_key_id, params.view_only_key_id, params.inputs)?; let outputs = params .outputs .into_iter() @@ -737,12 +739,11 @@ impl<'a, TStore: WalletStore> StealthOutputsApi<'a, TStore> { &self, output_encrypted_value: &EncryptedData, output_commitment: &PedersenCommitmentBytes, - key_branch: KeyBranch, claim_secret_key_id: KeyId, reciprocal_public_key: &RistrettoPublicKey, skip_memo: bool, ) -> Result { - let key = self.key_manager_api.get_key(key_branch, claim_secret_key_id)?; + let key = self.key_manager_api.get_key(claim_secret_key_id)?; let decrypted = self.crypto_api.decrypt_value_and_mask( output_encrypted_value, output_commitment, @@ -770,7 +771,6 @@ impl<'a, TStore: WalletStore> StealthOutputsApi<'a, TStore> { } pub struct TransferStatementParams<'a, I> { - pub spend_key_branch: KeyBranch, pub spend_key_id: KeyId, pub view_only_key_id: KeyId, pub resource_address: &'a ResourceAddress, diff --git a/crates/wallet/sdk/src/apis/stealth_transfer/api.rs b/crates/wallet/sdk/src/apis/stealth_transfer/api.rs index e556470628..dc38fcb022 100644 --- a/crates/wallet/sdk/src/apis/stealth_transfer/api.rs +++ b/crates/wallet/sdk/src/apis/stealth_transfer/api.rs @@ -7,12 +7,7 @@ use log::*; use tari_crypto::ristretto::RistrettoPublicKey; use tari_engine_types::{substate::SubstateId, ConvertFromByteType, FromByteType, ToByteType}; use tari_ootle_address::RistrettoOotleAddress; -use tari_ootle_common_types::{ - displayable::Displayable, - optional::{IsNotFoundError, Optional}, - Network, - SubstateRequirement, -}; +use tari_ootle_common_types::{displayable::Displayable, optional::Optional, Network, SubstateRequirement}; use tari_ootle_wallet_crypto::memo::Memo; use tari_template_lib::{ constants::XTR, @@ -46,44 +41,30 @@ use crate::{ stealth_outputs::{StealthOutputsApi, TransferStatementParams}, substate::{SubstatesApi, ValidatorScanResult}, }, - models::{ - AccountWithAddress, - KeyBranch, - KeyId, - OutputStatus, - StealthOutputModel, - WalletLockDropGuard, - WalletLockId, - }, - network::WalletNetworkInterface, - storage::WalletStore, + models::{AccountWithAddress, KeyBranch, OutputStatus, StealthOutputModel, WalletLockDropGuard, WalletLockId}, + WalletSdkSpec, }; const LOG_TARGET: &str = "tari::ootle::wallet_sdk::apis::stealth_transfers"; -pub struct StealthTransferApi<'a, TStore, TNetworkInterface> { - accounts_api: AccountsApi<'a, TStore, TNetworkInterface>, - outputs_api: StealthOutputsApi<'a, TStore>, - locks_api: LocksApi<'a, TStore>, - substate_api: SubstatesApi<'a, TStore, TNetworkInterface>, - key_manager_api: KeyManagerApi<'a, TStore>, - config_api: ConfigApi<'a, TStore>, +pub struct StealthTransferApi<'a, TSpec: WalletSdkSpec> { + accounts_api: AccountsApi<'a, TSpec>, + outputs_api: StealthOutputsApi<'a, TSpec>, + locks_api: LocksApi<'a, TSpec::Store>, + substate_api: SubstatesApi<'a, TSpec::Store, TSpec::NetworkInterface>, + key_manager_api: KeyManagerApi<'a, TSpec>, + config_api: ConfigApi<'a, TSpec::Store>, semaphore: Semaphore, } -impl<'a, TStore, TNetworkInterface> StealthTransferApi<'a, TStore, TNetworkInterface> -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError, -{ +impl<'a, TSpec: WalletSdkSpec> StealthTransferApi<'a, TSpec> { pub fn new( - accounts_api: AccountsApi<'a, TStore, TNetworkInterface>, - outputs_api: StealthOutputsApi<'a, TStore>, - locks_api: LocksApi<'a, TStore>, - substate_api: SubstatesApi<'a, TStore, TNetworkInterface>, - key_manager_api: KeyManagerApi<'a, TStore>, - config_api: ConfigApi<'a, TStore>, + accounts_api: AccountsApi<'a, TSpec>, + outputs_api: StealthOutputsApi<'a, TSpec>, + locks_api: LocksApi<'a, TSpec::Store>, + substate_api: SubstatesApi<'a, TSpec::Store, TSpec::NetworkInterface>, + key_manager_api: KeyManagerApi<'a, TSpec>, + config_api: ConfigApi<'a, TSpec::Store>, ) -> Self { Self { accounts_api, @@ -304,7 +285,7 @@ where &self, owner_account: AccountWithAddress, params: StealthTransferParams, - ) -> Result<(WalletLockDropGuard<'a, TStore>, StealthTransferOutput), StealthTransferApiError> { + ) -> Result<(WalletLockDropGuard<'a, TSpec::Store>, StealthTransferOutput), StealthTransferApiError> { let network = self.config_api.get_network()?; params.validate(network)?; @@ -398,21 +379,17 @@ where // Figure out which signing key to use - if there are no revealed funds, which necessitate using an account // withdraw auth signature, then we can use a nonce key. let must_sign_with_account_key = fee_inputs_to_spend.revealed.is_positive(); - let (signing_key_branch, signing_key_id) = if must_sign_with_account_key { - (KeyBranch::Account, owner_key_id) + let signing_key_id = if must_sign_with_account_key { + owner_key_id } else { - let next_index = self.key_manager_api.next_derived_key_index(KeyBranch::Nonce)?; - (KeyBranch::Nonce, KeyId::derived(next_index)) + self.key_manager_api.next_derived_key_id(KeyBranch::Nonce)?.into() }; - let required_signer = self - .key_manager_api - .get_public_key(signing_key_branch, signing_key_id)?; + let required_signer = self.key_manager_api.get_public_key(signing_key_id)?; let required_signer_pk = required_signer.public_key.to_byte_type(); let fee_signer = required_signer; // Generate fee transfer statement let fee_transfer_statement = self.outputs_api.generate_transfer_statement(TransferStatementParams { - spend_key_branch: KeyBranch::Account, spend_key_id: owner_key_id, view_only_key_id: owner_account.view_only_key_id(), resource_address: ¶ms.resource_address, @@ -455,18 +432,15 @@ where // Signing key for main transfer intent let must_sign_with_account_key = !params.badge_usage.is_none() || inputs_to_spend.revealed.is_positive(); - let (signing_key_branch, signing_key_id) = if must_sign_with_account_key { - (KeyBranch::Account, owner_key_id) + let signing_key_id = if must_sign_with_account_key { + owner_key_id } else { - let next_index = self.key_manager_api.next_derived_key_index(KeyBranch::Nonce)?; - (KeyBranch::Nonce, KeyId::derived(next_index)) + self.key_manager_api.next_derived_key_id(KeyBranch::Nonce)?.into() }; - let main_signer = if signing_key_branch == fee_signer.branch && signing_key_id == fee_signer.key_id { + let main_signer = if fee_signer.key_id() == signing_key_id { None } else { - let required_signer = self - .key_manager_api - .get_public_key(signing_key_branch, signing_key_id)?; + let required_signer = self.key_manager_api.get_public_key(signing_key_id)?; Some(required_signer) }; let required_signer_pk = main_signer.as_ref().unwrap_or(&fee_signer).public_key().to_byte_type(); @@ -527,7 +501,6 @@ where .collect::, StealthTransferApiError>>()?; let transfer_statement = self.outputs_api.generate_transfer_statement(TransferStatementParams { - spend_key_branch: KeyBranch::Account, spend_key_id: owner_key_id, view_only_key_id: owner_account.view_only_key_id(), resource_address: ¶ms.resource_address, diff --git a/crates/wallet/sdk/src/cipher_seed.rs b/crates/wallet/sdk/src/cipher_seed.rs index 8896fc16f5..05241113a5 100644 --- a/crates/wallet/sdk/src/cipher_seed.rs +++ b/crates/wallet/sdk/src/cipher_seed.rs @@ -18,15 +18,17 @@ impl<'a> CipherSeedRestore<'a> { } } +pub type SafeCipherSeed = Arc; + #[derive(Debug, Clone, Default)] pub enum WalletCipherSeed { #[default] None, - CipherSeed(Arc), + CipherSeed(SafeCipherSeed), } impl WalletCipherSeed { - pub fn cipher_seed(&self) -> Option<&CipherSeed> { + pub fn cipher_seed(&self) -> Option<&SafeCipherSeed> { match self { Self::CipherSeed(seed) => Some(seed), Self::None => None, diff --git a/crates/wallet/sdk/src/key_managers/backend.rs b/crates/wallet/sdk/src/key_managers/backend.rs index 83626d5564..3db1d1b882 100644 --- a/crates/wallet/sdk/src/key_managers/backend.rs +++ b/crates/wallet/sdk/src/key_managers/backend.rs @@ -1,30 +1,44 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use tari_crypto::ristretto::{RistrettoPublicKey, RistrettoSchnorr, RistrettoSecretKey}; +use rand::rngs::OsRng; +use tari_crypto::{ + keys::PublicKey, + ristretto::{RistrettoPublicKey, RistrettoSchnorr, RistrettoSecretKey}, +}; +use tari_ootle_common_types::Signable; -use crate::models::{DerivedKeyIndex, KeyId}; +use crate::models::DerivedKeyIndex; pub struct SignatureOutput { pub signature: RistrettoSchnorr, pub public_key: RistrettoPublicKey, } -pub trait KeyManagerBackend { - type Error; +pub trait WalletKeyStore { + type Error: std::error::Error + Send + Sync + 'static; - fn try_sign(&mut self, branch: &str, key_id: KeyId, message: M) -> Result; -} - -pub trait WalletKeyStore { - type Error; - - /// Derive a secret key from the cipher seed for the given branch and key index. + /// Derive a secret key for the given branch and key index. fn derive_secret(&self, branch: &str, key_index: DerivedKeyIndex) -> Result; - /// Retrieve an imported secret key by its key identifier. - fn get_imported_secret(&self, key: K) -> Result; - - /// Retrieve the cipher seed birthday if it exists. If this is not supported, it is correct to return Ok(None). - fn cipher_seed_birthday(&self) -> Result, Self::Error>; + /// Sign a message using a derived key for the given branch and key index. + fn sign, C>( + &self, + key_branch: &str, + index: DerivedKeyIndex, + context: C, + message: &M, + ) -> Result { + let secret = self.derive_secret(key_branch, index)?; + let signature = RistrettoSchnorr::sign(&secret, message.as_signing_message(context), &mut OsRng) + .expect("RistrettoSchnorr::sign is infallible as it internally hashes the message into canonical form"); + Ok(SignatureOutput { + signature, + public_key: RistrettoPublicKey::from_secret_key(&secret), + }) + } + + /// Retrieve the key birthday if it exists. The birthday is defined as the number of seconds since the zero epoch, + /// which is predefined for a given network. If this is not supported, it is correct to return Ok(None). + fn key_birthday(&self) -> Result, Self::Error>; } diff --git a/crates/wallet/sdk/src/key_managers/local.rs b/crates/wallet/sdk/src/key_managers/local.rs deleted file mode 100644 index 0cd8f75bc5..0000000000 --- a/crates/wallet/sdk/src/key_managers/local.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2025 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use digest::crypto_common::rand_core::OsRng; -use tari_crypto::{ - keys::PublicKey, - ristretto::{RistrettoPublicKey, RistrettoSchnorr}, -}; -use tari_ootle_common_types::optional::IsNotFoundError; - -use crate::{ - apis::password_manager::PasswordManagerApiError, - key_managers::{backend::WalletKeyStore, KeyManagerBackend, SignatureOutput}, - models::{ImportedKeyId, KeyId}, - storage::WalletStorageError, -}; - -#[derive(Debug, Clone)] -pub struct LocalKeyManager { - key_store: TKeyStore, -} - -impl> LocalKeyManager { - pub fn new(key_store: TKeyStore) -> Self { - Self { key_store } - } -} - -impl KeyManagerBackend for LocalKeyManager -where - M: AsRef<[u8]>, - TKeyStore: WalletKeyStore, -{ - type Error = LocalKeyManagerError; - - fn try_sign(&mut self, branch: &str, key_id: KeyId, message: M) -> Result { - let secret = match key_id { - KeyId::Derived { index } => self - .key_store - .derive_secret(branch, index) - .map_err(LocalKeyManagerError::KeyStoreError)?, - KeyId::Imported { local_key_id } => self - .key_store - .get_imported_secret(local_key_id) - .map_err(LocalKeyManagerError::KeyStoreError)?, - }; - let signature = RistrettoSchnorr::sign(&secret, message, &mut OsRng) - .expect("RistrettoSchnorr::sign is infallible as it internally hashes the message into canonical form"); - let public_key = RistrettoPublicKey::from_secret_key(&secret); - Ok(SignatureOutput { signature, public_key }) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum LocalKeyManagerError { - #[error("Store error: {0}")] - StoreError(#[from] WalletStorageError), - #[error("Password manager error: {0}")] - PasswordManagerApiError(#[from] PasswordManagerApiError), - #[error("Key manager is in read only mode")] - ReadOnlyMode, - #[error("Key store error: {0}")] - KeyStoreError(TKeyStoreErr), -} - -impl IsNotFoundError for LocalKeyManagerError { - fn is_not_found_error(&self) -> bool { - matches!(self, LocalKeyManagerError::StoreError(e) if e.is_not_found_error()) - } -} diff --git a/crates/wallet/sdk/src/key_managers/mod.rs b/crates/wallet/sdk/src/key_managers/mod.rs index 4de0bae273..5ff2db2c7e 100644 --- a/crates/wallet/sdk/src/key_managers/mod.rs +++ b/crates/wallet/sdk/src/key_managers/mod.rs @@ -2,6 +2,5 @@ // SPDX-License-Identifier: BSD-3-Clause mod backend; -pub mod local; pub use backend::*; diff --git a/crates/wallet/sdk/src/lib.rs b/crates/wallet/sdk/src/lib.rs index 61ef6d5137..0375d7db47 100644 --- a/crates/wallet/sdk/src/lib.rs +++ b/crates/wallet/sdk/src/lib.rs @@ -8,14 +8,14 @@ pub mod models; mod sdk; pub use sdk::{WalletSdk, WalletSdkConfig}; +pub use spec::*; pub use tari_common_types::seeds::cipher_seed::CipherSeed; pub mod cipher_seed; pub mod key_managers; -mod local_key_store; +pub mod local_key_store; pub mod network; - -pub type WalletDerivedSecretKey = tari_transaction_components::key_manager::tari_key_manager::DerivedKey; +mod spec; // Re-export commonly used types pub use tari_common_types::seeds::seed_words::SeedWords; diff --git a/crates/wallet/sdk/src/local_key_store.rs b/crates/wallet/sdk/src/local_key_store.rs index f3909e884c..5f26c28bb9 100644 --- a/crates/wallet/sdk/src/local_key_store.rs +++ b/crates/wallet/sdk/src/local_key_store.rs @@ -1,75 +1,52 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use tari_common_types::seeds::cipher_seed::CipherSeed; -use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; -use tari_ootle_wallet_crypto::encryption::{decrypt_with_password, CipherError}; +use tari_common_types::{seeds::cipher_seed::CipherSeed, types::PrivateKey}; +use tari_crypto::{hashing::DomainSeparatedHasher, keys::SecretKey, ristretto::RistrettoSecretKey}; +use tari_ootle_wallet_crypto::encryption::CipherError; use crate::{ - apis::{ - key_manager::WalletKeyManager, - password_manager::{PasswordManagerApi, PasswordManagerApiError}, - }, - cipher_seed::WalletCipherSeed, + apis::password_manager::PasswordManagerApiError, + cipher_seed::{SafeCipherSeed, WalletCipherSeed}, key_managers::WalletKeyStore, - models::{DerivedKeyIndex, ImportedKeyId}, - storage::{WalletStorageError, WalletStore, WalletStoreReader}, + models::DerivedKeyIndex, + storage::WalletStorageError, }; #[derive(Clone)] -pub struct LocalKeyStore<'a, TStore> { - password_manager_api: PasswordManagerApi<'a, TStore>, - cipher_seed: &'a WalletCipherSeed, - wallet_store: &'a TStore, +pub struct LocalKeyStore { + cipher_seed: WalletCipherSeed, } -impl<'a, TStore> LocalKeyStore<'a, TStore> { - pub fn new( - cipher_seed: &'a WalletCipherSeed, - password_manager_api: PasswordManagerApi<'a, TStore>, - wallet_store: &'a TStore, - ) -> Self { - Self { - cipher_seed, - password_manager_api, - wallet_store, - } +impl LocalKeyStore { + pub fn new(cipher_seed: WalletCipherSeed) -> Self { + Self { cipher_seed } + } + + pub fn set_cipher_seed(&mut self, cipher_seed: SafeCipherSeed) -> &mut Self { + self.cipher_seed = WalletCipherSeed::CipherSeed(cipher_seed); + self + } + + pub fn cipher_seed(&self) -> Option<&SafeCipherSeed> { + self.cipher_seed.cipher_seed() } - fn get_cipher_seed(&self) -> Result<&CipherSeed, LocalKeyStoreError> { - self.cipher_seed.cipher_seed().ok_or(LocalKeyStoreError::NoCipherSeed) + fn get_cipher_seed(&self) -> Result<&SafeCipherSeed, LocalKeyStoreError> { + self.cipher_seed().ok_or(LocalKeyStoreError::NoCipherSeed) } } -impl WalletKeyStore for LocalKeyStore<'_, TStore> { +impl WalletKeyStore for LocalKeyStore { type Error = LocalKeyStoreError; fn derive_secret(&self, branch: &str, key_index: DerivedKeyIndex) -> Result { let cipher_seed = self.get_cipher_seed()?; - let km = WalletKeyManager::from(cipher_seed.clone(), branch.to_string(), 0); - let secret = km - .derive_key(key_index) - .expect("Key derivation bug: derive key internally creates a canonical key and must not fail"); - Ok(secret.key) - } - - fn get_imported_secret(&self, key: ImportedKeyId) -> Result { - let password = self.password_manager_api.get_cipher_seed_password()?; - let (_ty, encrypted) = self - .wallet_store - .with_read_tx(|tx| tx.key_manager_get_raw_imported_key(key))?; - let decrypted = decrypt_with_password(&encrypted, password.reveal())?; - let secret = RistrettoSecretKey::from_canonical_bytes(&decrypted).map_err(|e| { - LocalKeyStoreError::WalletStorage(WalletStorageError::DecodingError { - operation: "get_imported_secret", - item: "imported secret key", - details: format!("Imported key at id {key} is non-canonical {e}"), - }) - })?; + let secret = derive_private_key(cipher_seed, branch.to_string(), key_index); Ok(secret) } - fn cipher_seed_birthday(&self) -> Result, Self::Error> { + fn key_birthday(&self) -> Result, Self::Error> { let seed = self.get_cipher_seed()?; Ok(Some(seed.birthday())) } @@ -86,3 +63,31 @@ pub enum LocalKeyStoreError { #[error("Cannot derive keys because no cipher seed was provided")] NoCipherSeed, } + +fn derive_private_key(seed: &CipherSeed, branch_seed: String, account: u64) -> PrivateKey { + use blake2::{digest::consts::U64, Blake2b}; + use digest::typenum::ToInt; + use tari_hashing::KeyManagerDomain; + + pub const HASHER_LABEL_DERIVE_KEY: &str = "derive_key"; + const fn assert_equal(a: usize, b: usize) { + if a != b { + panic!("RistrettoSecretKey::WIDE_REDUCTION_LEN is not equal to 64"); + } + } + + let derive_key = DomainSeparatedHasher::, KeyManagerDomain>::new_with_label(HASHER_LABEL_DERIVE_KEY) + .chain(seed.entropy()) + .chain(branch_seed.as_bytes()) + .chain(account.to_le_bytes()) + .finalize(); + + // At compile time, fail if the length of the derived key is not equal to the expected length which would lead to a + // runtime panic + const { + assert_equal(RistrettoSecretKey::WIDE_REDUCTION_LEN, U64::INT); + } + // const _: () = assert_equal(RistrettoSecretKey::WIDE_REDUCTION_LEN, U64::INT); + + PrivateKey::from_uniform_bytes(derive_key.as_ref()).expect("derived key length matches RistrettoSecretKey length") +} diff --git a/crates/wallet/sdk/src/models/account.rs b/crates/wallet/sdk/src/models/account.rs index 8cc5339977..7b62eac1bc 100644 --- a/crates/wallet/sdk/src/models/account.rs +++ b/crates/wallet/sdk/src/models/account.rs @@ -126,7 +126,7 @@ impl Display for AccountWithAddress { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct NewAccountData { pub address: ComponentAddress, } diff --git a/crates/wallet/sdk/src/models/key.rs b/crates/wallet/sdk/src/models/key.rs index 9d1f2e9f21..f99136c6ff 100644 --- a/crates/wallet/sdk/src/models/key.rs +++ b/crates/wallet/sdk/src/models/key.rs @@ -3,12 +3,15 @@ use std::{fmt::Display, str::FromStr}; +use anyhow::anyhow; +use rand::rngs::OsRng; use tari_bor::{Deserialize, Serialize}; use tari_crypto::{ keys::PublicKey as _, - ristretto::{RistrettoPublicKey, RistrettoSecretKey}, + ristretto::{RistrettoPublicKey, RistrettoSchnorr, RistrettoSecretKey}, }; use tari_ootle_address::RistrettoOotleAddress; +use tari_ootle_common_types::Signable; use tari_template_lib::prelude::RistrettoPublicKeyBytes; #[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)] @@ -53,12 +56,17 @@ impl AsRef for KeyBranch { } } +impl Display for KeyBranch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + #[derive(Clone)] pub struct WalletKeyRecord { pub(crate) key_id: KeyId, pub(crate) public_key: RistrettoPublicKey, pub(crate) secret_key: RistrettoSecretKey, - pub(crate) branch: KeyBranch, pub(crate) is_active: bool, } @@ -74,10 +82,6 @@ impl WalletKeyRecord { pub fn public_key(&self) -> &RistrettoPublicKey { &self.public_key } - - pub fn branch(&self) -> KeyBranch { - self.branch - } } #[derive(Clone, serde::Serialize, serde::Deserialize)] @@ -106,8 +110,7 @@ impl ImportedWalletKey { #[derive(Clone)] pub struct DerivedWalletKey { pub key: RistrettoSecretKey, - pub branch: KeyBranch, - pub key_index: DerivedKeyIndex, + pub derived_key_id: DerivedKeyId, } impl DerivedWalletKey { @@ -115,15 +118,22 @@ impl DerivedWalletKey { RistrettoPublicKey::from_secret_key(&self.key) } + pub fn key_index(&self) -> DerivedKeyIndex { + self.derived_key_id.index + } + pub fn as_key_id(&self) -> KeyId { - KeyId::derived(self.key_index) + self.derived_key_id.into() + } + + pub fn derived_key_id(&self) -> &DerivedKeyId { + &self.derived_key_id } } #[derive(Clone)] pub struct WalletPublicKey { pub public_key: RistrettoPublicKey, - pub branch: KeyBranch, pub key_id: KeyId, } @@ -141,7 +151,6 @@ impl From for WalletPublicKey { fn from(derived: DerivedWalletKey) -> Self { Self { key_id: derived.as_key_id(), - branch: derived.branch, public_key: derived.to_public_key(), } } @@ -165,6 +174,12 @@ impl WalletSecretKey { pub fn to_public_key(&self) -> RistrettoPublicKey { RistrettoPublicKey::from_secret_key(&self.secret) } + + pub fn sign, C>(&self, context: C, item: &T) -> RistrettoSchnorr { + let message = item.as_signing_message(context); + RistrettoSchnorr::sign(&self.secret, message.as_ref(), &mut OsRng) + .expect("message is hashed internally into canonical form, so signing is infallible") + } } impl From for WalletSecretKey { @@ -218,7 +233,7 @@ pub struct DerivedKeyPair { impl DerivedKeyPair { pub fn key_index(&self) -> DerivedKeyIndex { - self.derived_key.key_index + self.derived_key.derived_key_id.index } pub fn public_key(&self) -> &RistrettoPublicKey { @@ -283,29 +298,42 @@ impl From for KeyIdOrPublicKey { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] #[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] -pub struct BranchAndKeyId { +pub struct DerivedKeyId { pub branch: KeyBranch, - pub key_id: KeyId, + pub index: DerivedKeyIndex, } -impl BranchAndKeyId { - pub fn new(branch: KeyBranch, key_id: KeyId) -> Self { - Self { branch, key_id } +impl DerivedKeyId { + pub fn new(branch: KeyBranch, index: DerivedKeyIndex) -> Self { + Self { branch, index } } - pub fn for_account(key_id: KeyId) -> Self { - Self { - branch: KeyBranch::Account, - key_id, - } + pub fn index(&self) -> DerivedKeyIndex { + self.index + } + + pub fn branch(&self) -> KeyBranch { + self.branch + } + + pub fn as_key_id(&self) -> KeyId { + KeyId::derived(self.branch, self.index) } } -impl Display for BranchAndKeyId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self.branch.as_str(), self.key_id) +impl TryFrom for DerivedKeyId { + type Error = anyhow::Error; + + fn try_from(value: KeyId) -> Result { + match value { + KeyId::Derived { key_branch, index } => Ok(DerivedKeyId { + branch: key_branch, + index, + }), + KeyId::Imported { .. } => Err(anyhow!("Cannot convert Imported KeyId to DerivedKeyId")), + } } } @@ -313,14 +341,17 @@ impl Display for BranchAndKeyId { #[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub enum KeyId { /// Derived from the seed key - Derived { index: DerivedKeyIndex }, + Derived { + key_branch: KeyBranch, + index: DerivedKeyIndex, + }, /// Imported key Imported { local_key_id: ImportedKeyId }, } impl KeyId { - pub fn derived(index: DerivedKeyIndex) -> Self { - Self::Derived { index } + pub fn derived(key_branch: KeyBranch, index: DerivedKeyIndex) -> Self { + Self::Derived { key_branch, index } } pub fn imported(local_key_id: ImportedKeyId) -> Self { @@ -329,7 +360,7 @@ impl KeyId { pub fn derived_index(&self) -> Option { match self { - Self::Derived { index } => Some(*index), + Self::Derived { index, .. } => Some(*index), Self::Imported { .. } => None, } } @@ -340,12 +371,28 @@ impl KeyId { Self::Derived { .. } => None, } } + + pub fn derived_branch(&self) -> Option { + match self { + Self::Derived { key_branch, .. } => Some(*key_branch), + Self::Imported { .. } => None, + } + } +} + +impl From for KeyId { + fn from(derived: DerivedKeyId) -> Self { + Self::Derived { + key_branch: derived.branch, + index: derived.index, + } + } } impl Display for KeyId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Derived { index } => write!(f, "Derived({index})"), + Self::Derived { key_branch, index } => write!(f, "Derived({key_branch},{index})"), Self::Imported { local_key_id: local_import_id, } => write!(f, "Imported({local_import_id})"), diff --git a/crates/wallet/sdk/src/network.rs b/crates/wallet/sdk/src/network.rs index 68c51d33d5..7e82261e1c 100644 --- a/crates/wallet/sdk/src/network.rs +++ b/crates/wallet/sdk/src/network.rs @@ -11,7 +11,7 @@ use tari_engine_types::{ substate::{Substate, SubstateId, SubstateValue}, Utxo, }; -use tari_ootle_common_types::{shard::Shard, Epoch, StateVersion}; +use tari_ootle_common_types::{optional::IsNotFoundError, shard::Shard, Epoch, StateVersion}; use tari_template_abi::TemplateDef; use tari_template_lib::{ models::{ResourceAddress, UtxoId}, @@ -27,7 +27,7 @@ use crate::models::UtxoUpdatePayload; pub type UtxoUpdateStream = Pin> + Send + 'static>>; pub trait WalletNetworkInterface { - type Error: std::error::Error + Send + Sync + 'static; + type Error: IsNotFoundError + StatusResponseError + std::error::Error + Send + Sync + 'static; fn query_substate( &self, diff --git a/crates/wallet/sdk/src/sdk.rs b/crates/wallet/sdk/src/sdk.rs index 8c4c7e265a..7ca95d2c14 100644 --- a/crates/wallet/sdk/src/sdk.rs +++ b/crates/wallet/sdk/src/sdk.rs @@ -1,6 +1,8 @@ // Copyright 2023 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::{fmt::Debug, sync::Arc}; + use log::{info, warn}; use tari_common_types::seeds::{ cipher_seed::CipherSeed, @@ -9,12 +11,7 @@ use tari_common_types::seeds::{ seed_words::SeedWords, }; use tari_crypto::tari_utilities::SafePassword; -use tari_ootle_common_types::{ - optional::{IsNotFoundError, Optional}, - Epoch, - Network, - NetworkParseError, -}; +use tari_ootle_common_types::{optional::Optional, Epoch, Network, NetworkParseError}; use zeroize::Zeroizing; use crate::{ @@ -40,17 +37,14 @@ use crate::{ viewable_balance::ViewableBalanceApi, }, cipher_seed::{CipherSeedRestore, WalletCipherSeed}, - key_managers::local::LocalKeyManager, local_key_store::LocalKeyStore, models::EpochBirthday, - network::{StatusResponseError, WalletNetworkInterface}, - storage::{WalletStorageError, WalletStore}, + spec::WalletSdkSpec, + storage::WalletStorageError, }; const LOG_TARGET: &str = "wallet::sdk::api"; -pub type LocalSignerApi<'a, TStore> = SignerApi>>; - #[derive(Debug, Clone)] pub struct WalletSdkConfig { pub network: Network, @@ -58,95 +52,60 @@ pub struct WalletSdkConfig { pub override_keyring_password: Option, } -#[derive(Debug, Clone)] -pub struct WalletSdk { - store: TStore, - network_interface: TNetworkInterface, +pub struct WalletSdk { + store: TSpec::Store, + network_interface: TSpec::NetworkInterface, + key_store: TSpec::KeyStore, config: WalletSdkConfig, - loaded_cipher_seed: WalletCipherSeed, epoch_birthday: EpochBirthday, } -impl WalletSdk -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, -{ +impl WalletSdk { pub fn initialize( - store: TStore, - indexer: TNetworkInterface, + store: TSpec::Store, + indexer: TSpec::NetworkInterface, + key_store: TSpec::KeyStore, config: WalletSdkConfig, epoch_birthday: EpochBirthday, - ) -> Result, WalletSdkError> { - // initialize network - if let Some(network) = Self::get_store_network(&store)? { - if config.network != network { - return Err(WalletSdkError::InvariantError { - details: format!( - "Network mismatch. Config network is {:?} but database network is {:?}", - config.network, network - ), - }); - } - } else { - ConfigApi::new(&store).set(ConfigKey::Network, config.network.as_key_str())?; - } + ) -> Result { + Self::check_or_set_store_network(&store, config.network)?; Ok(Self { store, network_interface: indexer, + key_store, config, - loaded_cipher_seed: WalletCipherSeed::None, epoch_birthday, }) } - pub fn get_store_network(store: &TStore) -> Result, WalletSdkError> { + pub fn get_store_network(store: &TSpec::Store) -> Result, WalletSdkError> { let config_api = ConfigApi::new(store); let network = config_api.get(ConfigKey::Network).optional()?; Ok(network) } - /// Initializes the cipher seed for the wallet. Either creating a new cipher seed or recovering it from the provided - /// seed words if provided and necessary. Returns true if the cipher seed was recovered from the seed words, - /// otherwise false. - pub fn initialize_cipher_seed(&mut self, restore: CipherSeedRestore<'_>) -> Result { - match self.load_cipher_seed()? { - Some(_) => { - if !restore.is_create_new() { - warn!( - target: LOG_TARGET, - "⚠️ Wallet already initialized. Ignoring seed words provided for recovery.", - ); - } - let requires_recovery = self.config_api().get(ConfigKey::RecoveryNeeded).optional()?; - // This should have been set - it is an error if it is not - requires_recovery.ok_or_else(|| WalletSdkError::InvariantError { - details: "Cipher seed already initialized but recovery_needed not set.".to_string(), - }) - }, - None => match restore { - CipherSeedRestore::CreateNewIfRequired => { - self.create_cipher_seed()?; - self.config_api().set(ConfigKey::RecoveryNeeded, &false)?; - Ok(false) - }, - CipherSeedRestore::FromSeedWords(seed_words) => { - self.restore_cipher_seed_from_seed_words(seed_words)?; - info!(target: LOG_TARGET, "🔑 Successfully restored wallet seed key!"); - self.config_api().set(ConfigKey::RecoveryNeeded, &true)?; - Ok(true) - }, - }, + fn check_or_set_store_network(store: &TSpec::Store, config_network: Network) -> Result<(), WalletSdkError> { + if let Some(network) = Self::get_store_network(store)? { + if config_network != network { + return Err(WalletSdkError::InvariantError { + details: format!( + "Network mismatch. Config network is {:?} but database network is {:?}", + config_network, network + ), + }); + } + } else { + ConfigApi::new(&store).set(ConfigKey::Network, config_network.as_key_str())?; } + Ok(()) } - pub fn store(&self) -> &TStore { + pub fn store(&self) -> &TSpec::Store { &self.store } - pub fn config_api(&self) -> ConfigApi<'_, TStore> { + pub fn config_api(&self) -> ConfigApi<'_, TSpec::Store> { ConfigApi::new(&self.store) } @@ -158,51 +117,49 @@ where self.config.network } - pub fn get_network_interface(&self) -> &TNetworkInterface { + pub fn get_network_interface(&self) -> &TSpec::NetworkInterface { &self.network_interface } - pub fn locks_api(&self) -> LocksApi<'_, TStore> { + pub fn locks_api(&self) -> LocksApi<'_, TSpec::Store> { LocksApi::new(&self.store) } - pub fn event_api(&self) -> EventsApi<'_, TStore> { + pub fn event_api(&self) -> EventsApi<'_, TSpec::Store> { EventsApi::new(&self.store) } /// Returns the KeyManager API for the wallet. - pub fn key_manager_api(&self) -> KeyManagerApi<'_, TStore> { + /// This key manager uses the configured key store to access key material. + pub fn key_manager_api(&self) -> KeyManagerApi<'_, TSpec> { let network = self.config.network; KeyManagerApi::new( network, &self.store, - LocalKeyStore::new(&self.loaded_cipher_seed, self.password_manager_api(), &self.store), + &self.key_store, self.password_manager_api(), self.epoch_birthday, ) } - /// Returns the Signer API for the wallet if the cipher seed has been initialized. This signer uses the local key - /// store where key material is kept in the local database. - pub fn local_signer_api(&self) -> LocalSignerApi<'_, TStore> { - let store = LocalKeyStore::new(&self.loaded_cipher_seed, self.password_manager_api(), &self.store); - let backend = LocalKeyManager::new(store); - SignerApi::new(backend) + /// Returns the Signer API for the wallet. This API uses the configured key store. + pub fn signer_api(&self) -> SignerApi<'_, TSpec> { + SignerApi::new(self.key_manager_api()) } - pub(crate) fn password_manager_api(&self) -> PasswordManagerApi<'_, TStore> { + pub(crate) fn password_manager_api(&self) -> PasswordManagerApi<'_, TSpec::Store> { PasswordManagerApi::new(self.config_api(), &self.config) } - pub fn transaction_api(&self) -> TransactionApi<'_, TStore, TNetworkInterface> { + pub fn transaction_api(&self) -> TransactionApi<'_, TSpec::Store, TSpec::NetworkInterface> { TransactionApi::new(&self.store, &self.network_interface) } - pub fn substate_api(&self) -> SubstatesApi<'_, TStore, TNetworkInterface> { + pub fn substate_api(&self) -> SubstatesApi<'_, TSpec::Store, TSpec::NetworkInterface> { SubstatesApi::new(&self.store, &self.network_interface) } - pub fn accounts_api(&self) -> AccountsApi<'_, TStore, TNetworkInterface> { + pub fn accounts_api(&self) -> AccountsApi<'_, TSpec> { AccountsApi::new( self.config.network, &self.store, @@ -212,7 +169,7 @@ where ) } - pub fn resources_api(&self) -> ResourcesApi<'_, TStore> { + pub fn resources_api(&self) -> ResourcesApi<'_, TSpec::Store> { ResourcesApi::new(&self.store) } @@ -220,11 +177,11 @@ where ConfidentialCryptoApi::new() } - pub fn confidential_outputs_api(&self) -> ConfidentialOutputsApi<'_, TStore> { + pub fn confidential_outputs_api(&self) -> ConfidentialOutputsApi<'_, TSpec> { ConfidentialOutputsApi::new(&self.store, self.key_manager_api(), self.confidential_crypto_api()) } - pub fn confidential_transfer_api(&self) -> ConfidentialTransferApi<'_, TStore, TNetworkInterface> { + pub fn confidential_transfer_api(&self) -> ConfidentialTransferApi<'_, TSpec> { ConfidentialTransferApi::new( self.key_manager_api(), self.accounts_api(), @@ -241,7 +198,7 @@ where StealthCryptoApi::new() } - pub fn stealth_transfer_api(&self) -> StealthTransferApi<'_, TStore, TNetworkInterface> { + pub fn stealth_transfer_api(&self) -> StealthTransferApi<'_, TSpec> { StealthTransferApi::new( self.accounts_api(), self.stealth_outputs_api(), @@ -252,7 +209,7 @@ where ) } - pub fn stealth_outputs_api(&self) -> StealthOutputsApi<'_, TStore> { + pub fn stealth_outputs_api(&self) -> StealthOutputsApi<'_, TSpec> { StealthOutputsApi::new( self.store(), self.key_manager_api(), @@ -261,11 +218,11 @@ where ) } - pub fn non_fungible_api(&self) -> NonFungibleTokensApi<'_, TStore> { + pub fn non_fungible_api(&self) -> NonFungibleTokensApi<'_, TSpec::Store> { NonFungibleTokensApi::new(&self.store) } - pub fn template_api(&self) -> TemplateApi<'_, TStore> { + pub fn template_api(&self) -> TemplateApi<'_, TSpec::Store> { TemplateApi::new(&self.store) } @@ -276,34 +233,57 @@ where pub fn calculate_birthday_epoch(&self) -> Epoch { self.epoch_birthday.calculate_current_epoch() } +} - /// Tries to get encrypted cipher seed from DB and decrypts it using OS keyring if possible. - fn load_cipher_seed(&mut self) -> Result, WalletSdkError> { - // Workaround for borrow checker limitation as described in https://blog.polybdenum.com/2024/12/21/four-limitations-of-rust-s-borrow-checker.html - if self.loaded_cipher_seed.cipher_seed().is_some() { - return Ok(Some(self.loaded_cipher_seed.cipher_seed().expect("checked above"))); - } +impl WalletSdk +where TSpec: WalletSdkSpec +{ + pub fn initialize_with_local_key_store( + store: TSpec::Store, + indexer: TSpec::NetworkInterface, + config: WalletSdkConfig, + epoch_birthday: EpochBirthday, + ) -> Result { + Self::check_or_set_store_network(&store, config.network)?; - let Some(cipher_seed_encrypted) = self - .config_api() - .get::>>(ConfigKey::CipherSeed) + let cipher_seed = Self::load_cipher_seed( + ConfigApi::new(&store), + PasswordManagerApi::new(ConfigApi::new(&store), &config), + )? + .map(WalletCipherSeed::CipherSeed) + .unwrap_or(WalletCipherSeed::None); + + Ok(Self { + store, + network_interface: indexer, + key_store: LocalKeyStore::new(cipher_seed), + config, + epoch_birthday, + }) + } + + fn load_cipher_seed( + config_api: ConfigApi<'_, TSpec::Store>, + password_manager_api: PasswordManagerApi<'_, TSpec::Store>, + ) -> Result>, WalletSdkError> { + let Some(cipher_seed_encrypted) = config_api + .get::>>(ConfigKey::CipherSeed) .optional()? else { // Cipher seed not found in DB. This is expected if the wallet has not been initialized yet. return Ok(None); }; - let password = self.password_manager_api().get_cipher_seed_password()?; + let password = password_manager_api.get_cipher_seed_password()?; let cipher_seed = CipherSeed::from_enciphered_bytes(&cipher_seed_encrypted, Some(password))?; - self.loaded_cipher_seed = cipher_seed.into(); - Ok(self.loaded_cipher_seed.cipher_seed()) + Ok(Some(Arc::new(cipher_seed))) } fn create_cipher_seed(&mut self) -> Result<(), WalletSdkError> { let password = self.password_manager_api().create_cipher_seed_password()?; - let cipher_seed = CipherSeed::new(); + let cipher_seed = CipherSeed::random(); let encrypted_cipher_seed = cipher_seed.encipher(Some(password))?; self.config_api().set(ConfigKey::CipherSeed, &encrypted_cipher_seed)?; - self.loaded_cipher_seed = cipher_seed.into(); + self.key_store.set_cipher_seed(Arc::new(cipher_seed)); Ok(()) } @@ -314,18 +294,89 @@ where let cipher_seed = CipherSeed::from_mnemonic(seed_words, None)?; let encrypted_cipher_seed = cipher_seed.encipher(Some(password))?; self.config_api().set(ConfigKey::CipherSeed, &encrypted_cipher_seed)?; - self.loaded_cipher_seed = cipher_seed.into(); + self.key_store.set_cipher_seed(Arc::new(cipher_seed)); Ok(()) } /// Retrieve the seed words from current cipher seed stored. pub fn load_seed_words(&mut self) -> Result, WalletSdkError> { let seed_words = self - .load_cipher_seed()? + .key_store + .cipher_seed() .map(|s| s.to_mnemonic(MnemonicLanguage::English, None)) .transpose()?; Ok(seed_words) } + + pub fn is_recovery_needed(&self) -> Result { + let recovery_needed = self + .config_api() + .get::(ConfigKey::RecoveryNeeded) + .optional()? + .unwrap_or(false); + Ok(recovery_needed) + } + + /// Initializes the cipher seed for the wallet. Either creating a new cipher seed or recovering it from the provided + /// seed words if provided and necessary. Returns true if the cipher seed was recovered from the seed words, + /// otherwise false. + pub fn initialize_cipher_seed(&mut self, restore: CipherSeedRestore<'_>) -> Result { + match self.key_store.cipher_seed() { + Some(_) => { + if !restore.is_create_new() { + warn!( + target: LOG_TARGET, + "⚠️ Wallet already initialized. Ignoring seed words provided for recovery.", + ); + } + let requires_recovery = self.config_api().get(ConfigKey::RecoveryNeeded).optional()?; + // This should have been set - it is an error if it is not + requires_recovery.ok_or_else(|| WalletSdkError::InvariantError { + details: "Cipher seed already initialized but recovery_needed not set.".to_string(), + }) + }, + None => match restore { + CipherSeedRestore::CreateNewIfRequired => { + self.create_cipher_seed()?; + self.config_api().set(ConfigKey::RecoveryNeeded, &false)?; + Ok(false) + }, + CipherSeedRestore::FromSeedWords(seed_words) => { + self.restore_cipher_seed_from_seed_words(seed_words)?; + info!(target: LOG_TARGET, "🔑 Successfully restored wallet seed key!"); + self.config_api().set(ConfigKey::RecoveryNeeded, &true)?; + Ok(true) + }, + }, + } + } +} + +impl Clone for WalletSdk +where + TSpec: WalletSdkSpec, + TSpec::Store: Clone, + TSpec::NetworkInterface: Clone, + TSpec::KeyStore: Clone, +{ + fn clone(&self) -> Self { + Self { + store: self.store.clone(), + network_interface: self.network_interface.clone(), + key_store: self.key_store.clone(), + config: self.config.clone(), + epoch_birthday: self.epoch_birthday, + } + } +} + +impl Debug for WalletSdk { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("WalletSdk") + .field("config", &self.config) + .field("epoch_birthday", &self.epoch_birthday) + .finish() + } } #[derive(Debug, thiserror::Error)] diff --git a/crates/wallet/sdk/src/spec.rs b/crates/wallet/sdk/src/spec.rs new file mode 100644 index 0000000000..a021a078e3 --- /dev/null +++ b/crates/wallet/sdk/src/spec.rs @@ -0,0 +1,18 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use crate::{key_managers::WalletKeyStore, network::WalletNetworkInterface, storage::WalletStore}; + +pub trait WalletSdkSpec { + type Store: WalletStore; + type KeyStore: WalletKeyStore; + type NetworkInterface: WalletNetworkInterface; +} + +// Allow: (previously warn) this is a known limitation of the type checker that may be lifted in a future edition. +// see issue #112792 for more information + +#[allow(type_alias_bounds)] +pub type KeyStoreError = ::Error; +#[allow(type_alias_bounds)] +pub type NetworkInterfaceError = ::Error; diff --git a/crates/wallet/sdk/src/storage/mod.rs b/crates/wallet/sdk/src/storage/mod.rs index 0cbe0f86a6..5fcd2daf13 100644 --- a/crates/wallet/sdk/src/storage/mod.rs +++ b/crates/wallet/sdk/src/storage/mod.rs @@ -72,6 +72,6 @@ impl WriteableWalletStore for &T { } } -pub trait WalletStore: ReadableWalletStore + WriteableWalletStore {} +pub trait WalletStore: ReadableWalletStore + WriteableWalletStore + Clone {} -impl WalletStore for T where T: ReadableWalletStore + WriteableWalletStore {} +impl WalletStore for T where T: ReadableWalletStore + WriteableWalletStore + Clone {} diff --git a/crates/wallet/sdk/tests/confidential_output_api.rs b/crates/wallet/sdk/tests/confidential_output_api.rs index f9d14e352e..0177b94fd0 100644 --- a/crates/wallet/sdk/tests/confidential_output_api.rs +++ b/crates/wallet/sdk/tests/confidential_output_api.rs @@ -6,7 +6,7 @@ mod support; use tari_crypto::commitment::HomomorphicCommitmentFactory; use tari_engine_types::{crypto::get_commitment_factory, substate::SubstateDiff, ToByteType}; use tari_ootle_wallet_sdk::{ - models::{ConfidentialOutputModel, KeyId, OutputStatus}, + models::{ConfidentialOutputModel, KeyBranch, KeyId, OutputStatus}, storage::{ReadableWalletStore, WalletStoreReader}, }; use tari_template_lib::types::EncryptedData; @@ -86,8 +86,8 @@ fn outputs_locked_and_finalized() { commitment: commitment_change, value: 24.into(), sender_public_nonce: None, - view_only_key_id: KeyId::derived(0), - owner_key_id: Some(KeyId::derived(0)), + view_only_key_id: KeyId::derived(KeyBranch::ViewOnlyKey, 0), + owner_key_id: Some(KeyId::derived(KeyBranch::Account, 0)), encrypted_data: EncryptedData::try_from(vec![0; EncryptedData::min_size()]).unwrap(), public_asset_tag: None, memo: None, diff --git a/crates/wallet/sdk/tests/support/harness.rs b/crates/wallet/sdk/tests/support/harness.rs index 096055acb6..6dbe5030b1 100644 --- a/crates/wallet/sdk/tests/support/harness.rs +++ b/crates/wallet/sdk/tests/support/harness.rs @@ -10,22 +10,38 @@ use tari_engine_types::{ ToByteType, Utxo, }; -use tari_ootle_common_types::{optional::Optional, shard::Shard, Epoch, Network, StateVersion}; +use tari_ootle_common_types::{ + optional::{IsNotFoundError, Optional}, + shard::Shard, + Epoch, + Network, + StateVersion, +}; use tari_ootle_wallet_sdk::{ cipher_seed::CipherSeedRestore, + local_key_store::LocalKeyStore, models::{ ConfidentialOutputModel, EpochBirthday, + KeyBranch, KeyId, OutputStatus, UtxoUpdateSet, WalletLockDropGuard, WalletLockId, }, - network::{SubstateQueryResult, TransactionQueryResult, UtxoUpdateStream, WalletNetworkInterface}, + network::{ + StatusResponseError, + SubstateQueryResult, + TransactionQueryResult, + UtxoUpdateStream, + WalletNetworkInterface, + WalletQueryErrorStatus, + }, storage::TagAndPublicNoncePair, WalletSdk, WalletSdkConfig, + WalletSdkSpec, }; use tari_ootle_wallet_storage_sqlite::SqliteWalletStore; use tari_template_abi::TemplateDef; @@ -37,9 +53,17 @@ use tari_template_lib::{ }; use tari_transaction::{Transaction, TransactionId}; +pub struct TestSdkSpec; + +impl WalletSdkSpec for TestSdkSpec { + type KeyStore = LocalKeyStore; + type NetworkInterface = PanicNetworkInterface; + type Store = SqliteWalletStore; +} + pub struct Test { store: SqliteWalletStore, - sdk: WalletSdk, + sdk: WalletSdk, _temp: tempfile::TempDir, } @@ -49,7 +73,7 @@ impl Test { let store = SqliteWalletStore::try_open(temp.path().join("data/wallet.sqlite")).unwrap(); store.run_migrations().unwrap(); - let mut sdk = WalletSdk::initialize( + let mut sdk = WalletSdk::initialize_with_local_key_store( store.clone(), PanicNetworkInterface, WalletSdkConfig { @@ -66,8 +90,8 @@ impl Test { .add_account( Some("test"), &Test::test_account_address(), - KeyId::derived(0), - KeyId::derived(0), + KeyId::derived(KeyBranch::ViewOnlyKey, 0), + KeyId::derived(KeyBranch::Account, 0), Epoch::zero(), true, true, @@ -117,8 +141,8 @@ impl Test { commitment, value: amount, sender_public_nonce: None, - view_only_key_id: KeyId::derived(0), - owner_key_id: Some(KeyId::derived(0)), + view_only_key_id: KeyId::derived(KeyBranch::ViewOnlyKey, 0), + owner_key_id: Some(KeyId::derived(KeyBranch::Account, 0)), encrypted_data: EncryptedData::try_from(vec![0; EncryptedData::min_size()]).unwrap(), public_asset_tag: None, memo: None, @@ -142,7 +166,7 @@ impl Test { .unwrap_or_default() } - pub fn sdk(&self) -> &WalletSdk { + pub fn sdk(&self) -> &WalletSdk { &self.sdk } @@ -156,7 +180,7 @@ pub struct PanicNetworkInterface; // TODO: test the substate scanning in the SDK impl WalletNetworkInterface for PanicNetworkInterface { - type Error = Infallible; + type Error = PanicError; #[allow(clippy::diverging_sub_expression)] async fn query_substate( @@ -219,3 +243,30 @@ impl WalletNetworkInterface for PanicNetworkInterface { panic!("PanicNetworkInterface called") } } + +#[derive(Debug)] +pub struct PanicError; + +impl std::fmt::Display for PanicError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "PanicError") + } +} + +impl std::error::Error for PanicError {} + +impl StatusResponseError for PanicError { + fn get_status(&self) -> WalletQueryErrorStatus { + panic!("get_status called on PanicError") + } + + fn get_error_message(&self) -> String { + panic!("get_error_message called on PanicError") + } +} + +impl IsNotFoundError for PanicError { + fn is_not_found_error(&self) -> bool { + false + } +} diff --git a/crates/wallet/sdk_services/src/account_monitor/monitor.rs b/crates/wallet/sdk_services/src/account_monitor/monitor.rs index a5b2376ea2..9f5d84679a 100644 --- a/crates/wallet/sdk_services/src/account_monitor/monitor.rs +++ b/crates/wallet/sdk_services/src/account_monitor/monitor.rs @@ -17,9 +17,8 @@ use tari_ootle_wallet_sdk::{ transaction::TransactionApiError, }, models::{NewAccountData, WalletEvent}, - network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, WalletSdk, + WalletSdkSpec, }; use tari_shutdown::ShutdownSignal; use tari_template_lib::{models::ResourceAddress, prelude::ComponentAddress}; @@ -41,27 +40,26 @@ use crate::{ const LOG_TARGET: &str = "tari::ootle::wallet_services::account_monitor"; -pub struct AccountMonitor { +pub struct AccountMonitor { notify_subscription: broadcast::Receiver, - wallet_sdk: WalletSdk, + wallet_sdk: WalletSdk, request_rx: mpsc::Receiver, pending_accounts: HashMap, utxo_scanner_handle: UtxoScannerHandle, periodic_scan_interval: Duration, enable_periodic_scanning_of_utxos: bool, - scanner: AccountScanner, + scanner: AccountScanner, shutdown_signal: ShutdownSignal, } -impl AccountMonitor +impl AccountMonitor where - TStore: WalletStore + Clone, - TNetworkInterface: WalletNetworkInterface + Clone, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, + TSpec: WalletSdkSpec, + WalletSdk: Clone, { pub fn new( notify: Notify, - wallet_sdk: WalletSdk, + wallet_sdk: WalletSdk, utxo_scanner_handle: UtxoScannerHandle, shutdown_signal: ShutdownSignal, ) -> (Self, AccountMonitorHandle) { diff --git a/crates/wallet/sdk_services/src/account_monitor/scanner.rs b/crates/wallet/sdk_services/src/account_monitor/scanner.rs index d817c656ba..b17a3e32f3 100644 --- a/crates/wallet/sdk_services/src/account_monitor/scanner.rs +++ b/crates/wallet/sdk_services/src/account_monitor/scanner.rs @@ -11,13 +11,12 @@ use tari_engine_types::{ substate::{Substate, SubstateDiff, SubstateId, SubstateValue}, vault::Vault, }; -use tari_ootle_common_types::optional::{IsNotFoundError, Optional}; +use tari_ootle_common_types::optional::Optional; use tari_ootle_wallet_sdk::{ apis::substate::ValidatorScanResult, models::{AccountChangedEvent, AccountCreatedEvent, AccountUpdate, NewAccountData, NonFungibleToken, WalletEvent}, - network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, WalletSdk, + WalletSdkSpec, }; use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS; use tari_template_lib::{ @@ -31,19 +30,16 @@ use crate::{account_monitor::monitor::AccountMonitorError, notify::Notify}; const LOG_TARGET: &str = "tari::ootle::wallet_services::account_monitor"; -#[derive(Debug, Clone)] -pub struct AccountScanner { +#[derive(Debug)] +pub struct AccountScanner { notify: Notify, - wallet_sdk: WalletSdk, + wallet_sdk: WalletSdk, } -impl AccountScanner -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, +impl AccountScanner +where TSpec: WalletSdkSpec { - pub fn new(notify: Notify, wallet_sdk: WalletSdk) -> Self { + pub fn new(notify: Notify, wallet_sdk: WalletSdk) -> Self { Self { notify, wallet_sdk } } diff --git a/crates/wallet/sdk_services/src/account_recovery/service.rs b/crates/wallet/sdk_services/src/account_recovery/service.rs index b5e311bc18..7d2531597c 100644 --- a/crates/wallet/sdk_services/src/account_recovery/service.rs +++ b/crates/wallet/sdk_services/src/account_recovery/service.rs @@ -16,8 +16,8 @@ use tari_ootle_wallet_sdk::{ apis::config::ConfigKey, models::{DerivedWalletKey, KeyBranch, KeyId}, network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, WalletSdk, + WalletSdkSpec, }; use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS; use tokio::time; @@ -27,21 +27,20 @@ use crate::{account_monitor::AccountMonitorHandle, account_recovery::AccountReco const LOG_TARGET: &str = "tari::ootle_wallet_daemon::resource_scanner"; /// Scans through all the substates to find related resources to current wallet. -pub struct AccountRecoveryService { - wallet_sdk: WalletSdk, +pub struct AccountRecoveryService { + wallet_sdk: WalletSdk, account_monitor_handle: AccountMonitorHandle, abandon_after_not_found: usize, cipher_seed_birthday_epoch: Epoch, } -impl AccountRecoveryService +impl AccountRecoveryService where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, + TSpec: WalletSdkSpec, + ::Error: IsNotFoundError + StatusResponseError, { pub fn new( - wallet_sdk: WalletSdk, + wallet_sdk: WalletSdk, account_monitor_handle: AccountMonitorHandle, abandon_after_not_found: usize, cipher_seed_birthday_epoch: Epoch, @@ -77,7 +76,7 @@ where let mut not_found_accounts_count = 0; let mut found_accounts_count = 0; let initial_key_index = match key_manager_api.get_active_key(KeyBranch::Account) { - Ok(key) => key.key_index, + Ok(key) => key.key_index(), Err(err) => { error!(target: LOG_TARGET, "Error getting active key: {err}. Scanning failed..."); return; @@ -92,11 +91,11 @@ where return; }, }; - info!(target: LOG_TARGET, "🔍️ Attempting to recover account with key index {}", key.key_index); + info!(target: LOG_TARGET, "🔍️ Attempting to recover account with key index {}", key.key_index()); match self.try_recover_account(&key).await { Ok(true) => { - last_found_key = Some(key.key_index); - info!(target: LOG_TARGET, "✅ Account with key index {} found!", key.key_index); + last_found_key = Some(key.key_index()); + info!(target: LOG_TARGET, "✅ Account with key index {} found!", key.key_index()); not_found_accounts_count = 0; found_accounts_count += 1; }, @@ -171,14 +170,14 @@ where // We cannot find this account on chain, however there could be UTXOs owned by this key which we'll need // to scan for. self.wallet_sdk.accounts_api().add_account( - Some(format!("recovered-account-{}", key.key_index).as_str()), + Some(format!("recovered-account-{}", key.key_index()).as_str()), &account_addr, key.as_key_id(), key.as_key_id(), birthday_epoch, false, // if this is the first account, set it as the default - key.key_index == 0, + key.key_index() == 0, )?; // Update UTXOs @@ -220,17 +219,17 @@ where "🔑 Adding account {} with owner key {} and key index {}", account_addr, component.owner_key.display(), - key.key_index + key.key_index() ); self.wallet_sdk.accounts_api().add_account( - Some(format!("recovered-account-{}", key.key_index).as_str()), + Some(format!("recovered-account-{}", key.key_index()).as_str()), &account_addr, - KeyId::derived(key.key_index), - KeyId::derived(key.key_index), + KeyId::derived(KeyBranch::ViewOnlyKey, key.key_index()), + KeyId::derived(KeyBranch::Account, key.key_index()), birthday_epoch, true, // if this is the first account, set it as the default - key.key_index == 0, + key.key_index() == 0, )?; // Update vaults, UTXOs, nfts etc diff --git a/crates/wallet/sdk_services/src/transaction_service/service.rs b/crates/wallet/sdk_services/src/transaction_service/service.rs index a5b9120651..f88630b2b7 100644 --- a/crates/wallet/sdk_services/src/transaction_service/service.rs +++ b/crates/wallet/sdk_services/src/transaction_service/service.rs @@ -17,8 +17,8 @@ use tari_ootle_wallet_sdk::{ WalletLockId, }, network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, WalletSdk, + WalletSdkSpec, }; use tari_shutdown::ShutdownSignal; use tari_transaction::{Transaction, TransactionId}; @@ -36,25 +36,27 @@ use crate::notify::Notify; const LOG_TARGET: &str = "tari::ootle::wallet_services::transaction_service"; -pub struct TransactionService { +pub struct TransactionService { rx_request: mpsc::Receiver, notify: Notify, - wallet_sdk: WalletSdk, + wallet_sdk: WalletSdk, trigger_poll: watch::Sender<()>, rx_trigger: watch::Receiver<()>, poll_semaphore: Arc, shutdown_signal: ShutdownSignal, } -impl TransactionService +impl TransactionService where - TStore: WalletStore + Clone + Send + Sync + 'static, - TNetworkInterface: WalletNetworkInterface + Clone + Send + Sync + 'static, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, + TSpec: WalletSdkSpec + Send + 'static, + TSpec::Store: Clone + Send + Sync + 'static, + TSpec::NetworkInterface: Clone + Send + Sync + 'static, + TSpec::KeyStore: Clone + Send + Sync + 'static, + ::Error: IsNotFoundError + StatusResponseError, { pub fn new( notify: Notify, - wallet_sdk: WalletSdk, + wallet_sdk: WalletSdk, shutdown_signal: ShutdownSignal, ) -> (Self, TransactionServiceHandle) { let (trigger, rx_trigger) = watch::channel(()); @@ -211,7 +213,7 @@ where Ok(()) } - fn clear_stale_locks(wallet_sdk: &WalletSdk) -> Result<(), TransactionServiceError> { + fn clear_stale_locks(wallet_sdk: &WalletSdk) -> Result<(), TransactionServiceError> { let transaction_api = wallet_sdk.locks_api(); let num_cleared = transaction_api.clear_stale_locks()?; if num_cleared > 0 { @@ -230,7 +232,7 @@ where } async fn resubmit_new_transactions( - wallet_sdk: &WalletSdk, + wallet_sdk: &WalletSdk, notify: &Notify, ) -> Result<(), TransactionServiceError> { let transaction_api = wallet_sdk.transaction_api(); @@ -271,7 +273,7 @@ where } async fn check_pending_transactions( - wallet_sdk: &WalletSdk, + wallet_sdk: &WalletSdk, notify: &Notify, ) -> Result<(), TransactionServiceError> { let transaction_api = wallet_sdk.transaction_api(); diff --git a/crates/wallet/sdk_services/src/utxo_scanner/scanner.rs b/crates/wallet/sdk_services/src/utxo_scanner/scanner.rs index c4fc506614..bd35662524 100644 --- a/crates/wallet/sdk_services/src/utxo_scanner/scanner.rs +++ b/crates/wallet/sdk_services/src/utxo_scanner/scanner.rs @@ -1,12 +1,10 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use tari_ootle_common_types::optional::IsNotFoundError; use tari_ootle_wallet_sdk::{ models::{AccountWithAddress, WalletEvent}, - network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, WalletSdk, + WalletSdkSpec, }; use tari_template_lib::models::ResourceAddress; @@ -15,18 +13,13 @@ use crate::{ utxo_scanner::{StealthScannerApiError, UtxoScanRoundStats, UtxoScannerRound}, }; -pub struct UtxoScanner { - sdk: WalletSdk, +pub struct UtxoScanner { + sdk: WalletSdk, wallet_notify: Notify, } -impl UtxoScanner -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, -{ - pub fn new(sdk: WalletSdk, wallet_notify: Notify) -> Self { +impl UtxoScanner { + pub fn new(sdk: WalletSdk, wallet_notify: Notify) -> Self { Self { sdk, wallet_notify } } @@ -37,10 +30,7 @@ where ) -> Result { let network = self.sdk.config_api().get_network()?; - let view_key = self - .sdk - .key_manager_api() - .get_view_only_key(account.view_only_key_id())?; + let view_key = self.sdk.key_manager_api().get_key(account.view_only_key_id())?; let mut scanner_round = UtxoScannerRound::new( network, diff --git a/crates/wallet/sdk_services/src/utxo_scanner/scanner_round.rs b/crates/wallet/sdk_services/src/utxo_scanner/scanner_round.rs index 682a361689..0af0ed5aeb 100644 --- a/crates/wallet/sdk_services/src/utxo_scanner/scanner_round.rs +++ b/crates/wallet/sdk_services/src/utxo_scanner/scanner_round.rs @@ -7,13 +7,7 @@ use futures::StreamExt; use log::{debug, info, trace, warn}; use tari_crypto::ristretto::RistrettoPublicKey; use tari_engine_types::ConvertFromByteType; -use tari_ootle_common_types::{ - optional::{IsNotFoundError, Optional}, - shard::Shard, - Network, - NumPreshards, - StateVersion, -}; +use tari_ootle_common_types::{optional::Optional, shard::Shard, Network, NumPreshards, StateVersion}; use tari_ootle_wallet_sdk::{ models::{ AccountWithAddress, @@ -25,9 +19,11 @@ use tari_ootle_wallet_sdk::{ WalletSecretKey, WalletUtxoUpdate, }, - network::{StatusResponseError, UtxoUpdateStream, WalletNetworkInterface}, - storage::{WalletStorageError, WalletStore, WalletStoreReader, WalletStoreWriter}, + network::{UtxoUpdateStream, WalletNetworkInterface}, + storage::{ReadableWalletStore, WalletStorageError, WalletStoreReader, WalletStoreWriter, WriteableWalletStore}, + NetworkInterfaceError, WalletSdk, + WalletSdkSpec, }; use tari_template_lib::models::{ComponentAddress, ResourceAddress, UtxoAddress}; @@ -37,13 +33,13 @@ const LOG_TARGET: &str = "tari::ootle::wallet_services::scanner_round"; // TODO: either fetch num preshards from the network or we should hardcode it to a single value for all apps const NUM_PRESHARDS: NumPreshards = NumPreshards::P256; -pub struct UtxoScannerRound<'a, TStore, TNetworkInterface> { +pub struct UtxoScannerRound<'a, TSpec: WalletSdkSpec> { network: Network, account: &'a AccountWithAddress, view_key: &'a WalletSecretKey, resource_address: &'a ResourceAddress, - sdk: &'a WalletSdk, + sdk: &'a WalletSdk, stats: UtxoScanRoundStats, shard_state_versions_to_set: HashMap, @@ -52,15 +48,12 @@ pub struct UtxoScannerRound<'a, TStore, TNetworkInterface> { notify: &'a Notify, } -impl<'a, TStore, TNetworkInterface> UtxoScannerRound<'a, TStore, TNetworkInterface> -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, +impl<'a, TSpec> UtxoScannerRound<'a, TSpec> +where TSpec: WalletSdkSpec { pub fn new( network: Network, - sdk: &'a WalletSdk, + sdk: &'a WalletSdk, account: &'a AccountWithAddress, view_key: &'a WalletSecretKey, resource_address: &'a ResourceAddress, @@ -141,7 +134,7 @@ where async fn process_stream( &mut self, - mut stream: UtxoUpdateStream, + mut stream: UtxoUpdateStream>, ) -> Result { let mut num_received = 0usize; let mut sos: Option = None; @@ -301,7 +294,7 @@ where } fn spend( - tx: &mut TStore::WriteTransaction<'_>, + tx: &mut ::WriteTransaction<'_>, resource_address: &ResourceAddress, spent: &UtxoSpent, ) -> Result { diff --git a/crates/wallet/sdk_services/src/utxo_scanner/utxo_recovery.rs b/crates/wallet/sdk_services/src/utxo_scanner/utxo_recovery.rs index 66ce80b6c9..636c4da7c5 100644 --- a/crates/wallet/sdk_services/src/utxo_scanner/utxo_recovery.rs +++ b/crates/wallet/sdk_services/src/utxo_scanner/utxo_recovery.rs @@ -18,8 +18,9 @@ use tari_ootle_wallet_sdk::{ WalletEvent, }, network::{StatusResponseError, WalletNetworkInterface}, - storage::{WalletStorageError, WalletStore, WalletStoreReader, WalletStoreWriter}, + storage::{ReadableWalletStore, WalletStorageError, WalletStoreReader, WalletStoreWriter, WriteableWalletStore}, WalletSdk, + WalletSdkSpec, }; use tari_template_lib::models::{ComponentAddress, ResourceAddress, UtxoAddress, UtxoId}; use tokio::sync::watch; @@ -28,19 +29,18 @@ use crate::{notify::Notify, utxo_scanner::StealthScannerApiError}; const LOG_TARGET: &str = "tari::ootle::wallet_services::utxo_recovery"; -pub struct UtxoRecovery { - sdk: WalletSdk, +pub struct UtxoRecovery { + sdk: WalletSdk, notify: Option>, round_id: usize, } -impl UtxoRecovery +impl UtxoRecovery where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, + TSpec: WalletSdkSpec, + ::Error: IsNotFoundError + StatusResponseError, { - pub fn new(sdk: WalletSdk) -> Self { + pub fn new(sdk: WalletSdk) -> Self { Self { sdk, notify: None, @@ -238,13 +238,10 @@ where found: FoundUtxo, ) -> Result { let account = self.sdk.accounts_api().get_account_by_address(&found.account_addr)?; - let view_only_key = self - .sdk - .key_manager_api() - .get_view_only_key(account.view_only_key_id())?; + let view_only_key = self.sdk.key_manager_api().get_key(account.view_only_key_id())?; let account_key = account .owner_key_id() - .map(|key_id| self.sdk.key_manager_api().get_account_owner_key(key_id)) + .map(|key_id| self.sdk.key_manager_api().get_key(key_id)) .transpose()?; let keys = AccountAndViewKeys { account_public_key: *account.owner_public_key(), diff --git a/crates/wallet/sdk_services/src/utxo_scanner/worker.rs b/crates/wallet/sdk_services/src/utxo_scanner/worker.rs index 3d47869e1e..7e5154c22f 100644 --- a/crates/wallet/sdk_services/src/utxo_scanner/worker.rs +++ b/crates/wallet/sdk_services/src/utxo_scanner/worker.rs @@ -10,13 +10,7 @@ use std::{ use futures_bounded::PushError; use log::{info, warn}; -use tari_ootle_common_types::optional::IsNotFoundError; -use tari_ootle_wallet_sdk::{ - models::WalletEvent, - network::{StatusResponseError, WalletNetworkInterface}, - storage::WalletStore, - WalletSdk, -}; +use tari_ootle_wallet_sdk::{models::WalletEvent, WalletSdk, WalletSdkSpec}; use tari_template_lib::{models::ComponentAddress, prelude::ResourceAddress}; use tokio::{ sync::{mpsc, watch}, @@ -50,19 +44,20 @@ impl UtxoScannerHandle { } } -pub struct StealthUtxoScannerWorker { - scanner: StealthUtxoScanner, +pub struct StealthUtxoScannerWorker { + scanner: StealthUtxoScanner, } -impl StealthUtxoScannerWorker +impl StealthUtxoScannerWorker where - TStore: WalletStore + Clone + Send + Sync + 'static, - TNetworkInterface: WalletNetworkInterface + Clone + Send + Sync + 'static, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, + TSpec: WalletSdkSpec + Send + 'static, + TSpec::Store: Clone + Send + Sync + 'static, + TSpec::NetworkInterface: Clone + Send + Sync + 'static, + TSpec::KeyStore: Clone + Send + Sync + 'static, { - pub fn new(sdk: WalletSdk, notify: Notify) -> Self { + pub fn new(sdk: WalletSdk, notify: Notify) -> Self { Self { - scanner: StealthUtxoScanner::new(sdk.clone(), notify), + scanner: StealthUtxoScanner::new(sdk, notify), } } @@ -105,20 +100,21 @@ where type ScanResult = anyhow::Result<()>; -pub struct StealthUtxoScanner { +pub struct StealthUtxoScanner { in_progress_work: futures_bounded::FuturesMap, - sdk: WalletSdk, + sdk: WalletSdk, notify_tx: watch::Sender<()>, wallet_notify: Notify, } -impl StealthUtxoScanner +impl StealthUtxoScanner where - TStore: WalletStore + Clone + Send + Sync + 'static, - TNetworkInterface: WalletNetworkInterface + Clone + Send + Sync + 'static, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, + TSpec: WalletSdkSpec + 'static, + TSpec::Store: Clone + Send + Sync + 'static, + TSpec::NetworkInterface: Clone + Send + Sync + 'static, + TSpec::KeyStore: Clone + Send + Sync + 'static, { - pub(self) fn new(sdk: WalletSdk, wallet_events: Notify) -> Self { + pub(self) fn new(sdk: WalletSdk, wallet_events: Notify) -> Self { let (notify_tx, _) = watch::channel::<()>(()); Self { in_progress_work: futures_bounded::FuturesMap::new(Duration::from_secs(300), MAX_CONCURRENT_SCANS), @@ -181,17 +177,12 @@ where } } -async fn do_work( - sdk: WalletSdk, +async fn do_work( + sdk: WalletSdk, notify_tx: watch::Sender<()>, task: UtxoScanRequest, wallet_notify: Notify, -) -> ScanResult -where - TStore: WalletStore, - TNetworkInterface: WalletNetworkInterface, - TNetworkInterface::Error: IsNotFoundError + StatusResponseError, -{ +) -> ScanResult { info!(target: LOG_TARGET, "🔍 Scanning for UTXOs for {}", task); let account = sdk.accounts_api().get_account_by_address(&task.account_address)?; let stats = UtxoScanner::new(sdk, wallet_notify) diff --git a/crates/wallet/storage_sqlite/tests/accounts.rs b/crates/wallet/storage_sqlite/tests/accounts.rs index ad2b217ccc..c071fb907a 100644 --- a/crates/wallet/storage_sqlite/tests/accounts.rs +++ b/crates/wallet/storage_sqlite/tests/accounts.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use tari_ootle_common_types::Epoch; use tari_ootle_wallet_sdk::{ - models::{AccountUpdate, KeyId}, + models::{AccountUpdate, KeyBranch, KeyId}, storage::{CommittableStore, WalletStoreReader, WalletStoreWriter, WriteableWalletStore}, }; use tari_ootle_wallet_storage_sqlite::SqliteWalletStore; @@ -22,8 +22,8 @@ fn update_account() { tx.accounts_insert( Some("test"), &address, - KeyId::derived(0), - Some(KeyId::derived(0)), + KeyId::derived(KeyBranch::Account, 0), + Some(KeyId::derived(KeyBranch::Account, 0)), &RistrettoPublicKeyBytes::default(), &Default::default(), Epoch::zero(), diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index c2145451d8..5975941d2d 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -17,7 +17,6 @@ tari_ootle_storage = { workspace = true } tari_template_builtin = { workspace = true } tari_transaction_components = { workspace = true } -tari_transaction_key_manager = { workspace = true } minotari_app_grpc = { workspace = true } minotari_app_utilities = { workspace = true } minotari_node_grpc_client = { workspace = true } diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 1f942b0bba..2ed95d52e0 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -46,9 +46,8 @@ use tari_ootle_wallet_sdk::models::AccountWithAddress; use tari_sidechain::EvictionProof; use tari_transaction_components::{ consensus::ConsensusManager, - key_manager::{TariKeyId, TransactionKeyManagerInterface}, + key_manager::{KeyManager, TariKeyId, TransactionKeyManagerInterface}, }; -use tari_transaction_key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}; use template::RegisteredTemplate; use validator_node::ValidatorNodeProcess; use wallet::WalletProcess; @@ -89,7 +88,7 @@ pub struct TariWorld { pub claim_proofs: HashMap, pub substate_ids: IndexMap, pub num_databases_saved: usize, - pub key_manager: MemoryDbKeyManager, + pub key_manager: KeyManager, pub wallet_accounts: IndexMap, pub wallet_daemons: IndexMap, /// Used for all one-sided coinbase payments @@ -125,7 +124,7 @@ impl TariWorld { claim_proofs: HashMap::new(), substate_ids: IndexMap::new(), num_databases_saved: 0, - key_manager: create_memory_db_key_manager().await.unwrap(), + key_manager: KeyManager::new_random().unwrap(), wallet_accounts: IndexMap::new(), wallet_daemons: IndexMap::new(), minotari_wallet_private_key: wallet_private_key, @@ -318,10 +317,9 @@ impl TariWorld { } } - pub async fn script_key_id(&self) -> TariKeyId { + pub fn script_key_id(&self) -> TariKeyId { self.key_manager - .import_key(self.minotari_wallet_private_key.clone(), None) - .await + .create_encrypted_key(self.minotari_wallet_private_key.clone(), None) .unwrap() } diff --git a/integration_tests/src/miner.rs b/integration_tests/src/miner.rs index efb5830689..e150841c4c 100644 --- a/integration_tests/src/miner.rs +++ b/integration_tests/src/miner.rs @@ -32,11 +32,10 @@ use tari_common_types::tari_address::TariAddress; use tari_transaction_components::{ consensus::ConsensusManager, generate_coinbase_with_wallet_output, - key_manager::TariKeyId, + key_manager::{KeyManager, TariKeyId}, transaction_components::{MemoField, RangeProofType, WalletOutput}, MicroMinotari, }; -use tari_transaction_key_manager::MemoryDbKeyManager; use crate::{util::cucumber_log, TariWorld}; @@ -92,7 +91,7 @@ async fn create_base_node_client(world: &TariWorld, miner_name: &String) -> Base } async fn mine_block(world: &mut TariWorld, payment_address: &TariAddress, base_client: &mut BaseNodeClient) { - let key_id = world.script_key_id().await; + let key_id = world.script_key_id(); let (block_template, _) = create_block_template_with_coinbase( base_client, 0, @@ -123,7 +122,7 @@ async fn mine_block_without_wallet_with_template(base_client: &mut BaseNodeClien async fn create_block_template_with_coinbase( base_client: &mut BaseNodeClient, weight: u64, - key_manager: &mut MemoryDbKeyManager, + key_manager: &mut KeyManager, script_key_id: &TariKeyId, wallet_payment_address: &TariAddress, stealth_payment: bool, @@ -165,7 +164,6 @@ async fn create_block_template_with_coinbase( RangeProofType::BulletProofPlus, MemoField::new_empty(), ) - .await .unwrap(); let body = block_template.body.as_mut().unwrap(); diff --git a/integration_tests/src/wallet_daemon_client.rs b/integration_tests/src/wallet_daemon_client.rs index 2759d42b94..6142e3f429 100644 --- a/integration_tests/src/wallet_daemon_client.rs +++ b/integration_tests/src/wallet_daemon_client.rs @@ -29,7 +29,7 @@ use tari_ootle_address::OotleAddress; use tari_ootle_common_types::{Epoch, SubstateRequirement}; use tari_ootle_wallet_sdk::{ apis::{confidential_transfer::UtxoInputSelection, stealth_transfer::BadgeUsage}, - models::{Account, AccountWithAddress, BranchAndKeyId, KeyBranch, NonFungibleToken}, + models::{Account, AccountWithAddress, NonFungibleToken}, }; use tari_template_lib::{ prelude::{ResourceAddress, RistrettoPublicKeyBytes}, @@ -452,7 +452,7 @@ pub async fn submit_manifest_with_signing_keys( let transaction_submit_req = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: true, detect_inputs_use_unversioned: true, @@ -540,7 +540,7 @@ pub async fn submit_manifest( let transaction_submit_req = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: true, detect_inputs_use_unversioned: true, @@ -658,7 +658,7 @@ pub async fn create_component( let transaction_submit_req = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account(owner_key_id), + seal_signer: owner_key_id, other_signers: vec![], detect_inputs: true, detect_inputs_use_unversioned: true, @@ -949,7 +949,7 @@ async fn submit_unsigned_tx_and_wait_for_response( ); let submit_req = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::new(KeyBranch::Account, account.owner_key_id.expect("no owner_key_id")), + seal_signer: account.owner_key_id.expect("no owner_key_id"), other_signers: vec![], detect_inputs: true, detect_inputs_use_unversioned: use_unversioned_inputs, diff --git a/integration_tests/tests/steps/wallet_daemon.rs b/integration_tests/tests/steps/wallet_daemon.rs index 48057bed69..afd42c6637 100644 --- a/integration_tests/tests/steps/wallet_daemon.rs +++ b/integration_tests/tests/steps/wallet_daemon.rs @@ -12,7 +12,7 @@ use integration_tests::{ }; use rand::{rngs::OsRng, Rng}; use tari_engine_types::commit_result::FinalizeResult; -use tari_ootle_wallet_sdk::models::{BranchAndKeyId, KeyBranch}; +use tari_ootle_wallet_sdk::models::KeyBranch; use tari_template_lib::{ constants::XTR, types::{bytes::Bytes, crypto::PedersenCommitmentBytes, Amount}, @@ -127,7 +127,7 @@ async fn when_i_run_up_fees(world: &mut TariWorld, amount: u64, wallet_daemon_na let transaction_submit_req = TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::new(KeyBranch::Account, account.owner_key_id().expect("no owner key id")), + seal_signer: account.owner_key_id().expect("no owner key id"), other_signers: vec![], detect_inputs: true, detect_inputs_use_unversioned: true, @@ -222,7 +222,9 @@ async fn when_i_burn_funds_with_wallet_daemon( .create_burn_transaction(minotari_app_grpc::tari_rpc::CreateBurnTransactionRequest { amount, fee_per_gram: 1, - payment_id: MemoField::open_from_string("Burn", TxType::Burn).to_bytes(), + payment_id: MemoField::new_open_from_string("Burn", TxType::Burn) + .unwrap() + .to_bytes(), claim_public_key: public_key.to_vec(), sidechain_deployment_key: vec![], }) diff --git a/utilities/tariswap_test_bench/src/accounts.rs b/utilities/tariswap_test_bench/src/accounts.rs index c6007af405..b3f507db1c 100644 --- a/utilities/tariswap_test_bench/src/accounts.rs +++ b/utilities/tariswap_test_bench/src/accounts.rs @@ -25,7 +25,7 @@ impl Runner { let owner_key = self .sdk .key_manager_api() - .get_public_key(KeyBranch::Account, KeyId::derived(0))?; + .get_public_key(KeyId::derived(KeyBranch::Account, 0))?; let owner_public_key = owner_key.public_key.to_byte_type(); let account_address = derive_component_address_from_public_key(&ACCOUNT_TEMPLATE_ADDRESS, &owner_public_key); @@ -45,10 +45,7 @@ impl Runner { ]) .build(); - let transaction = self - .sdk - .local_signer_api() - .sign(KeyBranch::Account, owner_key.key_id, transaction)?; + let transaction = self.sdk.signer_api().sign(owner_key.key_id, transaction)?; let finalize = self.submit_transaction_and_wait(transaction).await?; let diff = finalize.result.any_accept().unwrap(); @@ -65,8 +62,8 @@ impl Runner { self.sdk.accounts_api().add_account( None, &account, - KeyId::derived(0), - KeyId::derived(0), + KeyId::derived(KeyBranch::ViewOnlyKey, 0), + KeyId::derived(KeyBranch::Account, 0), Epoch::zero(), true, true, @@ -87,7 +84,7 @@ impl Runner { let key = self .sdk .key_manager_api() - .get_public_key(KeyBranch::Account, KeyId::derived(0))?; + .get_public_key(KeyId::derived(KeyBranch::Account, 0))?; let key_index_start = *account_key_indexes.start(); let num_accounts = *account_key_indexes.end() as usize - key_index_start as usize + 1; let owners = account_key_indexes @@ -95,7 +92,7 @@ impl Runner { let key = self .sdk .key_manager_api() - .get_public_key(KeyBranch::Account, KeyId::derived(idx))?; + .get_public_key(KeyId::derived(KeyBranch::Account, idx))?; Ok(key) }) .collect::>>()?; @@ -120,10 +117,7 @@ impl Runner { ]) .build(); - let transaction = self - .sdk - .local_signer_api() - .sign(KeyBranch::Account, key.key_id, transaction)?; + let transaction = self.sdk.signer_api().sign(key.key_id, transaction)?; let finalize = self.submit_transaction_and_wait(transaction).await?; let diff = finalize.result.any_accept().unwrap(); diff --git a/utilities/tariswap_test_bench/src/runner.rs b/utilities/tariswap_test_bench/src/runner.rs index fd4afd63b1..4aba6cceb1 100644 --- a/utilities/tariswap_test_bench/src/runner.rs +++ b/utilities/tariswap_test_bench/src/runner.rs @@ -7,7 +7,13 @@ use log::info; use tari_crypto::tari_utilities::SafePassword; use tari_engine_types::commit_result::FinalizeResult; use tari_ootle_common_types::Network; -use tari_ootle_wallet_sdk::{cipher_seed::CipherSeedRestore, models::EpochBirthday, WalletSdk as Sdk, WalletSdkConfig}; +use tari_ootle_wallet_sdk::{ + cipher_seed::CipherSeedRestore, + local_key_store::LocalKeyStore, + models::EpochBirthday, + WalletSdk as Sdk, + WalletSdkConfig, +}; use tari_ootle_wallet_sdk_services::indexer_rest_api::IndexerRestApiNetworkInterface; use tari_ootle_wallet_storage_sqlite::SqliteWalletStore; use tari_template_lib::types::TemplateAddress; @@ -17,7 +23,15 @@ use url::Url; use crate::{cli::CommonArgs, stats::Stats, templates::get_templates}; -type WalletSdk = Sdk; +pub struct TariswapTestSdkSpec; + +impl tari_ootle_wallet_sdk::WalletSdkSpec for TariswapTestSdkSpec { + type KeyStore = LocalKeyStore; + type NetworkInterface = IndexerRestApiNetworkInterface; + type Store = SqliteWalletStore; +} + +type WalletSdk = Sdk; pub struct Runner { pub(crate) sdk: WalletSdk, pub(crate) _cli: CommonArgs, @@ -119,7 +133,7 @@ fn initialize_wallet_sdk>(db_path: P, indexer_url: Url) -> Result override_keyring_password: Some(SafePassword::from_str("N3Va g0nn4 gu355").unwrap()), }; let indexer = IndexerRestApiNetworkInterface::new(indexer_url); - let mut sdk = WalletSdk::initialize(store, indexer, sdk_config, EpochBirthday::far_future())?; + let mut sdk = WalletSdk::initialize_with_local_key_store(store, indexer, sdk_config, EpochBirthday::far_future())?; sdk.initialize_cipher_seed(CipherSeedRestore::CreateNewIfRequired)?; Ok(sdk) } diff --git a/utilities/tariswap_test_bench/src/tariswap.rs b/utilities/tariswap_test_bench/src/tariswap.rs index 436fb5eafb..eb8398146f 100644 --- a/utilities/tariswap_test_bench/src/tariswap.rs +++ b/utilities/tariswap_test_bench/src/tariswap.rs @@ -6,7 +6,7 @@ use std::collections::HashMap; use log::info; use tari_engine_types::{indexed_value::decode_value_at_path, ToByteType}; use tari_ootle_common_types::{optional::Optional, SubstateRequirement}; -use tari_ootle_wallet_sdk::models::{Account, KeyBranch}; +use tari_ootle_wallet_sdk::models::Account; use tari_template_lib::{ models::{ComponentAddress, VaultId}, prelude::{ResourceAddress, ResourceType, XTR}, @@ -91,10 +91,10 @@ impl Runner { amount_b: Amount, faucet: &Faucet, ) -> anyhow::Result<()> { - let primary_account_key = self.sdk.key_manager_api().get_public_key( - KeyBranch::Account, - primary_account.owner_key_id.expect("no owner key id"), - )?; + let primary_account_key = self + .sdk + .key_manager_api() + .get_public_key(primary_account.owner_key_id.expect("no owner key id"))?; let mut tx_ids = Vec::with_capacity(200); let primary_account_pk = primary_account_key.public_key().to_byte_type(); @@ -148,8 +148,7 @@ impl Runner { .with_authorized_seal_signer() .map(|builder| { // First sign with the account key to authorize the use of the account component - self.sdk.local_signer_api().sign_with_context( - KeyBranch::Account, + self.sdk.signer_api().sign_with_context( account.owner_key_id.expect("no owner key id"), &primary_account_pk, builder, @@ -158,10 +157,7 @@ impl Runner { .build(); // Then sign with the primary account key to pay the fee - let transaction = - self.sdk - .local_signer_api() - .sign(KeyBranch::Account, primary_account_key.key_id(), transaction)?; + let transaction = self.sdk.signer_api().sign(primary_account_key.key_id(), transaction)?; assert!( transaction.verify_all_signatures(), @@ -219,10 +215,10 @@ impl Runner { amount_b_for_a: Amount, faucet: &Faucet, ) -> anyhow::Result<()> { - let primary_account_key = self.sdk.key_manager_api().get_public_key( - KeyBranch::Account, - primary_account.owner_key_id.expect("no owner key id"), - )?; + let primary_account_key = self + .sdk + .key_manager_api() + .get_public_key(primary_account.owner_key_id.expect("no owner key id"))?; let primary_account_pk = primary_account_key.public_key.to_byte_type(); let mut tx_ids = vec![]; @@ -276,18 +272,16 @@ impl Runner { .call_method(account.component_address, "deposit", args![Workspace("swapped")]) .with_authorized_seal_signer(); - let transaction = self.sdk.local_signer_api().sign_with_context( - KeyBranch::Account, + let transaction = self.sdk.signer_api().sign_with_context( account.owner_key_id.expect("no owner key id"), &primary_account_pk, transaction, )?; - let transaction = self.sdk.local_signer_api().sign( - KeyBranch::Account, - primary_account_key.key_id(), - transaction.build(), - )?; + let transaction = self + .sdk + .signer_api() + .sign(primary_account_key.key_id(), transaction.build())?; tx_ids.push(self.submit_transaction(transaction).await?); } @@ -353,11 +347,10 @@ impl Runner { .with_authorized_seal_signer() .build(); - let transaction = self.sdk.local_signer_api().sign( - KeyBranch::Account, - account.owner_key_id.expect("no owner key id"), - transaction, - )?; + let transaction = self + .sdk + .signer_api() + .sign(account.owner_key_id().expect("no owner key id"), transaction)?; tx_ids.push(self.submit_transaction(transaction).await?); } diff --git a/utilities/traffic-sim/src/sim.rs b/utilities/traffic-sim/src/sim.rs index 614cf53c5f..e3854825e8 100644 --- a/utilities/traffic-sim/src/sim.rs +++ b/utilities/traffic-sim/src/sim.rs @@ -20,7 +20,7 @@ use tari_ootle_common_types::{ use tari_ootle_wallet_sdk::{ apis::{confidential_transfer::UtxoInputSelection, stealth_transfer::TransferOutput}, crypto::memo::Memo, - models::{AccountWithAddress, BranchAndKeyId, KeyBranch}, + models::{AccountWithAddress, KeyBranch}, }; use tari_template_lib::{ constants::XTR, @@ -315,12 +315,10 @@ impl TrafficSim { .client .submit_transaction(TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account( - account - .account - .owner_key_id - .ok_or_else(|| anyhow::anyhow!("Exchange account has no owner key ID"))?, - ), + seal_signer: account + .account + .owner_key_id + .ok_or_else(|| anyhow::anyhow!("Exchange account has no owner key ID"))?, other_signers: vec![], detect_inputs: true, detect_inputs_use_unversioned: true, @@ -487,7 +485,7 @@ impl TrafficSim { .client .submit_transaction(TransactionSubmitRequest { transaction, - seal_signer: BranchAndKeyId::for_account(exchange_account_key_id), + seal_signer: exchange_account_key_id, other_signers: transfer_resp.signing_keys, detect_inputs: true, detect_inputs_use_unversioned: true,