Skip to content

fix(wallet)!: adds wallet signer API - #1601

Merged
sdbondi merged 1 commit into
tari-project:developmentfrom
sdbondi:wallet-key-manager-backend
Oct 15, 2025
Merged

fix(wallet)!: adds wallet signer API#1601
sdbondi merged 1 commit into
tari-project:developmentfrom
sdbondi:wallet-key-manager-backend

Conversation

@sdbondi

@sdbondi sdbondi commented Oct 14, 2025

Copy link
Copy Markdown
Member

Description

Adds a local signer API to the wallet SDK
Removed the usage of several key manager calls that return secrets
Removed a couple of key manager calls that return secrets.
fix!: bind the schema version to unsigned transaction signatures

Motivation and Context

General-purpose API that signs items that implement the Signable trait.

This trait is implemented for unsigned transaction components, allowing the API to sign as follows:

let unsealed_transaction = Transaction::builder()
  //... build tx
    .build();

  let transaction = self.sdk.local_signer_api().sign(
    KeyBranch::Account,
    account.owner_key_id,
     unsealed_transaction,
  )?;

The local signer API utilises the locally stored and encrypted Cipher key; however, the underlying signer is backend-agnostic, meaning that a cold wallet backend can be implemented. The backend trait is defined as follows:

pub trait KeyManagerBackend<M> {
    type Error;

    fn try_sign(&mut self, branch: &str, key_id: KeyId, message: M) -> Result<SignatureOutput, Self::Error>;
}

How Has This Been Tested?

Manually and existing tests

What process can a PR reviewer use to test or verify this change?

Breaking Changes

  • None
  • Requires data directory to be deleted
  • Other - Please specify

BREAKING CHANGE: transactions signatures bind to the schema version (v1) - previous transaction signatures will be invalid after merge

Summary by CodeRabbit

  • New Features

    • Introduced a local signer API for secure, context-aware transaction signing.
    • Added generic “signable” interfaces enabling unified signing across transactions.
    • New key types and APIs: public/secret wallet keys, public-key retrieval, and ElGamal view key access.
    • Stealth outputs: added encrypt/decrypt helpers and spend-branch selection.
  • Refactor

    • Unified build-then-sign flow across transfers, NFTs, stealth, and validator operations.
    • KeyBranch and key models consolidated under a single public models namespace.
    • Transaction schema version standardized to u16.
  • Bug Fixes

    • Improved error reporting for indexer 400 responses with detailed messages.

@coderabbitai

coderabbitai Bot commented Oct 14, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This PR refactors key management and signing across the wallet stack: moves KeyBranch into models, replaces build_and_seal with unsigned build + local signer flow, introduces Signable/IntoSigned traits and a Signer API, adds a local key manager/backend, transitions SDK APIs to WalletPublicKey/WalletSecretKey, and versions signature messages.

Changes

Cohort / File(s) Summary
KeyBranch import relocation
applications/tari_swarm_daemon/src/process_manager/processes/wallet_daemon.rs, applications/tari_wallet_cli/src/command/key.rs, applications/tari_walletd/src/main.rs, applications/tari_walletd/src/handlers/transaction.rs, clients/wallet_daemon_client/src/lib.rs, clients/wallet_daemon_client/src/types.rs, integration_tests/tests/steps/wallet*.rs
Update imports to tari_ootle_wallet_sdk::models::KeyBranch. No logic changes.
Walletd handlers: switch to local signer flow
applications/tari_walletd/src/handlers/accounts.rs, .../confidential.rs, .../keys.rs, .../nfts.rs, .../stealth_utxos.rs, .../validator.rs, .../transaction.rs
Replace build_and_seal with build + local_signer_api().sign[_with_context] using KeyBranch and KeyId. Use Nonce/Account branches as appropriate. Update ElGamal view key retrieval to get_elgamal_encrypted_view_key. Shift to public-key-based paths.
Common types: signable traits
crates/common_types/src/lib.rs, crates/common_types/src/signable.rs
Add Signable and IntoSigned traits for generic signing and conversion to signed outputs; re-export module.
Transaction crate: signable integration and schema versioning
crates/transaction/src/builder/mod.rs, .../transaction.rs, .../unsigned_transaction.rs, .../v1/signature.rs, .../v1/transaction.rs, .../v1/unsealed.rs, .../v1/unsigned.rs
Implement Signable/IntoSigned for builders/transactions; change schema_version type to u16; expose versioned signature message creation and verify_v1; narrow set_dry_run visibility.
SDK key models and API overhaul
crates/wallet/sdk/src/models/key.rs, crates/wallet/sdk/src/apis/key_manager.rs, crates/wallet/sdk/src/apis/confidential_outputs.rs, crates/wallet/sdk/src/apis/confidential_transfer.rs
Introduce public KeyBranch enum in models; add WalletPublicKey/WalletSecretKey; shift KeyManager API to return typed keys, add public-key getters, ElGamal view key getter; adjust confidential APIs to new key types and imports.
Signer API and local key backend
crates/wallet/sdk/src/apis/mod.rs, .../apis/signer.rs, .../key_managers/mod.rs, .../key_managers/backend.rs, .../key_managers/local.rs, crates/wallet/sdk/src/lib.rs, .../local_key_store.rs, crates/wallet/sdk/src/sdk.rs
Add generic SignerApi, backend traits (KeyManagerBackend, WalletKeyStore) and local implementations (LocalKeyManager, LocalKeyStore); expose local_signer_api() from SDK.
SDK services updates
crates/wallet/sdk_services/src/account_recovery/service.rs, .../indexer_rest_api.rs, .../utxo_scanner/scanner_round.rs
Export KeyBranch via models; extend error mapping for indexer REST errors; update UTXO scanner view key type to WalletSecretKey.
Engine/storage minor tweaks
crates/engine/src/runtime/working_state.rs, crates/storage/src/consensus_models/leader_fee.rs
Minor refactor to avoid recomputation; comment updates only.
Utilities/test bench refactor to new signing
utilities/tariswap_test_bench/src/accounts.rs, .../tariswap.rs
Migrate to public-key retrieval (get_public_key), build + local signer signing, context-based authorization, and updated key-id usage.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Walletd as Walletd Handler
  participant SDK as Wallet SDK
  participant Signer as SignerApi(Local)
  participant KM as KeyManagerBackend
  participant Tx as Transaction (Unsigned/Signed)

  Client->>Walletd: Request (e.g., transfer)
  Walletd->>SDK: Build unsigned transaction
  SDK-->>Walletd: Unsigned Tx
  Walletd->>Signer: sign(KeyBranch::{Account|Nonce}, KeyId, Unsigned Tx)
  activate Signer
  Signer->>KM: try_sign(branch.as_str(), key_id, item.as_signing_message(ctx))
  KM-->>Signer: {public_key, signature}
  Signer-->>Walletd: item.into_signed(public_key, signature)
  deactivate Signer
  Walletd->>SDK: Submit signed transaction
  SDK-->>Client: Result
Loading
sequenceDiagram
  autonumber
  participant TxB as TransactionBuilder
  participant Traits as Signable/IntoSigned
  participant Signer as SignerApi
  participant KM as KeyManagerBackend

  TxB->>TxB: build() -> Unsigned
  Signer->>TxB: get signing message via Signable
  Signer->>KM: try_sign(..., message[64])
  KM-->>Signer: signature + pubkey
  Signer->>TxB: IntoSigned -> append TransactionSignature
  TxB-->>Signer: Signed Transaction
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

CR-too_long, P-acks_required, P-reviews_required

Poem

A whisk of keys, a hop through trees,
I sign with paws and gentle ease.
No more seals—just messages sung,
With branches, ids, and hashes strung.
A carrot-inked autograph, quite fine—
Behold! The ledger’s rabbit sign. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.47% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely conveys that the pull request introduces a wallet signer API, which is the main change implemented in this branch. It follows a conventional commit style to indicate a breaking change and the scope, and it focuses on the core feature without extraneous details.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
crates/storage/src/consensus_models/leader_fee.rs (1)

49-56: Overflow risk in branch condition can break fee conservation; compare using division instead of mul

The check (leader_fee + 1) * num_involved_shards.get() <= transaction_fee can overflow u64, leading to a wrong branch decision and invalid burn/payout totals. Replace with a division-based comparison that avoids overflow.

Apply:

 pub fn calculate_leader_fee(transaction_fee: u64, num_involved_shards: NonZeroU64, exhaust_divisor: u64) -> LeaderFee {
     let target_burn = transaction_fee.checked_div(exhaust_divisor).unwrap_or(0);
     let block_fee_after_burn = transaction_fee - target_burn;

-    let mut leader_fee = block_fee_after_burn / num_involved_shards;
-    // The extra amount that is burnt from dividing the number of shards involved
-    let excess_remainder_burn = block_fee_after_burn % num_involved_shards;
+    let shards = num_involved_shards.get();
+    let mut leader_fee = block_fee_after_burn / shards;
+    // The extra amount that is burnt from dividing the number of shards involved
+    let excess_remainder_burn = block_fee_after_burn % shards;

     // Adjust the leader fee to account for the remainder
     // If the remainder accounts for an extra burn of greater than half the number of involved shards, we
     // give each validator an extra 1 in fees if enough fees are available, burning less than the exhaust target.
     // Otherwise, we burn a little more than/equal to the exhaust target.
-    let actual_burn = if excess_remainder_burn > 0 &&
-        // If the div floor burn accounts for 1 less fee for more than half of number of shards, and ...
-        excess_remainder_burn >= num_involved_shards.get() / 2 &&
-        // ... if there are enough fees to pay out an additional 1 to all shards
-        (leader_fee + 1) * num_involved_shards.get() <= transaction_fee
+    let actual_burn = if excess_remainder_burn > 0 &&
+        // If the div floor burn accounts for 1 less fee for more than half of number of shards, and ...
+        excess_remainder_burn >= shards / 2 &&
+        // ... if there are enough fees to pay out an additional 1 to all shards (overflow-safe)
+        leader_fee < transaction_fee / shards
     {
         // Pay each leader 1 more
         leader_fee += 1;

-        // We burn a little less (< num_involved_shards) due to the remainder
-        target_burn.saturating_sub(num_involved_shards.get() - excess_remainder_burn)
+        // We burn a little less (< num_involved_shards) due to the remainder
+        target_burn.saturating_sub(shards - excess_remainder_burn)
     } else {
-        // We burn a little more (< num_involved_shards) due to the remainder
-        target_burn + excess_remainder_burn
+        // We burn a little more (< num_involved_shards) due to the remainder
+        target_burn + excess_remainder_burn
     };

This preserves behavior while eliminating overflow. Optionally, add debug_assert!(target_burn >= shards - excess_remainder_burn); in the true branch to document the invariant.

Also applies to: 58-63

utilities/tariswap_test_bench/src/tariswap.rs (1)

32-58: Migrate from derive_account_key/build_and_seal to local_signer_api

This still uses derive_account_key + build_and_seal, which undermines the PR goal to remove secret-key handling and standardize signing. Please switch to the local signer API with KeyBranch::Account and the in_account’s owner_key_id.

Example refactor:

-        let key = self.sdk.key_manager_api().derive_account_key(0)?;
+        // Use the paying account's owner key id for signing fees
+        let fee_key_id = in_account.owner_key_id.expect("no owner key id");

 ...
-            .build_and_seal(&key.key);
+            .build();
+
+        let transaction = self
+            .sdk
+            .local_signer_api()
+            .sign(KeyBranch::Account, fee_key_id, transaction)?;
utilities/tariswap_test_bench/src/accounts.rs (1)

156-188: Migrate fund_accounts to local_signer_api; remove secret usage

This still uses derive_account_key + build_and_seal. Please switch to the local signer and the fee_account’s owner_key_id to align with the new security posture.

-        let key = self.sdk.key_manager_api().derive_account_key(0)?;
+        let fee_key_id = fee_account
+            .owner_key_id
+            .expect("fee_account has no owner_key_id");

 ...
-                .build_and_seal(&key.key);
+                .build();
+
+            let transaction = self
+                .sdk
+                .local_signer_api()
+                .sign(KeyBranch::Account, fee_key_id, transaction)?;
applications/tari_walletd/src/handlers/keys.rs (1)

63-68: Branch parameter ignored in set_active/get_active.

set_active_key/get_active_key are hardcoded to KeyBranch::Account. If KeysSetActiveRequest carries a branch, use it to avoid surprising behavior.

Suggested change:

-    km.set_active_key(KeyBranch::Account, req.index)?;
-    let key = km.get_active_key(KeyBranch::Account)?;
+    km.set_active_key(req.branch, req.index)?;
+    let key = km.get_active_key(req.branch)?;
🧹 Nitpick comments (15)
utilities/tariswap_test_bench/src/tariswap.rs (2)

94-100: Unify key accessors for forward-compatibility

This uses public_key() while other places (Line 226 and in accounts.rs) use the public field. Pick one style project‑wide; prefer methods to avoid relying on public fields.


222-227: Consistency: use the same accessor style

Use the same accessor style as earlier for the public key.

-        let primary_account_pk = primary_account_key.public_key.to_byte_type();
+        let primary_account_pk = primary_account_key.public_key().to_byte_type();
utilities/tariswap_test_bench/src/accounts.rs (1)

25-30: Optional: prefer getter methods over public fields

For consistency with tariswap.rs, consider using methods (e.g., public_key(), key_id()) to avoid relying on public fields.

Also applies to: 89-93, 107-109

applications/tari_walletd/src/handlers/transaction.rs (1)

330-358: Consider adding a clarifying comment for the multi-step signing flow.

The signing logic here handles multiple scenarios with conditional signing, signature extraction, and a final signing step. While the implementation appears correct, a brief comment explaining the signing flow would improve maintainability:

  1. Lines 332-341: Sign with non-owner key if different from account owner
  2. Lines 342-343: Extract signatures and build unsigned transaction
  3. Lines 350-353: Build with collected signatures
  4. Lines 355-357: Add final signature with account owner key

Example comment:

+        // Multi-signature flow:
+        // 1. Sign with non-owner key if specified (via sign_with_context)
+        // 2. Build unsigned transaction and collect signatures
+        // 3. Rebuild with signatures and authorize the sealed signer
+        // 4. Add final signature with account owner key
         let transaction = context
             .transaction_builder()
crates/wallet/sdk_services/src/utxo_scanner/scanner_round.rs (2)

38-39: Naming/readability: variable suggests pubkey, but holds a secret.

view_key is now a WalletSecretKey. Consider renaming to view_secret_key (and param) to avoid confusion and accidental misuse.

Also applies to: 60-61


266-271: Avoid direct field access of secret; use an accessor.

Accessing WalletSecretKey.secret directly ties callers to struct layout and weakens encapsulation. Prefer a method (e.g., secret() or as_secret()) and keep the field private.

crates/common_types/src/signable.rs (2)

6-10: Trait shape looks good; add minimal docs for contract clarity.

Brief doc comments explaining message domain separation expectations and typical Ctx usage will help prevent ambiguous implementations.


12-16: IntoSigned API is straightforward.

No issues spotted. Consider a short doc note that self should reflect the final pre-sign state to avoid post-sign mutation hazards.

crates/wallet/sdk/src/key_managers/backend.rs (1)

13-17: Use typed KeyBranch and constrain message type to avoid stringly-typed bugs

Prefer a strongly-typed branch and explicit message bound. This reduces runtime mistakes and clarifies expectations for backends.

-use crate::models::KeyId;
+use crate::models::{KeyBranch, KeyId};

-pub trait KeyManagerBackend<M> {
+pub trait KeyManagerBackend<M: AsRef<[u8]>> {
     type Error;

-    fn try_sign(&mut self, branch: &str, key_id: KeyId, message: M) -> Result<SignatureOutput, Self::Error>;
+    fn try_sign(
+        &mut self,
+        branch: KeyBranch,
+        key_id: KeyId,
+        message: M,
+    ) -> Result<SignatureOutput, Self::Error>;
 }
crates/transaction/src/v1/signature.rs (3)

91-105: Remove magic literal; define a V1 schema constant

Avoid hardcoding 1. Define a module const and use it in both sign and verify to reduce drift.

+const V1_SCHEMA_VERSION: u16 = 1;
@@
-        let message = Self::create_message(1, seal_signer, transaction);
+        let message = Self::create_message(V1_SCHEMA_VERSION, seal_signer, transaction);

107-116: Mirror the constant in verification

Keep sign/verify consistent by using the same constant.

-    pub fn verify_v1(&self, seal_signer: &RistrettoPublicKeyBytes, transaction: &UnsignedTransactionV1) -> bool {
-        let message = Self::create_message(1, seal_signer, transaction);
+    pub fn verify_v1(&self, seal_signer: &RistrettoPublicKeyBytes, transaction: &UnsignedTransactionV1) -> bool {
+        let message = Self::create_message(V1_SCHEMA_VERSION, seal_signer, transaction);

126-137: Optional: assert schema-version cohesion in debug builds

Add a debug assertion to catch mismatched schema versions when future-proofing.

 pub fn create_message(
     schema_version: u16,
     seal_signer: &RistrettoPublicKeyBytes,
     transaction: &UnsignedTransactionV1,
 ) -> [u8; 64] {
+    debug_assert_eq!(schema_version, V1_SCHEMA_VERSION, "Unexpected schema_version for v1");
     let signature_fields = TransactionSignatureFields::from(transaction);
     engine_hasher64(EngineHashDomainLabel::TransactionSignature)
         .chain(&schema_version)
         .chain(seal_signer)
         .chain(&signature_fields)
         .result()
 }
crates/wallet/sdk/src/local_key_store.rs (1)

29-47: Secret handling looks correct; add a brief doc comment warning against logging

get_imported_secret returns sensitive material. Add a short doc comment reminding consumers not to log or persist it, and to keep scope minimal. RistrettoSecretKey typically zeroizes on drop, but caller hygiene still matters.

crates/wallet/sdk/src/apis/signer.rs (1)

21-35: Align with a typed branch in backend; avoid passing &str

If KeyManagerBackend takes KeyBranch (recommended), drop as_str() and pass the enum directly.

-        let message = item.as_signing_message(context);
-        let signature = self.backend.try_sign(branch.as_str(), key_id, message)?;
+        let message = item.as_signing_message(context);
+        let signature = self.backend.try_sign(branch, key_id, message)?;
crates/wallet/sdk/src/key_managers/local.rs (1)

34-37: Clarify the warning comment.

The warning about not using next_key is helpful, but could be more explicit about why this always returns the same key (because the key manager is initialized with index 0 and never incremented).

Consider rewording for clarity:

-    /// WARNING: dont use next_key on the key manager because this will always return the same key
+    /// WARNING: Don't use next_key on this key manager. Since it's initialized with index 0 and never
+    /// incremented, next_key would always return the same key. Use derive_key with explicit indices instead.
     fn get_key_manager(&mut self, branch: &str) -> WalletKeyManager {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between edd96aa and 402bde1.

📒 Files selected for processing (44)
  • applications/tari_swarm_daemon/src/process_manager/processes/wallet_daemon.rs (1 hunks)
  • applications/tari_wallet_cli/src/command/key.rs (1 hunks)
  • applications/tari_walletd/src/handlers/accounts.rs (6 hunks)
  • applications/tari_walletd/src/handlers/confidential.rs (2 hunks)
  • applications/tari_walletd/src/handlers/keys.rs (2 hunks)
  • applications/tari_walletd/src/handlers/nfts.rs (3 hunks)
  • applications/tari_walletd/src/handlers/stealth_utxos.rs (1 hunks)
  • applications/tari_walletd/src/handlers/transaction.rs (5 hunks)
  • applications/tari_walletd/src/handlers/validator.rs (4 hunks)
  • applications/tari_walletd/src/main.rs (1 hunks)
  • clients/wallet_daemon_client/src/lib.rs (1 hunks)
  • clients/wallet_daemon_client/src/types.rs (1 hunks)
  • crates/common_types/src/lib.rs (2 hunks)
  • crates/common_types/src/signable.rs (1 hunks)
  • crates/engine/src/runtime/working_state.rs (1 hunks)
  • crates/storage/src/consensus_models/leader_fee.rs (1 hunks)
  • crates/transaction/src/builder/mod.rs (3 hunks)
  • crates/transaction/src/transaction.rs (1 hunks)
  • crates/transaction/src/unsigned_transaction.rs (3 hunks)
  • crates/transaction/src/v1/signature.rs (3 hunks)
  • crates/transaction/src/v1/transaction.rs (1 hunks)
  • crates/transaction/src/v1/unsealed.rs (4 hunks)
  • crates/transaction/src/v1/unsigned.rs (2 hunks)
  • crates/wallet/sdk/src/apis/confidential_outputs.rs (2 hunks)
  • crates/wallet/sdk/src/apis/confidential_transfer.rs (1 hunks)
  • crates/wallet/sdk/src/apis/key_manager.rs (5 hunks)
  • crates/wallet/sdk/src/apis/mod.rs (1 hunks)
  • crates/wallet/sdk/src/apis/signer.rs (1 hunks)
  • crates/wallet/sdk/src/apis/stealth_outputs.rs (7 hunks)
  • crates/wallet/sdk/src/apis/stealth_transfer.rs (3 hunks)
  • crates/wallet/sdk/src/key_managers/backend.rs (1 hunks)
  • crates/wallet/sdk/src/key_managers/local.rs (1 hunks)
  • crates/wallet/sdk/src/key_managers/mod.rs (1 hunks)
  • crates/wallet/sdk/src/lib.rs (1 hunks)
  • crates/wallet/sdk/src/local_key_store.rs (1 hunks)
  • crates/wallet/sdk/src/models/key.rs (7 hunks)
  • crates/wallet/sdk/src/sdk.rs (3 hunks)
  • crates/wallet/sdk_services/src/account_recovery/service.rs (1 hunks)
  • crates/wallet/sdk_services/src/indexer_rest_api.rs (2 hunks)
  • crates/wallet/sdk_services/src/utxo_scanner/scanner_round.rs (3 hunks)
  • integration_tests/tests/steps/wallet.rs (1 hunks)
  • integration_tests/tests/steps/wallet_daemon.rs (1 hunks)
  • utilities/tariswap_test_bench/src/accounts.rs (5 hunks)
  • utilities/tariswap_test_bench/src/tariswap.rs (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (37)
crates/transaction/src/transaction.rs (3)
crates/transaction/src/unsigned_transaction.rs (1)
  • schema_version (21-25)
crates/transaction/src/v1/transaction.rs (1)
  • schema_version (44-46)
crates/transaction/src/v1/unsealed.rs (1)
  • schema_version (42-44)
crates/wallet/sdk/src/key_managers/backend.rs (3)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
crates/wallet/sdk/src/key_managers/local.rs (1)
  • try_sign (47-65)
crates/wallet/sdk/src/local_key_store.rs (1)
  • get_imported_secret (32-46)
crates/wallet/sdk/src/apis/confidential_transfer.rs (2)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/OutputStatus.ts (1)
  • OutputStatus (3-3)
crates/transaction/src/v1/unsigned.rs (4)
crates/common_types/src/signable.rs (1)
  • as_signing_message (9-9)
crates/transaction/src/builder/mod.rs (1)
  • as_signing_message (488-490)
crates/transaction/src/unsigned_transaction.rs (1)
  • as_signing_message (161-165)
crates/transaction/src/v1/signature.rs (2)
  • create_message (71-76)
  • create_message (126-137)
applications/tari_walletd/src/handlers/nfts.rs (2)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/Account.ts (1)
  • Account (6-14)
utilities/tariswap_test_bench/src/accounts.rs (6)
bindings/src/types/Account.ts (1)
  • Account (6-14)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
crates/wallet/sdk/src/models/key.rs (1)
  • derived (298-300)
crates/wallet/sdk/src/models/account.rs (2)
  • owner_public_key (37-39)
  • owner_public_key (95-97)
utilities/transaction_generator/src/transaction_builders/free_coins.rs (1)
  • builder (12-36)
applications/tari_wallet_cli/src/command/key.rs (2)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
crates/wallet/sdk/src/apis/signer.rs (2)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
crates/wallet/sdk_services/src/indexer_rest_api.rs (1)
networking/rpc_framework/src/status.rs (1)
  • details (114-116)
crates/transaction/src/unsigned_transaction.rs (7)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
crates/transaction/src/transaction.rs (2)
  • schema_version (245-249)
  • network (81-85)
crates/transaction/src/v1/transaction.rs (2)
  • schema_version (44-46)
  • network (52-54)
crates/transaction/src/v1/unsealed.rs (2)
  • schema_version (42-44)
  • as_signing_message (130-135)
crates/transaction/src/v1/unsigned.rs (3)
  • set_network (58-61)
  • set_dry_run (63-66)
  • as_signing_message (151-153)
crates/common_types/src/signable.rs (1)
  • as_signing_message (9-9)
crates/transaction/src/builder/mod.rs (1)
  • as_signing_message (488-490)
applications/tari_walletd/src/main.rs (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/local_key_store.rs (2)
crates/wallet/crypto/src/encryption.rs (1)
  • decrypt_with_password (30-98)
crates/wallet/sdk/src/key_managers/backend.rs (1)
  • get_imported_secret (22-22)
applications/tari_walletd/src/handlers/keys.rs (4)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
crates/wallet/sdk/src/models/key.rs (1)
  • derived (298-300)
bindings/src/types/wallet-daemon-client/KeysCreateResponse.ts (1)
  • KeysCreateResponse (4-4)
crates/transaction/src/builder/mod.rs (5)
crates/common_types/src/signable.rs (2)
  • as_signing_message (9-9)
  • into_signed (15-15)
crates/transaction/src/unsigned_transaction.rs (1)
  • as_signing_message (161-165)
crates/transaction/src/v1/unsealed.rs (2)
  • as_signing_message (130-135)
  • into_signed (141-146)
crates/transaction/src/v1/unsigned.rs (1)
  • as_signing_message (151-153)
crates/transaction/src/v1/signature.rs (6)
  • public_key (63-65)
  • public_key (122-124)
  • signature (59-61)
  • signature (118-120)
  • new (32-34)
  • new (87-89)
crates/common_types/src/signable.rs (5)
crates/transaction/src/builder/mod.rs (2)
  • as_signing_message (488-490)
  • into_signed (496-501)
crates/transaction/src/unsigned_transaction.rs (1)
  • as_signing_message (161-165)
crates/transaction/src/v1/unsealed.rs (2)
  • as_signing_message (130-135)
  • into_signed (141-146)
crates/transaction/src/v1/unsigned.rs (1)
  • as_signing_message (151-153)
crates/transaction/src/v1/signature.rs (4)
  • public_key (63-65)
  • public_key (122-124)
  • signature (59-61)
  • signature (118-120)
clients/wallet_daemon_client/src/types.rs (2)
bindings/src/types/ConfidentialTransferInputSelection.ts (1)
  • ConfidentialTransferInputSelection (3-7)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/transaction/src/v1/signature.rs (5)
bindings/src/types/UnsignedTransactionV1.ts (1)
  • UnsignedTransactionV1 (6-18)
crates/transaction/src/transaction.rs (1)
  • schema_version (245-249)
crates/transaction/src/unsigned_transaction.rs (1)
  • schema_version (21-25)
crates/transaction/src/v1/unsealed.rs (1)
  • schema_version (42-44)
crates/engine_types/src/hashing.rs (1)
  • engine_hasher64 (35-37)
crates/wallet/sdk_services/src/utxo_scanner/scanner_round.rs (5)
bindings/src/types/AccountWithAddress.ts (1)
  • AccountWithAddress (5-5)
bindings/src/types/UtxoSpent.ts (1)
  • UtxoSpent (4-4)
bindings/src/types/UtxoUnspent.ts (1)
  • UtxoUnspent (5-5)
bindings/src/types/WalletUtxoUpdate.ts (1)
  • WalletUtxoUpdate (6-6)
crates/engine_types/src/resource.rs (1)
  • view_key (126-128)
crates/transaction/src/v1/transaction.rs (3)
crates/transaction/src/transaction.rs (1)
  • schema_version (245-249)
crates/transaction/src/unsigned_transaction.rs (1)
  • schema_version (21-25)
crates/transaction/src/v1/unsealed.rs (1)
  • schema_version (42-44)
crates/wallet/sdk/src/key_managers/local.rs (5)
crates/wallet/sdk/src/cipher_seed.rs (1)
  • cipher_seed (29-34)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
crates/wallet/sdk/src/apis/key_manager.rs (1)
  • get_key_manager (332-341)
crates/wallet/sdk/src/models/key.rs (12)
  • from (119-124)
  • from (144-149)
  • from (173-178)
  • from (182-187)
  • from (191-196)
  • from (200-205)
  • from (277-279)
  • from (283-285)
  • key_id (65-67)
  • key_id (138-140)
  • key_id (163-165)
  • secret (159-161)
crates/wallet/sdk/src/key_managers/backend.rs (1)
  • try_sign (16-16)
applications/tari_walletd/src/handlers/confidential.rs (2)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/engine_types/src/resource.rs (1)
  • view_key (126-128)
integration_tests/tests/steps/wallet_daemon.rs (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/sdk.rs (2)
crates/wallet/sdk/src/cipher_seed.rs (1)
  • cipher_seed (29-34)
crates/wallet/sdk/src/apis/key_manager.rs (1)
  • new (50-62)
applications/tari_walletd/src/handlers/transaction.rs (4)
crates/transaction/src/transaction.rs (3)
  • builder (47-49)
  • signatures (99-103)
  • inputs (123-127)
crates/transaction/src/v1/unsigned.rs (2)
  • builder (33-35)
  • inputs (76-78)
crates/transaction/src/builder/mod.rs (1)
  • signatures (406-408)
crates/transaction/src/v1/unsealed.rs (2)
  • signatures (77-79)
  • inputs (96-98)
crates/transaction/src/v1/unsealed.rs (6)
crates/engine_types/src/hashing.rs (1)
  • engine_hasher64 (35-37)
crates/transaction/src/transaction.rs (2)
  • schema_version (245-249)
  • new (51-53)
crates/transaction/src/unsigned_transaction.rs (2)
  • schema_version (21-25)
  • as_signing_message (161-165)
crates/common_types/src/signable.rs (2)
  • as_signing_message (9-9)
  • into_signed (15-15)
crates/transaction/src/builder/mod.rs (3)
  • as_signing_message (488-490)
  • into_signed (496-501)
  • new (53-59)
crates/transaction/src/v1/unsigned.rs (2)
  • as_signing_message (151-153)
  • new (37-56)
crates/wallet/sdk/src/apis/key_manager.rs (4)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
crates/wallet/sdk/src/models/key.rs (3)
  • key_id (65-67)
  • key_id (138-140)
  • key_id (163-165)
bindings/src/types/Account.ts (1)
  • Account (6-14)
crates/wallet/sdk/src/apis/stealth_transfer.rs (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
clients/wallet_daemon_client/src/lib.rs (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/apis/stealth_outputs.rs (3)
bindings/src/types/EncryptedData.ts (1)
  • EncryptedData (7-7)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/apis/stealth_crypto.rs (2)
  • decrypt_value_and_mask (130-146)
  • encrypt_value_and_mask (103-114)
crates/wallet/sdk/src/models/key.rs (3)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
applications/tari_swarm_daemon/src/process_manager/processes/wallet_daemon.rs (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/engine/src/runtime/working_state.rs (2)
crates/engine_types/src/fees.rs (1)
  • total_fees_paid (46-48)
bindings/src/types/TransactionReceipt.ts (1)
  • TransactionReceipt (7-12)
applications/tari_walletd/src/handlers/validator.rs (5)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
bindings/src/types/Account.ts (1)
  • Account (6-14)
crates/wallet/sdk/src/models/key.rs (4)
  • key_id (65-67)
  • key_id (138-140)
  • key_id (163-165)
  • derived (298-300)
crates/common_types/src/fee_pool.rs (1)
  • derive_fee_pool_address (9-20)
utilities/tariswap_test_bench/src/tariswap.rs (2)
bindings/src/types/Account.ts (1)
  • Account (6-14)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
integration_tests/tests/steps/wallet.rs (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk_services/src/account_recovery/service.rs (2)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
applications/tari_walletd/src/handlers/accounts.rs (3)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
crates/wallet/sdk/src/models/key.rs (4)
  • key_id (65-67)
  • key_id (138-140)
  • key_id (163-165)
  • derived (298-300)
crates/wallet/sdk/src/models/account.rs (2)
  • owner_key_id (33-35)
  • owner_key_id (91-93)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: file licenses
  • GitHub Check: check stable
  • GitHub Check: fmt
  • GitHub Check: clippy
  • GitHub Check: check nightly
  • GitHub Check: test
  • GitHub Check: machete
🔇 Additional comments (61)
crates/engine/src/runtime/working_state.rs (1)

1051-1062: LGTM! Clean refactor that improves readability.

Extracting the total_fees_paid computation into a local variable eliminates potential duplicate computation and makes the code clearer.

crates/wallet/sdk_services/src/indexer_rest_api.rs (2)

29-35: LGTM! Import addition supports new error handling.

The Displayable import is correctly added to support formatting error details in the new ErrorResponse handling branch below.


312-322: LGTM! Error handling correctly maps ErrorResponse to appropriate statuses.

The logic appropriately distinguishes HTTP 400 errors (invalid requests → TransactionRejected) from other errors (→ InternalError). The use of details.display() from the newly imported Displayable trait provides formatted error details for user-facing messages. The cast of INVALID_REQUEST_CODE to u16 is safe and necessary for comparison with source.status().as_u16().

utilities/tariswap_test_bench/src/tariswap.rs (4)

9-9: LGTM: import path update

Using KeyBranch from models aligns with the new SDK structure.


149-158: Confirm sign_with_context’s context value

You pass the primary account public key as context while authorizing the per‑account component. Please confirm this is the intended coupling (fee payer as context). If the context should be the account’s owner key instead, adjust accordingly.


160-165: LGTM: final fee-payer signature

Second signature with primary account key to cover fees looks correct.


277-290: LGTM: two-step signer flow

Authorized seal + contextual sign + fee-payer sign matches the new API.

utilities/tariswap_test_bench/src/accounts.rs (4)

25-31: LGTM: switched to public key retrieval

Using get_public_key + local signer aligns with the new API.


48-51: LGTM: adopting local_signer_api for account creation

Signs with KeyBranch::Account and the owner key id; looks correct.


102-116: LGTM: folded builder for multiple accounts

The fold over owners to create accounts and fee prepayment is clean and efficient.


140-143: LGTM: account registration with owner key_id

Persisting owner.key_id for both owner and view-only ids matches current usage.

crates/wallet/sdk/src/apis/confidential_outputs.rs (2)

18-18: LGTM: Import updated to reflect new key types.

The import change from Key to WalletSecretKey aligns with the broader refactor moving key representations to WalletSecretKey and WalletPublicKey types throughout the wallet SDK.


268-268: LGTM: Parameter type updated consistently.

The parameter type change to WalletSecretKey is consistent with the import changes and the usage at lines 292 and 315 where key.secret and key.key_id are accessed.

applications/tari_walletd/src/main.rs (1)

32-32: LGTM: Import path updated to reflect public API reorganization.

The import path change moves KeyBranch from apis::key_manager to the public models module, aligning with the broader refactor to expose key-related types via the models module.

crates/wallet/sdk/src/apis/mod.rs (1)

13-13: LGTM: New signer module added to public API.

This addition expands the public API surface to expose the new signing functionality introduced in this PR, consistent with the PR objectives of adding a local signer API to the wallet SDK.

applications/tari_swarm_daemon/src/process_manager/processes/wallet_daemon.rs (1)

5-5: LGTM: Import path updated consistently.

The import path change moves KeyBranch to the public models module, consistent with the broader refactor across the codebase.

applications/tari_walletd/src/handlers/stealth_utxos.rs (1)

82-82: LGTM: Simplified key retrieval using specialized getter.

The change from derive_key(KeyBranch::ElgamalEncryptionViewKey, id) to get_elgamal_encrypted_view_key(id) simplifies the API by using a specialized getter instead of a generic derivation method with branch parameter. The usage at lines 110 and 119 shows the return type is compatible.

integration_tests/tests/steps/wallet_daemon.rs (1)

15-15: LGTM: Import path updated in integration tests.

The import path change aligns the integration tests with the new public API where KeyBranch is exported from the models module.

integration_tests/tests/steps/wallet.rs (1)

14-14: LGTM: Import path updated in integration tests.

The import path change maintains consistency with the new public API structure where KeyBranch is now exported from the models module.

clients/wallet_daemon_client/src/lib.rs (1)

40-40: LGTM: Client updated to use new public API path.

The wallet daemon client import is updated to reference KeyBranch from the public models module, ensuring the client uses the officially exported API surface. The public interface of the client remains unchanged.

crates/transaction/src/v1/unsigned.rs (1)

148-154: LGTM! Signable implementation is correct.

The Signable trait implementation for UnsignedTransactionV1 correctly delegates to TransactionSignature::create_message with the appropriate schema version (1) for V1 transactions. This enables the signing flow described in the PR objectives.

crates/common_types/src/lib.rs (1)

30-30: LGTM! Standard module addition.

The signable module is correctly added and publicly re-exported, making the Signable and IntoSigned traits available as part of the public API for the signing flow.

Also applies to: 54-54

crates/transaction/src/transaction.rs (1)

245-245: Schema version type narrowed to u16.

The return type change from u64 to u16 is a breaking change that aligns with the PR's stated objective to bind transaction signatures to schema version (v1). This change is consistent across all transaction types.

applications/tari_wallet_cli/src/command/key.rs (1)

24-24: LGTM! Import path updated to reflect module restructuring.

The consolidated import path for KeyBranch and KeyId from tari_ootle_wallet_sdk::models aligns with the PR-wide refactoring that moves these types to the public models module.

crates/wallet/sdk/src/key_managers/mod.rs (1)

1-7: LGTM! Well-organized module structure.

The module correctly exposes the key management backend interfaces publicly while organizing the implementation details appropriately. The backend module is re-exported for public access to signing traits, and the local submodule provides the local key manager implementation.

crates/wallet/sdk_services/src/account_recovery/service.rs (1)

15-16: LGTM! Import paths updated for module restructuring.

The reorganized imports reflect the migration of KeyBranch and KeyId to the public models module, consistent with the broader refactoring across the PR.

crates/transaction/src/v1/transaction.rs (1)

44-44: Schema version type narrowed to u16.

The return type change from u64 to u16 for the schema_version method is consistent with the schema versioning changes across the transaction module and aligns with the PR's breaking change to bind signatures to schema version.

clients/wallet_daemon_client/src/types.rs (1)

42-48: LGTM! Import paths updated for consistency.

The reorganized imports correctly reference KeyBranch from the models module, maintaining consistency with the PR-wide refactoring that centralizes key management types in the public models API.

crates/wallet/sdk/src/sdk.rs (1)

169-185: LGTM! Clear panic documentation.

The local_signer_api() method correctly panics with a clear error message if the cipher seed hasn't been initialized, and the documentation explicitly states this precondition. The panic is appropriate for this initialization requirement.

applications/tari_walletd/src/handlers/confidential.rs (1)

290-290: LGTM! Improved API specificity.

The change from derive_key(KeyBranch::ElgamalEncryptionViewKey, ...) to get_elgamal_encrypted_view_key(...) is more specific and aligns with the principle of not exposing raw key material directly from the key manager API.

crates/transaction/src/unsigned_transaction.rs (2)

21-25: LGTM! Schema versioning support added.

The schema_version() method correctly returns version 1 for V1 transactions, enabling version-aware transaction signing as described in the PR objectives. This is a key component of the breaking change that binds signatures to the schema version.


158-166: LGTM! Clean Signable trait implementation.

The trait implementation correctly delegates signing message generation to the inner V1 transaction, maintaining the version-specific signing logic.

crates/transaction/src/builder/mod.rs (2)

69-71: LGTM! Builder pattern enhancement.

Making then() public enables external callers to compose builder operations with closures, improving the builder's flexibility and usability.


485-502: LGTM! Clean trait implementations for signing support.

The Signable and IntoSigned trait implementations cleanly enable the TransactionBuilder to participate in the generic signing API. The implementations correctly:

  • Delegate signing message generation to the underlying unsigned transaction
  • Convert signing results (public key + signature) into a TransactionSignature and add it to the builder
applications/tari_walletd/src/handlers/keys.rs (1)

31-33: KeyId-driven public key retrieval is correct.

The get_public_key/next_public_key flow aligns with the new KeyId API.

applications/tari_walletd/src/handlers/nfts.rs (3)

122-127: Switch to local_signer_api().sign is aligned with the new flow.

Good migration from build_and_seal to build + local signer.


296-314: Verify intent: signer key vs. authorized seal signer context.

You authorize the fee payer as the seal signer (with_authorized_seal_signer), then sign_with_context using the source account owner key and the fee payer’s public key as context. Confirm this is the intended authorization model (owner attests fee payer as seal signer) and that no further signatures are needed from the fee payer before submission.

If needed, I can scan call sites to ensure submit/seal paths don’t expect a separate fee-payer signature.


316-319: Final sign after build looks correct.

The second sign binds the sealed transaction to the v1 schema as per new semantics.

Ensure no additional signatures are appended after this step, since the seal signature will commit to the current signature set.

crates/transaction/src/v1/unsealed.rs (4)

42-44: Schema version to u16 looks good.

Matches the v1 versioning approach used elsewhere.


86-88: Switched to verify_v1 as expected.

Consistent with message versioning changes.


138-147: IntoSigned wraps the provided signature without recomputation.

Looks correct given the signer computes the signature over as_signing_message.

Double-check that the signing API for UnsealedTransactionV1 uses this exact message (schema_version + self).


127-136: Seal signature and signing message constructors are aligned. TransactionSealSignature::create_message and UnsealedTransactionV1::as_signing_message use the same engine_hasher64→schema_version→transaction sequence.

crates/wallet/sdk/src/key_managers/local.rs (2)

47-65: LGTM!

The signing implementation correctly handles both derived and imported keys, with appropriate error handling and clear documentation of infallibility assumptions.


68-84: LGTM!

The error type design is sound, properly wrapping underlying errors and implementing IsNotFoundError for error propagation semantics.

crates/wallet/sdk/src/apis/stealth_outputs.rs (3)

235-281: LGTM!

The refactoring to use KeyBranch-based key retrieval is clean and improves the API surface. The change from public to private visibility for resolve_output_masks_for_spending is appropriate since the functionality is now exposed through the new public methods below.


719-752: LGTM!

The new public encryption/decryption methods provide a clean abstraction over the lower-level crypto API, properly integrating with the key manager workflow.


756-765: LGTM!

The addition of spend_key_branch to TransferStatementParams properly supports the new key derivation workflow.

applications/tari_walletd/src/handlers/accounts.rs (5)

31-31: LGTM!

The import update reflects the move of KeyBranch and KeyId to the public models module, aligning with the broader API refactoring.


557-564: LGTM!

The migration to the two-step build-then-sign pattern is consistent with the new signer API design. Using a throwaway nonce for signing is appropriate here since the claim burn instruction is authorized by the proofs rather than by the signer.


665-669: LGTM!

Proper use of account-based signing for the create free test coins operation, which requires account authorization.


856-860: LGTM!

The transfer handler correctly uses account-based signing as account authorization is required for withdrawals.


990-1005: LGTM!

The conditional key selection logic is well-reasoned: account key signing is required when revealed amounts are involved, otherwise a throwaway nonce suffices. This aligns with the authorization model.

crates/wallet/sdk/src/models/key.rs (4)

14-54: LGTM!

The KeyBranch enum is well-designed with clear documentation for each variant. The as_str method and AsRef<str> implementation provide convenient string conversions. The variants cover all necessary key derivation use cases.


127-150: LGTM!

The WalletPublicKey abstraction cleanly pairs a public key with its identifier, providing a safer API surface than raw key types. The accessor methods and From<DerivedWalletKey> conversion are appropriately implemented.


152-206: LGTM!

The WalletSecretKey type properly encapsulates a secret key with its identifier, and the multiple From implementations provide convenient conversions from various key types. The to_public_key method is a useful addition.


208-213: LGTM!

Updating AccountAndViewKeys to use WalletSecretKey instead of the previous Key type maintains consistency with the new type system.

crates/wallet/sdk/src/apis/key_manager.rs (5)

126-145: LGTM!

The return type changes from Key to WalletSecretKey maintain API consistency with the new type system. The pub(crate) visibility for get_key appropriately restricts access to internal SDK usage.


147-165: LGTM!

The new get_public_key method is a useful addition that allows retrieving public keys without exposing secret keys. The TODO comment about optimizing imported key lookups is a good note for future improvements.


167-172: LGTM!

The new get_elgamal_encrypted_view_key method provides a clear, purpose-specific API for retrieving ElGamal encryption view keys, improving code readability at call sites.


260-270: LGTM!

The next_public_key method complements next_key by returning only the public key representation, useful when secret keys aren't needed.


318-330: LGTM!

Updating get_key_or_active to return WalletPublicKey instead of Key maintains consistency with the new type system while preserving the method's convenience of falling back to the active key.

Comment on lines +34 to 36
id: key.key_id.derived_index().expect("Key is derived"),
public_key: key.public_key.to_byte_type(),
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid panic on non-derived key; map to a user error.

expect("Key is derived") will crash the handler if invariants change. Convert this to a proper error and return 400/500 instead.

Apply this diff to handle the error explicitly:

-    Ok(KeysCreateResponse {
-        id: key.key_id.derived_index().expect("Key is derived"),
-        public_key: key.public_key.to_byte_type(),
-    })
+    let id = key
+        .key_id
+        .derived_index()
+        .ok_or_else(|| anyhow::anyhow!("Expected a derived key from key_manager_api()"))?;
+    Ok(KeysCreateResponse {
+        id,
+        public_key: key.public_key.to_byte_type(),
+    })
🤖 Prompt for AI Agents
In applications/tari_walletd/src/handlers/keys.rs around lines 34 to 36, the
code calls key.key_id.derived_index().expect("Key is derived") which can panic;
replace the expect with explicit error handling that maps a non-derived key into
a user-facing error and returns an appropriate HTTP response (e.g., 400 Bad
Request) or Result::Err for internal handlers. Change the handler to propagate
the Result from derived_index() (or match its Option) and construct a clear
error variant/message when the key is not derived, then return that error (or
convert it to a response with status 400/500) instead of panicking.

Comment thread applications/tari_walletd/src/handlers/validator.rs
Comment thread crates/wallet/sdk/src/key_managers/backend.rs
Comment on lines +81 to 85
let key = self
.sdk
.key_manager_api()
.get_public_key(KeyBranch::Account, KeyId::derived(0))?;
let key_index_start = *account_key_indexes.start();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fee signer should match pay_fee_account.owner_key_id, not derived(0)

Signing the batch account creation with a hardcoded derived(0) will fail if the paying account uses another key id. Use pay_fee_account.owner_key_id.

-        let key = self
-            .sdk
-            .key_manager_api()
-            .get_public_key(KeyBranch::Account, KeyId::derived(0))?;
+        let pay_fee_key_id = pay_fee_account
+            .owner_key_id
+            .expect("pay_fee_account has no owner_key_id");

 ...

-        let transaction = self
-            .sdk
-            .local_signer_api()
-            .sign(KeyBranch::Account, key.key_id, transaction)?;
+        let transaction = self
+            .sdk
+            .local_signer_api()
+            .sign(KeyBranch::Account, pay_fee_key_id, transaction)?;

Also applies to: 117-121

🤖 Prompt for AI Agents
In utilities/tariswap_test_bench/src/accounts.rs around lines 81-85 (and
similarly at 117-121), the fee signer key is being fetched using a hardcoded
KeyId::derived(0); replace that with the paying account's owner key id by using
pay_fee_account.owner_key_id when calling get_public_key / key retrieval so the
signer matches pay_fee_account.owner_key_id instead of always derived(0); ensure
both occurrences are updated and any variable names or types adjusted
accordingly.

Comment thread utilities/tariswap_test_bench/src/tariswap.rs
@github-actions

Copy link
Copy Markdown

Test Results (CI)

472 tests  ±0   462 ✅ +1   1h 31m 56s ⏱️ - 2m 16s
 78 suites ±0     0 💤 ±0 
  2 files   ±0    10 ❌  - 1 

For more details on these failures, see this check.

Results for commit 402bde1. ± Comparison against base commit edd96aa.

@sdbondi
sdbondi merged commit 53bf250 into tari-project:development Oct 15, 2025
13 of 14 checks passed
sdbondi added a commit to tari-project/ootle-wallet-cli that referenced this pull request Oct 15, 2025
@sdbondi
sdbondi deleted the wallet-key-manager-backend branch October 15, 2025 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants