Skip to content

feat!: generate stealth statements from wallet api+new sending test - #1620

Merged
sdbondi merged 2 commits into
tari-project:developmentfrom
sdbondi:util-traffic-sim
Oct 29, 2025
Merged

feat!: generate stealth statements from wallet api+new sending test#1620
sdbondi merged 2 commits into
tari-project:developmentfrom
sdbondi:util-traffic-sim

Conversation

@sdbondi

@sdbondi sdbondi commented Oct 29, 2025

Copy link
Copy Markdown
Member

Description

feat!: generate stealth statements from wallet api+new sending test
fix: endianness mismatch in value lookup file header
feat: list utxos indexer api
fix: separate input selections strategies for fees and main
fix: multithreaded value ristretto key generator
feat: util that sends funds between wallets in swarm
fix!: set balance proof to None if the transfer statement only involves revealed funds.

Motivation and Context

Allows stealth statements to be generated from API calls, this is used in the new util to send faucet funds as UTXOs.
Also would allow floweditor/manifest to generate stealth statements for built transactions.

Generating a value lookup file for hundreds of millions of values took more than an hour. This PR reduces this to 5-10 minutes.

The new util (traffic sim), funds and transfers funds between all wallets in the swarm. It can also ask the "exchange" wallet to decrypt utxo values.

How Has This Been Tested?

Manually, new unit tests

Breaking Changes

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

Summary by CodeRabbit

  • New Features

    • Paginated UTXO listing endpoint; full-UTXO list API.
    • Batch stealth transfer statement API.
    • Traffic-sim CLI for multi-wallet simulation, funding and UTXO decryption.
  • Improvements

    • Unified signing flow with seal-signer and multi-signer support.
    • Async, multi-threaded value lookup generation with validation and progress.
    • JS/TS bindings and APIs now use UTXO-based input selection and new transfer types.
  • Bug Fixes

    • Fixed value-lookup endianness and tightened input validation.
    • Renamed stealth decrypt response field (balances → values) and improved related logging.

@coderabbitai

coderabbitai Bot commented Oct 29, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Bumps workspace version and adds a new utilities crate; renames and extends UTXO APIs (GetUnspent* → GetUtxos/ListUtxos) across indexer, storage, client, and bindings; migrates input-selection and signing model (ConfidentialTransferInputSelection → UtxoInputSelection; signing_key_id → seal_signer/other_signers/lock_ids); makes balance_proof optional; adds WalletLockDropGuard and traffic-sim.

Changes

Cohort / File(s) Summary
Workspace & packages
Cargo.toml, bindings/package.json, clients/javascript/*/package.json
Workspace/package versions bumped (0.14.2→0.15.0; JS packages bumped); new workspace member utilities/traffic-sim.
Indexer REST & server
applications/tari_indexer/src/rest_api/handlers/utxos.rs, applications/tari_indexer/src/rest_api/server.rs
Replaced GetUnspentUtxos* with GetUtxos*; added new GET /utxos endpoint using ListUtxosRequest/ListUtxosResponse and limit validation.
Indexer storage & API
applications/tari_indexer/src/storage_sqlite/reader.rs, applications/tari_indexer/src/store.rs, applications/tari_indexer/src/substate_manager.rs
Added utxos_list implementation and trait method to enumerate unspent UTXOs with optional from_id and limit; query aliasing refined.
Indexer client & types / bindings
clients/tari_indexer_client/src/*, bindings/src/tari-indexer-client.ts, bindings/src/types/tari-indexer-client/*
Renamed types to GetUtxosRequest/GetUtxosResponse; added ListUtxosRequest/ListUtxosResponse; updated client methods and exports.
Signing model & transaction submit
applications/tari_wallet_cli/*, applications/tari_walletd/src/handlers/transaction.rs, bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts, clients/javascript/*
Replaced signing_key_id with seal_signer: BranchAndKeyId, added other_signers, replaced proof_idslock_ids; enforce owner_key_id derivation and updated dry-run/submit flows.
Stealth transfer: optional balance_proof
crates/template_lib/src/models/stealth.rs, crates/engine_types/src/stealth/transfer.rs, crates/p2p/src/conversions/transaction.rs, bindings/src/types/StealthTransferStatement.ts
Made balance_proof optional/null; added revealed-only constructors and adapted validation/conversion/serialization paths.
Stealth transfer API & params
crates/wallet/sdk/src/apis/stealth_transfer/*, applications/tari_walletd/src/handlers/accounts.rs
Replaced ConfidentialTransferInputSelection → UtxoInputSelection; added fee_input_selection to StealthTransferParams; enhanced InsufficientFunds error; added create_stealth_transfer_statement handler and types.
Confidential transfer & transaction wiring
crates/wallet/sdk/src/apis/confidential_transfer.rs, crates/wallet/sdk/src/sdk.rs
Integrated TransactionApi for lock->tx linking; switched to UtxoInputSelection; adjusted constructor and trait bounds.
Wallet lock drop guard
crates/wallet/sdk/src/models/lock_guard.rs, crates/wallet/sdk/src/models/mod.rs
New WalletLockDropGuard<TStore> that auto-releases locks on drop (with disarm) and module re-export.
Key model: BranchAndKeyId
crates/wallet/sdk/src/models/key.rs, bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts
New BranchAndKeyId struct/type with helpers (new, for_account) and Display; bindings added.
Bindings: input-selection migration & new types
bindings/src/index.ts, bindings/src/types/*, bindings/src/wallet-daemon-client.ts
Removed ConfidentialTransferInputSelection export; added UtxoInputSelection and many wallet-daemon-client types (TransferStatementRequest/TransferOutput/InputSelection/AccountsCreateStealthTransferStatementRequest/Response, etc.); updated request shapes (fee_input_selection, lock_ids, seal_signer).
Bindings & JS client surface
bindings/src/*, clients/javascript/wallet_daemon_client/src/index.ts, clients/wallet_daemon_client/src/*
Aligned JS/Rust client types: dry-run uses TransactionSubmitRequest, submitDryRun param types updated, new accounts_create_stealth_transfer_statement endpoint, From<&str> for ComponentAddressOrName.
Walletd handlers & JSON-RPC
applications/tari_walletd/src/handlers/{accounts.rs,helpers.rs,stealth_utxos.rs,transaction.rs}, applications/tari_walletd/src/jrpc_server.rs
Added handle_create_stealth_transfer_statement and JSON-RPC mapping; improved account-not-found behavior; stealth UTXO decrypt: validation, spawn_blocking with abort-on-drop guard, renamed response balancesvalues, LOG_TARGET update.
Web UI & TS updates
applications/tari_walletd/web_ui/src/routes/*, applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts, applications/tari_walletd/web_ui/src/utils/json_rpc.ts
Replaced ConfidentialTransferInputSelection→UtxoInputSelection; enforce owner_key_id in FlowEditor; add seal_signer/other_signers/lock_ids usage; divisibility formatting; updated submitTransactionDryRun types.
Value lookup & ristretto generator
crates/wallet/crypto/src/value_lookup/*, utilities/generate_ristretto_value_lookup/*
Header endianness LE→BE and seek offset adjustment; ValueLookupTable re-exported; generator rewritten async Tokio multi-threaded with jobs/validate and progress.
Engine crypto logging
crates/engine_types/src/crypto/elgamal.rs
Added info/warn logging and single-warning fallback for missing lookup entries.
Stealth crypto & templates
crates/wallet/crypto/src/stealth.rs, crates/wallet/sdk/src/apis/stealth_crypto.rs, crates/template_builtin/templates/faucet/src/lib.rs, crates/transaction/src/v1/unsigned.rs, tests
Tightened iterator bounds to ExactSizeIterator; create_transfer_statement may return None balance_proof when empty; faucet now derives signer from context; unsigned txn references include UTXO substates.
Traffic-sim utility
utilities/traffic-sim/{Cargo.toml,src/{main.rs,sim.rs}}
New traffic-sim crate with CLI and TrafficSim harness to discover/connect wallets, setup accounts/funds, send randomized stealth transfers, decrypt UTXOs, and list wallets.
Misc infra & epoch
applications/tari_validator_node/src/cli.rs, crates/epoch_oracles/src/*
Peer-seeds override per-network; epoch ticker emits to catch up to calculated epoch and added test; clarified TODO for conditional deletion.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Web UI / CLI
    participant WalletD as Wallet Daemon
    participant SDK as Wallet SDK
    participant Store as Wallet Store

    Client->>WalletD: create_stealth_transfer_statement(requests)
    activate WalletD
    WalletD->>SDK: generate_transfer_statement per request
    activate SDK
    SDK->>SDK: choose signer (account or nonce-derived)
    SDK->>Store: create_lock() -> lock_id
    Store-->>SDK: lock_id
    SDK->>SDK: build statements (balance_proof Some/None)
    SDK-->>WalletD: statements + signing_keys + lock_id
    deactivate SDK
    WalletD-->>Client: response { statements, lock_id, signing_keys }
    deactivate WalletD
Loading
sequenceDiagram
    participant App as Application
    participant ConfApi as ConfidentialTransferApi
    participant TxApi as TransactionApi
    participant Store as Wallet Store

    App->>ConfApi: confidential_transfer(seal_signer, lock_ids, ...)
    activate ConfApi
    ConfApi->>ConfApi: resolve inputs using UtxoInputSelection
    ConfApi->>TxApi: locks_set_transaction_id(lock_id, tx_id)
    activate TxApi
    TxApi->>Store: link lock -> tx
    Store-->>TxApi: OK
    deactivate TxApi
    ConfApi-->>App: result
    deactivate ConfApi
Loading
sequenceDiagram
    participant Client as Indexer Client
    participant REST as Indexer REST
    participant SubMgr as SubstateManager
    participant DB as SQLite Reader

    Client->>REST: GET /utxos?resource_address=...&limit=...&from_id=...
    activate REST
    REST->>SubMgr: list_utxos(resource_address, from_id, limit)
    activate SubMgr
    SubMgr->>DB: utxos_list(resource_address, from_id, limit)
    activate DB
    DB-->>SubMgr: Vec<(UtxoId, Utxo)>
    deactivate DB
    SubMgr-->>REST: ListUtxosResponse{utxos}
    REST-->>Client: 200 { utxos: [...] }
    deactivate SubMgr
    deactivate REST
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–75 minutes

Areas needing extra attention:

  • Transaction signing migration (seal_signer/other_signers/lock_ids) across daemon, CLI, bindings, JS clients, and tests.
  • Optional balance_proof propagation: serialization, verification, and p2p/template conversions.
  • WalletLockDropGuard drop semantics and disarm correctness.
  • Indexer utxos_list SQL/subquery correctness and pagination behavior.
  • Traffic-sim async orchestration and generate_ristretto_value_lookup multithreading/validation.

Possibly related PRs

"🐰
I hopped through crates and binding lands,
Swapped seals for keys with careful hands,
Optional proofs now hide or show,
Locks drop softly when they must go,
A traffic-sim dances, async streams in bands."

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.05% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "feat!: generate stealth statements from wallet api+new sending test" directly references two significant components of the changeset: the new stealth statement generation API (AccountsCreateStealthTransferStatementRequest/Response, handle_create_stealth_transfer_statement, and related endpoints across multiple handlers) and the traffic-sim utility that enables sending transactions between wallets in a swarm. The title accurately reflects the main user-facing features introduced by this PR. While the changeset includes additional improvements such as the list UTXOs API endpoint, value lookup file fixes, and balance proof handling changes, these are supporting infrastructure improvements that enable the primary features mentioned in the title. The title is concise, specific, and clearly conveys the primary intent to someone scanning git history.
✨ 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: 16

Caution

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

⚠️ Outside diff range comments (8)
crates/epoch_oracles/src/configured/real_time_ticker.rs (3)

91-103: Recompute calculated_epoch on every tick; current code can hang when start_epoch > calculated_epoch.

calculated_epoch is computed once before the loop and never updated. If self.epoch > calculated_epoch, the condition never becomes true and poll_tick never returns. This breaks the new “base time in future” case.

Apply this focused diff:

           loop {
               // Every tick, check if we need to emit a new epoch
               ready!(interval_mut.poll_tick(cx));
-
-              if self.epoch <= calculated_epoch {
+              // Recompute against current time each tick
+              let calculated_epoch = self.calc_current_epoch();
+              if self.epoch <= calculated_epoch {
                   let epoch = self.increment_epoch();
                   let epoch_hash = calc_static_epoch_hash(epoch);
                   return Poll::Ready(Some(EpochTickerData {
                       epoch,
                       epoch_hash,
                       done_for_now: true,
                   }));
               }
           }

111-116: Compile fix: qualify size_of (not in prelude).

Without an import, size_of won’t resolve.

-    const U64_SIZE: usize = size_of::<u64>();
+    const U64_SIZE: usize = std::mem::size_of::<u64>();

Optional: avoid const if FixedHash::byte_size() isn’t const fn:

-    const HASH_SIZE: usize = FixedHash::byte_size();
-    let mut epoch_hash = [0u8; HASH_SIZE];
-    epoch_hash[HASH_SIZE - U64_SIZE..].copy_from_slice(&epoch.to_be_bytes());
+    let hash_size = FixedHash::byte_size();
+    let mut epoch_hash = [0u8; 32]; // or [0u8; hash_size] if const-evaluable
+    epoch_hash[hash_size - U64_SIZE..].copy_from_slice(&epoch.to_be_bytes());

105-108: Return Poll::Ready(None) to signal stream termination when ticks are disabled.

The EpochTicker trait is designed to support stream termination via Poll::Ready(None), as demonstrated by the WatchEpochTicker implementation and its test expecting None after completion. The oracle caller already handles this case correctly (oracle.rs:198–202). Returning Poll::Pending without registering a waker violates the polling contract and causes a deadlock when ticks are disabled.

-        // Ticks have been disabled, never return any new epochs
-        assert!(self.interval.is_none(), "If interval is Some, we should not reach here");
-        Poll::Pending
+        // Ticks disabled: terminate stream
+        debug_assert!(self.interval.is_none(), "If interval is Some, we should not reach here");
+        Poll::Ready(None)
integration_tests/tests/steps/wallet_daemon.rs (1)

211-213: Fix logging placeholder (currently prints literal “{public_key}”).

Use format! to include the key value.

-    cucumber_log("Burning funds using claim key {public_key}");
+    cucumber_log(format!("Burning funds using claim key {}", public_key));
crates/wallet/sdk/src/apis/stealth_transfer/api.rs (1)

235-246: Bug: lock_id shadowing creates a new lock and leaks the caller’s lock.

PreferConfidential creates a fresh lock_id instead of using the provided one. The caller will attempt to release the original lock_id, leaving these new locks orphaned. Use the passed lock_id.

-            UtxoInputSelection::PreferConfidential => {
-                let lock_id = self.outputs_api.create_lock()?;
-                let (inputs, blinded_amount_locked) = self.outputs_api.lock_outputs_until_partial_amount(
+            UtxoInputSelection::PreferConfidential => {
+                let (inputs, blinded_amount_locked) = self.outputs_api.lock_outputs_until_partial_amount(
                     owner_account_component_address,
                     &resource_address,
                     spend_amount,
-                    lock_id,
+                    lock_id,
                 )?;
crates/wallet/sdk/src/apis/confidential_transfer.rs (1)

286-299: Lock leak on error path — release lock before returning Err.

When resolved_inputs_for_transfer fails, the lock_id created just before it is never released. Release it before returning.

         let inputs_to_spend = match self.resolved_inputs_for_transfer(
             lock_id,
             params.from_account,
             params.resource_address,
             params.amount,
             params.input_selection,
         ) {
             Ok(inputs) => inputs,
             Err(e) => {
-                warn!(target: LOG_TARGET, "Unlocking fee fund locks after error: {}", e);
-                return Err(e);
+                warn!(target: LOG_TARGET, "Unlocking input locks after error: {}", e);
+                if let Err(err) = self.confidential_outputs_api.release_lock(lock_id) {
+                    error!(target: LOG_TARGET, "Failed to release lock after error: {}", err);
+                }
+                return Err(e);
             },
         };
applications/tari_walletd/src/handlers/transaction.rs (1)

252-260: Bug: dry-run signs with Account branch regardless of request

handle_submit_dry_run always uses KeyBranch::Account even if req.seal_signer specifies a different branch. This will fail for Nonce/other branches.

Apply:

-    let transaction = sdk
-        .local_signer_api()
-        .sign(KeyBranch::Account, key.key_id, transaction)?;
+    let transaction = sdk
+        .local_signer_api()
+        .sign(req.seal_signer.branch, req.seal_signer.key_id, transaction)?;
clients/wallet_daemon_client/src/types.rs (1)

1183-1189: Update DecryptUtxoBalance.tsx: maximum_expected_value cannot be null

The breaking change is confirmed—maximum_expected_value is now required (non-optional). However, applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx:48 incorrectly assigns null when formState.maximumExpectedValue is falsy. This violates the type constraint; either provide a sensible default or require the field in the form.

🧹 Nitpick comments (35)
applications/tari_walletd/src/handlers/helpers.rs (1)

150-152: LGTM! Improved error specificity.

The change to use .optional()?.ok_or_else(|| not_found(...)) provides clearer, more actionable error messages when an account is not found. This pattern correctly distinguishes between "not found" cases and genuine errors, improving the API's usability.

Optional style nitpick: The trailing comma in the format! macro on line 152 is valid but unconventional:

-        result = get_account(a, accounts_api)
-            .optional()?
-            .ok_or_else(|| not_found(format!("Account '{a}' not found.",)))?;
+        result = get_account(a, accounts_api)
+            .optional()?
+            .ok_or_else(|| not_found(format!("Account '{a}' not found.")))?;
crates/engine_types/src/crypto/elgamal.rs (1)

232-232: Consider debug level or summary logging for batch operations.

Logging every found balance at info level may generate excessive log volume during batch operations, especially with the new traffic-sim utility.

Consider one of these alternatives:

Option 1: Use debug level for individual items

-                info!(target: LOG_TARGET, "Found encrypted balance: {}", v);
+                debug!(target: LOG_TARGET, "Found encrypted balance: {}", v);

Option 2: Add a summary log after the loop completes

         }
+        
+        let found_count = results.iter().filter(|r| r.is_some()).count();
+        info!(target: LOG_TARGET, "Found {}/{} encrypted balances", found_count, results.len());
 
         Ok(results)
applications/tari_walletd/src/handlers/stealth_utxos.rs (1)

60-60: Consider extracting helper functions to reduce function length.

The function is quite long (128 lines). While the linear flow makes it readable, extracting the file-based and in-memory lookup logic into separate helper functions could improve maintainability.

For example, you could extract:

  • spawn_file_based_lookup(...) for lines 112-146
  • spawn_in_memory_lookup(...) for lines 153-161
+async fn spawn_file_based_lookup(
+    sdk: WalletSdk,
+    path: PathBuf,
+    view_key: ViewKey,
+    elgamal_proofs: Vec<_>,
+    value_range: RangeInclusive<u64>,
+) -> JoinHandle<anyhow::Result<Vec<u64>>> {
+    spawn_blocking(move || {
+        let mut file = fs::File::open(&path)
+            .map_err(|e| anyhow!("Unable to load value lookup file '{}': {e}", path.display()))?;
+        let mut lookup = IoReaderValueLookup::load(&mut file)?;
+        info!(
+            target: LOG_TARGET,
+            "Using value lookup table from file '{}' ({}-{}) for brute force balance lookup",
+            path.display(),
+            lookup.range().start(),
+            lookup.range().end()
+        );
+        
+        let start = value_range.start();
+        let end = value_range.end();
+        if start < lookup.range().start() || end > lookup.range().end() {
+            warn!(
+                target: LOG_TARGET,
+                "The requested value range ({}-{}) is outside the loaded value lookup table range ({}-{}). \
+                 This query may take excessive amount of time.",
+                start,
+                end,
+                lookup.range().start(),
+                lookup.range().end()
+            );
+        }
+        
+        sdk.viewable_balance_api().try_brute_force_commitment_balances(
+            &view_key.key,
+            elgamal_proofs.iter(),
+            value_range,
+            &mut lookup,
+        )
+    })
+}
crates/template_lib/src/models/stealth.rs (3)

33-42: Guard against negative revealed output amounts

Add a simple non-negative check to match inputs-side validation and avoid constructing invalid statements.

Apply:

 impl StealthOutputsStatement {
   /// Create a new output statement with no stealth outputs, only a revealed amount.
   pub fn new_revealed_only(amount: Amount) -> Self {
+      assert!(!amount.is_negative(), "Revealed output amount must be non-negative");
       Self {
           outputs: vec![],
           revealed_output_amount: amount,
           agg_range_proof: RangeProofBytes::empty(),
       }
   }
 }

95-97: Optional balance_proof: consider eliding nulls in JSON

If these structs are serialized to JSON anywhere, add serde skip to avoid emitting explicit nulls; wire format (borsh/proto) unaffected.

Apply:

-    #[cfg_attr(feature = "ts", ts(type = "{public_nonce: string, signature: string} | null"))]
-    pub balance_proof: Option<BalanceProofSignature>,
+    #[cfg_attr(feature = "ts", ts(type = "{public_nonce: string, signature: string} | null"))]
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub balance_proof: Option<BalanceProofSignature>,

101-111: Assert the “revealed-only” invariant locally

Add a debug assertion to ensure this constructor never sneaks in stealth I/O and keeps balance_proof None only in that case.

Apply:

 pub fn revealed_only(
     input_amount: Amount,
     output_amount: Amount,
     required_signer: RistrettoPublicKeyBytes,
 ) -> Self {
-    Self {
-        inputs_statement: StealthInputsStatement::new_revealed_only(input_amount, required_signer),
-        outputs_statement: StealthOutputsStatement::new_revealed_only(output_amount),
-        balance_proof: None,
-    }
+    let inputs_statement = StealthInputsStatement::new_revealed_only(input_amount, required_signer);
+    let outputs_statement = StealthOutputsStatement::new_revealed_only(output_amount);
+    debug_assert!(
+        inputs_statement.inputs.is_empty() && outputs_statement.outputs.is_empty(),
+        "revealed_only must have no stealth inputs/outputs"
+    );
+    Self {
+        inputs_statement,
+        outputs_statement,
+        balance_proof: None,
+    }
 }

Also, the struct docstrings above still say “must contain confidential outputs”; please update to reflect revealed-only allowance.

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

823-824: Add a debug invariant on serialization symmetry

Ensure we never serialize a stealth transfer with missing proof unless it’s revealed-only.

Apply:

 impl From<tari_template_lib::models::StealthTransferStatement> for proto::transaction::StealthTransferStatement {
     fn from(value: tari_template_lib::models::StealthTransferStatement) -> Self {
+        let is_revealed_only =
+            value.inputs_statement.inputs.is_empty() && value.outputs_statement.outputs.is_empty();
+        let balance_proof_bytes = value.balance_proof.as_ref().map(|b| b.to_bytes()).unwrap_or_default();
+        debug_assert!(
+            (is_revealed_only && balance_proof_bytes.is_empty()) ||
+            (!is_revealed_only && !balance_proof_bytes.is_empty()),
+            "Invariant: balance_proof must be present unless revealed-only"
+        );
         Self {
             inputs_statement: Some(value.inputs_statement.into()),
             outputs_statement: Some(value.outputs_statement.into()),
-            balance_proof: value.balance_proof.as_ref().map(|b| b.to_bytes()).unwrap_or_default(),
+            balance_proof: balance_proof_bytes,
         }
     }
 }
crates/epoch_oracles/src/configured/real_time_ticker.rs (2)

66-75: Gate the “fast-forward to initial epoch” on self.epoch too.

Avoid needless emissions once self.epoch has already reached/passed initial_epoch.

-        if calculated_epoch < self.initial_epoch {
+        if calculated_epoch < self.initial_epoch && self.epoch < self.initial_epoch {
             let epoch = self.increment_epoch();
             let epoch_hash = calc_static_epoch_hash(epoch);
             return Poll::Ready(Some(EpochTickerData {
                 epoch,
                 epoch_hash,
                 done_for_now: false,
             }));
         }

164-177: Test relies on loop recompute; will stall without it.

With the fix to recompute calculated_epoch per tick, this test should pass. Without it, poll_tick never returns when base time > now.

Consider injecting a clock (trait or now_fn) into RealTimeEpochTicker so tests don’t depend on wall-clock timing.

utilities/traffic-sim/Cargo.toml (3)

10-11: Relax version pins to caret for compatibility.

Use caret constraints to pick up compatible bugfixes without manual bumps.

-clap = { version = "4.0", features = ["derive"] }
-tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
+clap = { version = "4", features = ["derive"] }
+tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

15-15: Prefer rustls and disable reqwest default features.

Avoid platform OpenSSL issues and shrink dependency tree.

-reqwest = { workspace = true, features = ["json"] }
+reqwest = { workspace = true, default-features = false, features = ["json", "rustls-tls"] }

If the workspace sets reqwest TLS features globally, confirm no duplication/conflict.


19-19: Avoid hard pin on csv unless strictly required.

Use caret for patch updates; keeps reproducible yet flexible.

-csv = "1.4.0"
+csv = "1.4"
applications/tari_wallet_cli/src/command/transaction.rs (4)

253-256: Improve error context for missing owner key.

Include the fee account address to speed up debugging.

-    let owner_key_id = fee_account
-        .owner_key_id
-        .ok_or_else(|| anyhow!("Fee account does not have an owner key ID"))?;
+    let owner_key_id = fee_account
+        .owner_key_id
+        .ok_or_else(|| anyhow!("Fee account {} does not have an owner key ID", fee_account.component_address))?;

285-291: LGTM – explicit seal_signer and detect_inputs flags are correct.

Consider factoring common request fields to reduce duplication between dry-run and submit.

Also applies to: 297-302, 355-360, 366-371


325-328: Apply the same improved error context in manifest submit.

Mirror the enhanced message here for consistency.

-    let owner_key_id = fee_account
-        .owner_key_id
-        .ok_or_else(|| anyhow!("Fee account does not have an owner key ID"))?;
+    let owner_key_id = fee_account
+        .owner_key_id
+        .ok_or_else(|| anyhow!("Fee account {} does not have an owner key ID", fee_account.component_address))?;

445-445: Make input selection configurable.

Defaulting to PreferConfidential is fine, but expose a CLI flag to toggle selection for ops/debug.

Would you like me to add --input-selection {PreferRevealed|PreferConfidential|RevealedOnly|ConfidentialOnly}? I can wire it with clap and map to UtxoInputSelection.

crates/wallet/sdk/src/apis/stealth_transfer/error.rs (1)

5-5: LGTM – error context improved with Amounts.

Consider adding serde derives if this bubbles over API boundaries.

crates/wallet/sdk/src/apis/stealth_transfer/params.rs (1)

22-24: Clarify field-level documentation.

The comments on lines 22 and 23 are identical. Consider clarifying the distinction between fee_input_selection (for fee payment) and input_selection (for main transfer amounts) to improve code maintainability.

Apply this diff to improve the documentation:

-    /// Strategy for input selection
     pub fee_input_selection: UtxoInputSelection,
-    /// Strategy for input selection
+    /// Strategy for selecting inputs for the fee payment
+    pub fee_input_selection: UtxoInputSelection,
+    /// Strategy for selecting inputs for the transfer amount
     pub input_selection: UtxoInputSelection,
utilities/traffic-sim/src/sim.rs (2)

268-412: Consider refactoring for maintainability.

This function is 144 lines long and handles multiple concerns (checking balances, creating test coins, creating transfer statements, building transactions, submitting, and waiting for results). Consider extracting smaller helper methods for each major step to improve readability and testability.


286-286: Consider parameterizing the fund amount.

The fund amount is hardcoded to 10_000_000_000. Consider making this a parameter to the function for flexibility in different testing scenarios.

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

182-186: New create_lock API: useful, but consider RAII guard to avoid leaked locks on early returns.

Expose a small drop-guard (e.g., WalletLockDropGuard) that auto-releases if not finalized, and return it from create_lock to make flows exception-safe.

-    pub fn create_lock(&self) -> Result<WalletLockId, StealthOutputsApiError> {
-        let lock_id = self.store.with_write_tx(|tx| tx.locks_create())?;
-        Ok(lock_id)
-    }
+    pub fn create_lock(&self) -> Result<WalletLockDropGuard<'_, TStore>, StealthOutputsApiError> {
+        let lock_id = self.store.with_write_tx(|tx| tx.locks_create())?;
+        Ok(WalletLockDropGuard::new(self.store, lock_id))
+    }

Note: adjust call sites and provide finalize() to consume the guard.

applications/tari_indexer/src/rest_api/handlers/utxos.rs (2)

100-113: fetch_utxos migration looks correct; keep limit guard consistent with GET list.

The 1000 cap mirrors other handlers; consider extracting a shared const to avoid drift.

-    if req.tag_and_nonce_pairs.len() > 1000 {
+    const MAX_UTXO_BATCH: usize = 1000;
+    if req.tag_and_nonce_pairs.len() > MAX_UTXO_BATCH {
         return Err(ErrorResponse::bad_request("cannot query more than 1000 UTXOs"));
     }

115-132: New list_utxos endpoint: solid; unify limits via a shared constant.

Add a MAX_UTXO_PAGE_SIZE const and reuse across stream/fetch/list to prevent divergence.

-#[utoipa::path(get, path = "/utxos", description = "List full UTXO data")]
+const MAX_UTXO_PAGE_SIZE: u32 = 1000;
+#[utoipa::path(get, path = "/utxos", description = "List full UTXO data")]
 pub async fn list_utxos(
     Extension(context): Extension<HandlerContext>,
     Query(req): Query<ListUtxosRequest>,
 ) -> HandlerResult<Json<ListUtxosResponse>> {
-    if req.limit == 0 {
+    if req.limit == 0 {
         return Err(ErrorResponse::bad_request("limit must be greater than 0"));
     }
-    if req.limit > 1000 {
+    if req.limit > MAX_UTXO_PAGE_SIZE {
         return Err(ErrorResponse::bad_request("cannot query more than 1000 UTXOs"));
     }

Please confirm the store layer enforces resource scoping with from_id to prevent cross-resource leakage when a malformed from_id is provided.

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

128-135: Improve owner_key_id error message with account context.

The suggestion is valid and beneficial. The owner_key_id() method returns Option<KeyId>, which can be None even for valid accounts. While the account existence is already guarded at lines 111–114, a panic with the account name will aid debugging. Since account_name is available as a function parameter (line 106), the suggested refactor using unwrap_or_else() with context is an improvement over the generic error message.

- seal_signer: BranchAndKeyId::new(KeyBranch::Account, account.owner_key_id().expect("no owner key id")),
+ seal_signer: BranchAndKeyId::new(
+     KeyBranch::Account,
+     account
+         .owner_key_id()
+         .unwrap_or_else(|| panic!("Account {account_name} has no owner key id; cannot seal-sign")),
+ ),
utilities/generate_ristretto_value_lookup/src/main.rs (3)

115-117: Scratch-pad preallocation is ineffective

vec![Some(Vec::with_capacity(...)); num_threads] clones an empty Vec; clones lose the reserved capacity. Build each entry explicitly.

-    let mut scratch_pad = vec![Some(Vec::with_capacity(CHUNK_SIZE)); num_threads];
+    let mut scratch_pad: Vec<Option<Vec<[u8; 32]>>> =
+        (0..num_threads).map(|_| Some(Vec::with_capacity(CHUNK_SIZE))).collect();

148-153: Buffered writes for throughput

Writing 32 bytes per key is syscall-heavy. Wrap the file in a BufWriter with a large buffer.

Within main (near file creation):

-use std::{
-    fs,
-    io,
-    io::{stdout, Write},
-    time::{Duration, Instant},
-};
+use std::{
+    fs,
+    io,
+    io::{stdout, Write, BufWriter},
+    time::{Duration, Instant},
+};
...
-    let writer = fs::File::create(&dest_file)?;
+    let writer = BufWriter::with_capacity(1 << 20, fs::File::create(&dest_file)?); // 1 MiB buffer

No change needed to write_output_async signature since BufWriter implements Write.


18-18: Remove unused import

ValueLookupTable isn’t used.

-use tari_ootle_wallet_crypto::ValueLookupTable;
clients/tari_indexer_client/src/rest_api_client.rs (1)

170-176: get_utxos/list_utxos methods — LGTM

POST to utxos/fetch and GET to utxos are correct and consistent with handlers. Consider surfacing a helper to clamp client-side limit to 1000 to fail fast, but server validates already.

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

11-14: Guard owns the store; disarm drops it — add must_use and a way to recover the store.

Owning TStore means callers lose it once passed in; disarm() also discards it. Add #[must_use] to the guard and expose into_inner() so callers can reclaim the store when disarming.

- pub struct WalletLockDropGuard<TStore: WriteableWalletStore> {
+ #[must_use]
+ pub struct WalletLockDropGuard<TStore: WriteableWalletStore> {
@@
 impl<TStore> WalletLockDropGuard<TStore>
 where TStore: WriteableWalletStore
 {
@@
     pub fn disarm(mut self) {
         self.store = None;
     }
+
+    /// Consume the guard and recover the owned store without unlocking.
+    pub fn into_inner(mut self) -> Option<TStore> {
+        self.store.take()
+    }
 }

Also applies to: 30-33

crates/wallet/sdk/src/apis/stealth_transfer/api.rs (1)

135-141: Error variant naming consistency (optional).

RevealedOnly returns InsufficientFunds with revealed-specific details, while other branches sometimes use InsufficientRevealedFunds. Consider standardizing the variant for clearer UX.

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

131-141: Use available_revealed_funds to avoid locking already-reserved funds.

PreferRevealed uses src_vault.revealed_balance rather than the computed available_revealed_funds; this can over-request and fail later. Use the available figure.

-            UtxoInputSelection::PreferRevealed => {
-                let revealed_to_spend = cmp::min(src_vault.revealed_balance, spend_amount);
+            UtxoInputSelection::PreferRevealed => {
+                let revealed_to_spend = cmp::min(available_revealed_funds, spend_amount);
applications/tari_walletd/src/handlers/accounts.rs (3)

1083-1088: Avoid magic number for batch size

Replace hard-coded 16 with a named constant for clarity and central control.

Apply:

-    if req.requests.len() > 16 {
+    const MAX_STEALTH_STATEMENT_REQUESTS: usize = 16;
+    if req.requests.len() > MAX_STEALTH_STATEMENT_REQUESTS {

If you prefer, hoist the constant near the top of the file.


1168-1179: Deterministic ordering for signing_keys

HashSet iteration order is nondeterministic. For stable client UX and reproducible responses, preserve insertion order.

Option A (preferred): use IndexSet.

-    let mut required_signers = HashSet::new();
+    use indexmap::IndexSet;
+    let mut required_signers = IndexSet::new();
...
-    Ok(AccountsCreateStealthTransferStatementResponse {
-        statements,
-        lock_id,
-        signing_keys: required_signers.into_iter().collect(),
-    })
+    Ok(AccountsCreateStealthTransferStatementResponse {
+        statements,
+        lock_id,
+        signing_keys: required_signers.into_iter().collect(), // now deterministic
+    })

Option B: collect to Vec and sort by (branch, key_id).


1094-1096: Avoid shadowing req inside the loop

Shadowing the outer request parameter with for req in req.requests harms readability.

Rename the loop variable, e.g.:

-    for req in req.requests {
+    for stm_req in req.requests {
clients/wallet_daemon_client/src/types.rs (1)

118-134: TransactionSubmitRequest surface looks correct

seal_signer/other_signers/lock_ids fields reflect server changes. Consider TS hint for lock_ids if WalletLockId is not already mapped to number[] in TS.

If needed, annotate:

 pub struct TransactionSubmitRequest {
     pub transaction: UnsignedTransaction,
     pub seal_signer: BranchAndKeyId,
     pub other_signers: Vec<BranchAndKeyId>,
@@
-    pub lock_ids: Vec<WalletLockId>,
+    #[cfg_attr(feature = "ts", ts(type = "Array<number>"))]
+    pub lock_ids: Vec<WalletLockId>,
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d7c8dd and 7610f95.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (87)
  • Cargo.toml (2 hunks)
  • applications/tari_indexer/src/rest_api/handlers/utxos.rs (3 hunks)
  • applications/tari_indexer/src/rest_api/server.rs (2 hunks)
  • applications/tari_indexer/src/storage_sqlite/reader.rs (2 hunks)
  • applications/tari_indexer/src/store.rs (1 hunks)
  • applications/tari_indexer/src/substate_manager.rs (1 hunks)
  • applications/tari_validator_node/src/cli.rs (2 hunks)
  • applications/tari_wallet_cli/src/command/transaction.rs (6 hunks)
  • applications/tari_walletd/src/handlers/accounts.rs (7 hunks)
  • applications/tari_walletd/src/handlers/helpers.rs (1 hunks)
  • applications/tari_walletd/src/handlers/stealth_utxos.rs (5 hunks)
  • applications/tari_walletd/src/handlers/transaction.rs (9 hunks)
  • applications/tari_walletd/src/jrpc_server.rs (1 hunks)
  • applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx (3 hunks)
  • applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx (2 hunks)
  • applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx (3 hunks)
  • applications/tari_walletd/web_ui/src/routes/Transactions/Inputs.tsx (2 hunks)
  • applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (3 hunks)
  • applications/tari_walletd/web_ui/src/utils/json_rpc.ts (2 hunks)
  • bindings/package.json (1 hunks)
  • bindings/src/index.ts (1 hunks)
  • bindings/src/tari-indexer-client.ts (2 hunks)
  • bindings/src/types/ConfidentialTransferInputSelection.ts (0 hunks)
  • bindings/src/types/StealthTransferStatement.ts (1 hunks)
  • bindings/src/types/UtxoInputSelection.ts (1 hunks)
  • bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1 hunks)
  • bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1 hunks)
  • bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1 hunks)
  • bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/ConfidentialTransferRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/InputSelection.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunRequest.ts (0 hunks)
  • bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/TransferOutput.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1 hunks)
  • bindings/src/wallet-daemon-client.ts (4 hunks)
  • clients/javascript/indexer_client/package.json (1 hunks)
  • clients/javascript/wallet_daemon_client/package.json (1 hunks)
  • clients/javascript/wallet_daemon_client/src/index.ts (1 hunks)
  • clients/tari_indexer_client/src/rest_api_client.rs (2 hunks)
  • clients/tari_indexer_client/src/types.rs (1 hunks)
  • clients/wallet_daemon_client/src/component_address.rs (1 hunks)
  • clients/wallet_daemon_client/src/lib.rs (3 hunks)
  • clients/wallet_daemon_client/src/types.rs (7 hunks)
  • crates/engine_types/src/crypto/elgamal.rs (3 hunks)
  • crates/engine_types/src/stealth/transfer.rs (5 hunks)
  • crates/epoch_oracles/src/base_layer/mod.rs (1 hunks)
  • crates/epoch_oracles/src/configured/real_time_ticker.rs (4 hunks)
  • crates/p2p/src/conversions/transaction.rs (2 hunks)
  • crates/template_builtin/templates/faucet/src/lib.rs (1 hunks)
  • crates/template_lib/src/models/stealth.rs (2 hunks)
  • crates/template_test_tooling/src/support/stealth.rs (1 hunks)
  • crates/transaction/src/v1/unsigned.rs (2 hunks)
  • crates/wallet/crypto/src/stealth.rs (3 hunks)
  • crates/wallet/crypto/src/value_lookup/header.rs (1 hunks)
  • crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (3 hunks)
  • crates/wallet/crypto/src/value_lookup/mod.rs (1 hunks)
  • crates/wallet/crypto/tests/stealth_transfer_statement.rs (8 hunks)
  • crates/wallet/sdk/src/apis/confidential_outputs.rs (0 hunks)
  • crates/wallet/sdk/src/apis/confidential_transfer.rs (13 hunks)
  • crates/wallet/sdk/src/apis/stealth_crypto.rs (1 hunks)
  • crates/wallet/sdk/src/apis/stealth_outputs.rs (5 hunks)
  • crates/wallet/sdk/src/apis/stealth_transfer/api.rs (9 hunks)
  • crates/wallet/sdk/src/apis/stealth_transfer/error.rs (2 hunks)
  • crates/wallet/sdk/src/apis/stealth_transfer/params.rs (2 hunks)
  • crates/wallet/sdk/src/apis/substate.rs (1 hunks)
  • crates/wallet/sdk/src/models/account.rs (1 hunks)
  • crates/wallet/sdk/src/models/key.rs (1 hunks)
  • crates/wallet/sdk/src/models/lock_guard.rs (1 hunks)
  • crates/wallet/sdk/src/models/mod.rs (2 hunks)
  • crates/wallet/sdk/src/models/wallet_transaction.rs (1 hunks)
  • crates/wallet/sdk/src/sdk.rs (1 hunks)
  • crates/wallet/sdk_services/src/indexer_rest_api.rs (2 hunks)
  • integration_tests/src/wallet_daemon_client.rs (10 hunks)
  • integration_tests/tests/steps/wallet_daemon.rs (2 hunks)
  • utilities/generate_ristretto_value_lookup/Cargo.toml (1 hunks)
  • utilities/generate_ristretto_value_lookup/src/cli.rs (1 hunks)
  • utilities/generate_ristretto_value_lookup/src/main.rs (1 hunks)
  • utilities/traffic-sim/Cargo.toml (1 hunks)
  • utilities/traffic-sim/src/main.rs (1 hunks)
  • utilities/traffic-sim/src/sim.rs (1 hunks)
💤 Files with no reviewable changes (3)
  • bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunRequest.ts
  • crates/wallet/sdk/src/apis/confidential_outputs.rs
  • bindings/src/types/ConfidentialTransferInputSelection.ts
🧰 Additional context used
🧬 Code graph analysis (56)
crates/wallet/sdk/src/models/wallet_transaction.rs (1)
bindings/src/types/TransactionStatus.ts (1)
  • TransactionStatus (3-11)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (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/web_ui/src/utils/json_rpc.ts (3)
clients/javascript/wallet_daemon_client/src/index.ts (1)
  • submitTransactionDryRun (228-230)
bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1)
  • TransactionSubmitRequest (5-21)
bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunResponse.ts (1)
  • TransactionSubmitDryRunResponse (5-5)
clients/wallet_daemon_client/src/component_address.rs (1)
bindings/src/types/wallet-daemon-client/ComponentAddressOrName.ts (1)
  • ComponentAddressOrName (4-4)
crates/wallet/crypto/src/stealth.rs (2)
crates/engine_types/src/crypto/messages.rs (1)
  • stealth_statement_metadata64 (74-79)
crates/wallet/crypto/src/balance_proof.rs (1)
  • generate_stealth_balance_proof_signature (38-55)
bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (4)
bindings/src/types/wallet-daemon-client/ComponentAddressOrName.ts (1)
  • ComponentAddressOrName (4-4)
bindings/src/types/ResourceAddress.ts (1)
  • ResourceAddress (6-6)
bindings/src/types/wallet-daemon-client/InputSelection.ts (1)
  • InputSelection (5-5)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
  • TransferOutput (6-24)
crates/wallet/sdk/src/models/account.rs (3)
crates/wallet/sdk/src/models/key.rs (1)
  • new (294-296)
bindings/src/types/Account.ts (1)
  • Account (6-14)
bindings/src/types/OotleAddress.ts (1)
  • OotleAddress (3-3)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
bindings/src/types/UtxoId.ts (1)
  • UtxoId (3-3)
crates/template_lib/src/models/stealth.rs (4)
crates/state_store_rocksdb/src/codecs/small_bytes.rs (1)
  • empty (19-21)
bindings/src/types/StealthTransferStatement.ts (1)
  • StealthTransferStatement (5-13)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
bindings/src/types/StealthInputsStatement.ts (1)
  • StealthInputsStatement (9-22)
bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (2)
bindings/src/types/UtxoId.ts (1)
  • UtxoId (3-3)
bindings/src/types/Utxo.ts (1)
  • Utxo (4-4)
bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (2)
bindings/src/types/UtxoId.ts (1)
  • UtxoId (3-3)
bindings/src/types/Utxo.ts (1)
  • Utxo (4-4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1)
  • TransferStatementRequest (7-12)
applications/tari_indexer/src/store.rs (1)
applications/tari_indexer/src/storage_sqlite/reader.rs (1)
  • utxos_list (563-606)
applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx (2)
crates/engine_types/src/resource.rs (1)
  • divisibility (211-213)
applications/tari_walletd/web_ui/src/utils/helpers.tsx (1)
  • bigintToDecimalString (233-253)
applications/tari_walletd/src/handlers/helpers.rs (1)
crates/wallet/sdk/src/sdk.rs (1)
  • accounts_api (228-235)
crates/wallet/sdk/src/models/key.rs (3)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-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)
applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (2)
bindings/src/types/StealthTransferStatement.ts (1)
  • StealthTransferStatement (5-13)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (2)
bindings/src/types/OotleAddress.ts (1)
  • OotleAddress (3-3)
bindings/src/types/Amount.ts (1)
  • Amount (12-12)
applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (2)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
bindings/src/helpers/consts.ts (1)
  • XTR (10-10)
bindings/src/types/wallet-daemon-client/ConfidentialTransferRequest.ts (2)
bindings/src/types/Amount.ts (1)
  • Amount (12-12)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
applications/tari_wallet_cli/src/command/transaction.rs (6)
integration_tests/src/wallet_daemon_client.rs (1)
  • confidential_transfer (877-920)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
crates/wallet/sdk/src/models/account.rs (2)
  • owner_key_id (33-35)
  • owner_key_id (95-97)
crates/wallet/sdk/src/models/key.rs (1)
  • for_account (298-303)
bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1)
  • TransactionSubmitRequest (5-21)
applications/tari_walletd/src/handlers/stealth_utxos.rs (5)
applications/tari_walletd/src/handlers/helpers.rs (1)
  • invalid_params (162-173)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1)
  • StealthUtxosDecryptValueRequest (5-11)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
  • StealthUtxosDecryptValueResponse (4-4)
crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (3)
  • lookup (90-101)
  • load (26-35)
  • range (82-84)
crates/wallet/crypto/src/value_lookup/mod.rs (1)
  • lookup (19-21)
utilities/generate_ristretto_value_lookup/src/main.rs (3)
utilities/generate_ristretto_value_lookup/src/cli.rs (1)
  • init (31-33)
crates/engine_types/src/crypto/elgamal.rs (3)
  • lookup (293-298)
  • from (160-162)
  • from (166-171)
crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (2)
  • lookup (90-101)
  • load (26-35)
bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (2)
bindings/src/types/ResourceAddress.ts (1)
  • ResourceAddress (6-6)
bindings/src/types/UtxoId.ts (1)
  • UtxoId (3-3)
applications/tari_walletd/src/jrpc_server.rs (2)
applications/tari_swarm_daemon/src/webserver/server.rs (1)
  • call_handler (154-178)
applications/tari_walletd/src/handlers/accounts.rs (2)
  • accounts (258-267)
  • handle_create_stealth_transfer_statement (1069-1180)
utilities/traffic-sim/src/sim.rs (5)
clients/tari_indexer_client/src/rest_api_client.rs (1)
  • connect (53-66)
clients/wallet_daemon_client/src/lib.rs (2)
  • connect (149-164)
  • endpoint (166-168)
clients/wallet_daemon_client/src/component_address.rs (5)
  • name (21-26)
  • component_address (28-33)
  • from (58-60)
  • from (64-66)
  • from (69-71)
crates/wallet/sdk/src/models/account.rs (7)
  • name (41-43)
  • name (87-89)
  • address (83-85)
  • new (71-73)
  • account (75-77)
  • component_address (25-27)
  • component_address (79-81)
crates/engine_types/src/resource.rs (2)
  • divisibility (211-213)
  • token_symbol (207-209)
crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (1)
crates/wallet/crypto/src/value_lookup/header.rs (1)
  • is_in_range (43-45)
bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (2)
bindings/src/types/UnsignedTransaction.ts (1)
  • UnsignedTransaction (4-4)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
applications/tari_indexer/src/rest_api/server.rs (4)
applications/tari_indexer/src/storage_sqlite/reader.rs (2)
  • utxos (505-509)
  • utxos (635-640)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (1)
  • list_utxos (116-132)
applications/tari_indexer/src/substate_manager.rs (1)
  • list_utxos (143-153)
clients/tari_indexer_client/src/rest_api_client.rs (1)
  • list_utxos (174-176)
crates/wallet/sdk/src/apis/stealth_transfer/params.rs (2)
integration_tests/src/wallet_daemon_client.rs (1)
  • confidential_transfer (877-920)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
clients/javascript/wallet_daemon_client/src/index.ts (2)
bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1)
  • TransactionSubmitRequest (5-21)
bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunResponse.ts (1)
  • TransactionSubmitDryRunResponse (5-5)
applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx (1)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (7)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
  • GetUtxosRequest (6-9)
bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1)
  • GetUtxosResponse (5-5)
bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1)
  • ListUtxosRequest (5-5)
bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1)
  • ListUtxosResponse (5-5)
applications/tari_indexer/src/storage_sqlite/reader.rs (2)
  • utxos (505-509)
  • utxos (635-640)
applications/tari_indexer/src/substate_manager.rs (1)
  • list_utxos (143-153)
clients/tari_indexer_client/src/rest_api_client.rs (1)
  • list_utxos (174-176)
crates/engine_types/src/stealth/transfer.rs (1)
crates/engine_types/src/crypto/helpers.rs (1)
  • try_decode_to_signature (91-93)
applications/tari_indexer/src/substate_manager.rs (2)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (1)
  • list_utxos (116-132)
clients/tari_indexer_client/src/rest_api_client.rs (1)
  • list_utxos (174-176)
bindings/src/types/wallet-daemon-client/InputSelection.ts (2)
bindings/src/types/Amount.ts (1)
  • Amount (12-12)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
crates/wallet/crypto/tests/stealth_transfer_statement.rs (2)
crates/wallet/crypto/src/stealth.rs (2)
  • output_statements (123-153)
  • create_outputs_statement (119-162)
crates/wallet/crypto/src/balance_proof.rs (1)
  • generate_stealth_balance_proof_signature (38-55)
clients/wallet_daemon_client/src/lib.rs (4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
  • AccountsCreateStealthTransferStatementRequest (4-4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
  • AccountsCreateStealthTransferStatementResponse (5-9)
clients/validator_node_client/src/lib.rs (1)
  • endpoint (58-60)
bindings/src/types/wallet-daemon-client/ProofsGenerateRequest.ts (1)
  • ProofsGenerateRequest (8-15)
integration_tests/tests/steps/wallet_daemon.rs (3)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/models/key.rs (1)
  • new (294-296)
bindings/src/types/Account.ts (1)
  • Account (6-14)
applications/tari_validator_node/src/cli.rs (1)
applications/tari_app_utilities/src/configuration.rs (1)
  • convert_l1_network_to_network (31-40)
applications/tari_walletd/src/handlers/accounts.rs (8)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
  • TransferOutput (6-24)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
  • AccountsCreateStealthTransferStatementRequest (4-4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
  • AccountsCreateStealthTransferStatementResponse (5-9)
applications/tari_walletd/src/handlers/helpers.rs (3)
  • get_account (113-124)
  • not_found (183-190)
  • invalid_params (162-173)
crates/wallet/sdk/src/apis/stealth_outputs.rs (2)
  • new (69-81)
  • outputs (692-692)
crates/wallet/sdk/src/models/key.rs (1)
  • new (294-296)
crates/wallet/sdk/src/models/lock_guard.rs (1)
  • lock_id (26-28)
clients/tari_indexer_client/src/rest_api_client.rs (6)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
  • GetUtxosRequest (6-9)
bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1)
  • GetUtxosResponse (5-5)
bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1)
  • ListUtxosRequest (5-5)
bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1)
  • ListUtxosResponse (5-5)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (1)
  • list_utxos (116-132)
applications/tari_indexer/src/substate_manager.rs (1)
  • list_utxos (143-153)
crates/wallet/sdk/src/apis/stealth_transfer/api.rs (2)
integration_tests/src/wallet_daemon_client.rs (1)
  • confidential_transfer (877-920)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
crates/transaction/src/v1/unsigned.rs (4)
bindings/src/helpers/consts.ts (1)
  • XTR (10-10)
bindings/src/types/UtxoAddress.ts (1)
  • UtxoAddress (4-4)
bindings/src/types/Instruction.ts (1)
  • Instruction (15-42)
bindings/src/types/ResourceAddressRef.ts (1)
  • ResourceAddressRef (5-5)
clients/wallet_daemon_client/src/types.rs (10)
integration_tests/src/wallet_daemon_client.rs (1)
  • confidential_transfer (877-920)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
  • TransferOutput (6-24)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
  • AccountsCreateStealthTransferStatementRequest (4-4)
bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1)
  • TransferStatementRequest (7-12)
bindings/src/types/wallet-daemon-client/InputSelection.ts (1)
  • InputSelection (5-5)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
  • AccountsCreateStealthTransferStatementResponse (5-9)
bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts (1)
  • StealthTransferRequest (8-17)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
  • StealthUtxosDecryptValueResponse (4-4)
utilities/traffic-sim/src/main.rs (2)
utilities/traffic-sim/src/sim.rs (1)
  • wallets (113-115)
clients/wallet_daemon_client/src/lib.rs (1)
  • endpoint (166-168)
applications/tari_indexer/src/storage_sqlite/reader.rs (1)
applications/tari_indexer/src/store.rs (1)
  • utxos_list (153-158)
integration_tests/src/wallet_daemon_client.rs (7)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
bindings/src/types/Account.ts (1)
  • Account (6-14)
bindings/src/types/AccountWithAddress.ts (1)
  • AccountWithAddress (5-5)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/models/account.rs (3)
  • owner_key_id (33-35)
  • owner_key_id (95-97)
  • account (75-77)
crates/wallet/sdk/src/models/key.rs (1)
  • for_account (298-303)
crates/wallet/sdk/src/apis/stealth_transfer/error.rs (2)
bindings/src/types/ResourceAddress.ts (1)
  • ResourceAddress (6-6)
bindings/src/types/Amount.ts (1)
  • Amount (12-12)
clients/tari_indexer_client/src/types.rs (9)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
  • GetUtxosRequest (6-9)
bindings/src/types/UtxoTag.ts (1)
  • UtxoTag (8-8)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
bindings/src/types/ResourceAddress.ts (1)
  • ResourceAddress (6-6)
bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1)
  • GetUtxosResponse (5-5)
bindings/src/types/UtxoId.ts (1)
  • UtxoId (3-3)
bindings/src/types/Utxo.ts (1)
  • Utxo (4-4)
bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1)
  • ListUtxosRequest (5-5)
bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1)
  • ListUtxosResponse (5-5)
crates/wallet/sdk/src/apis/confidential_transfer.rs (3)
crates/wallet/sdk/src/sdk.rs (2)
  • network (189-191)
  • transaction_api (220-222)
crates/wallet/sdk/src/apis/transaction.rs (1)
  • new (40-45)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
crates/p2p/src/conversions/transaction.rs (1)
crates/template_lib_types/src/crypto/scalar.rs (1)
  • from_bytes (32-43)
applications/tari_walletd/src/handlers/transaction.rs (5)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/models/account.rs (2)
  • owner_key_id (33-35)
  • owner_key_id (95-97)
applications/tari_walletd/src/handlers/helpers.rs (1)
  • invalid_params (162-173)
crates/wallet/sdk/src/models/key.rs (1)
  • for_account (298-303)
crates/wallet/sdk_services/src/indexer_rest_api.rs (1)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
  • GetUtxosRequest (6-9)
crates/template_test_tooling/src/support/stealth.rs (3)
crates/template_test_tooling/src/support/confidential.rs (1)
  • inputs (170-176)
crates/template_lib/src/models/stealth.rs (1)
  • revealed_input_amount (113-115)
crates/wallet/sdk/src/apis/stealth_outputs.rs (1)
  • outputs (692-692)
⏰ 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). (6)
  • GitHub Check: test
  • GitHub Check: check stable
  • GitHub Check: check nightly
  • GitHub Check: clippy
  • GitHub Check: machete
  • GitHub Check: fmt

Comment thread applications/tari_indexer/src/storage_sqlite/reader.rs
Comment on lines +27 to +34
use tari_common::{
configuration::{ConfigOverrideProvider, Network as L1Network},
ConfigPath,
};
use tari_ootle_app_utilities::{
configuration::convert_l1_network_to_network,
p2p_config::{PeerSeedsConfig, ReachabilityMode},
};

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

🧩 Analysis chain

Verify if ConfigPath import is necessary.

The ConfigPath import on line 29 doesn't appear to be used anywhere in this file. If it's not needed, consider removing it to keep imports clean.

Run the following script to verify if ConfigPath is used in this file:


🏁 Script executed:

#!/bin/bash
# Description: Check if ConfigPath is used in the cli.rs file

# Search for ConfigPath usage excluding the import line
rg -n 'ConfigPath' applications/tari_validator_node/src/cli.rs | grep -v 'use.*ConfigPath'

Length of output: 18


Remove unused ConfigPath import from line 29.

The verification confirms that ConfigPath is imported on line 29 but is never used anywhere in this file. Remove it to keep imports clean.

🤖 Prompt for AI Agents
In applications/tari_validator_node/src/cli.rs around lines 27 to 34, the import
list includes an unused ConfigPath (line 29); remove ConfigPath from the
tari_common import group so the file no longer imports that unused symbol and
keep imports tidy.

Comment thread applications/tari_walletd/src/handlers/accounts.rs
Comment thread applications/tari_walletd/src/handlers/accounts.rs
Comment thread applications/tari_walletd/src/handlers/accounts.rs
Comment thread crates/transaction/src/v1/unsigned.rs
Comment thread utilities/generate_ristretto_value_lookup/src/main.rs
Comment thread utilities/generate_ristretto_value_lookup/src/main.rs
Comment thread utilities/traffic-sim/src/sim.rs Outdated
Comment thread utilities/traffic-sim/src/sim.rs Outdated

@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

♻️ Duplicate comments (10)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1)

9-10: Breaking change: maximum_expected_value now required, but call sites still pass null.

The past review correctly identified that removing nullability from maximum_expected_value while keeping minimum_expected_value nullable creates both a type contract violation (DecryptUtxoBalance.tsx line 48 still passes null) and an unexplained asymmetry with similar types like ConfidentialViewVaultBalanceRequest.

Since this is a generated file, the fix must be applied to the Rust source. Given the feat!: breaking change marker in the PR title, ensure:

  1. All downstream call sites are updated to provide a concrete value
  2. The asymmetry between min/max nullability is intentional and documented
  3. A migration guide addresses this breaking API change

The verification script from the past review remains valid for confirming all call sites have been updated.

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

1194-1194: Field renamed from balances to values - frontend update required.

This field rename requires corresponding updates in the TypeScript UI code. As noted in the previous review, DecryptUtxoBalance.tsx still accesses .balances instead of .values.

applications/tari_indexer/src/storage_sqlite/reader.rs (1)

563-606: Burnt UTXOs should also be filtered in utxos_list query.

As noted in the previous review, Line 574 currently only filters is_spent = false but should also exclude burnt UTXOs (is_burnt = false) for consistency with other unspent UTXO queries in this file (e.g., utxos_get_unspent_by_public_nonce_and_tag at lines 638-639).

Apply this diff:

         let mut query = utxos::table
             .filter(utxos::resource_address.eq(resource_address.to_string()))
             .filter(utxos::is_spent.eq(false))
+            .filter(utxos::is_burnt.eq(false))
             .into_boxed();
applications/tari_validator_node/src/cli.rs (1)

27-30: Remove unused ConfigPath import.

ConfigPath isn’t referenced in this file. Drop it to keep imports clean.

-use tari_common::{
-    configuration::{ConfigOverrideProvider, Network as L1Network},
-    ConfigPath,
-};
+use tari_common::configuration::{ConfigOverrideProvider, Network as L1Network};
utilities/generate_ristretto_value_lookup/src/main.rs (2)

73-77: Compile risk: tokio runtime metrics require tokio_unstable; use a stable fallback.

Replace metrics-based worker count with std::thread::available_parallelism() and ensure at least 1.

Apply:

-    let jobs = cli
-        .jobs
-        .unwrap_or_else(|| tokio::runtime::Handle::current().metrics().num_workers());
+    let jobs = cli.jobs.unwrap_or_else(|| {
+        std::thread::available_parallelism()
+            .map(|n| n.get())
+            .unwrap_or(1)
+    });

168-183: Progress denominator off by one in printed total.

Total values = max - min + 1, but the print uses max - min.

Apply:

-                "{:.1}% ETA: {}. {}/{} values generated in {}",
+                "{:.1}% ETA: {}. {}/{} values generated in {}",
                 (completed as f64 / (max - min + 1) as f64) * 100.0,
                 humantime::format_duration(est_time),
                 completed,
-                max - min,
+                max - min + 1,
                 humantime::format_duration(Duration::from_secs(elapsed.as_secs()))
applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (1)

161-163: Use strict equality for XTR check

Change == to === to avoid type coercion surprises.

-          // For simplicity, we'll use prefer revealed for fees whenever a non-XTR stealth transfer is made
-          fee_input_selection: params.resource_address == XTR ? params.input_selection : "PreferRevealed",
+          // For simplicity, we'll use PreferRevealed for fees whenever a non‑XTR stealth transfer is made
+          fee_input_selection: params.resource_address === XTR ? params.input_selection : "PreferRevealed",
#!/bin/bash
# Verify no other '== XTR' checks remain
rg -nP --type=ts -C2 '\b==\s*XTR\b'
applications/tari_walletd/src/handlers/accounts.rs (3)

1103-1104: Validate resource is stealth before proceeding

Still missing the stealth-type guard. Generate a clear error early to avoid confusing decode failures later.

Apply this diff:

         let resource = sdk.substate_api().fetch_resource(req.resource_address).await?;
+        if !resource.resource_type().is_stealth() {
+            return Err(invalid_params(
+                "resource_address",
+                Some(format!(
+                    "Resource is not a stealth resource (type: {})",
+                    resource.resource_type()
+                )),
+            ));
+        }

1121-1127: Must sign with account key when revealed funds come FromBucket as well

Condition still omits revealed funds provided via FromBucket.

Apply this diff:

-        let must_sign_with_account_key = inputs.as_ref().is_some_and(|i| i.revealed.is_positive());
+        let must_sign_with_account_key =
+            inputs.as_ref().is_some_and(|i| i.revealed.is_positive()) ||
+            req.input_selection.as_from_bucket().is_some_and(|a| a.is_positive());

1152-1163: Avoid checked_add_positive with zero addend for input_revealed_amount

Zero addend causes a spurious error; compute conditionally.

Apply this diff:

-                input_revealed_amount: req
-                    .input_selection
-                    .as_from_bucket()
-                    .unwrap_or(Amount::zero())
-                    .checked_add_positive(inputs.as_ref().map(|i| i.revealed).unwrap_or(Amount::zero()))
-                    .ok_or_else(|| {
-                        invalid_params(
-                            "input_revealed_amount",
-                            Some("input revealed amount overflowed or was negative"),
-                        )
-                    })?,
+                input_revealed_amount: {
+                    let mut total = req.input_selection.as_from_bucket().unwrap_or(Amount::zero());
+                    if let Some(i) = inputs.as_ref() {
+                        if i.revealed.is_positive() {
+                            total = total.checked_add_positive(i.revealed).ok_or_else(|| {
+                                invalid_params(
+                                    "input_revealed_amount",
+                                    Some("input revealed amount overflowed"),
+                                )
+                            })?;
+                        }
+                    }
+                    total
+                },
🧹 Nitpick comments (15)
crates/wallet/sdk/src/models/wallet_transaction.rs (1)

51-57: Add documentation for these public helper methods.

These methods are part of the public API but lack doc comments. Consider adding documentation to clarify the distinction between "any acceptance" (including partial fee-only acceptance) and full acceptance.

Apply this diff to add documentation:

+    /// Returns `true` if the transaction has been accepted in any form,
+    /// including full acceptance or fee-only acceptance.
     pub fn is_any_accept(&self) -> bool {
         matches!(self, TransactionStatus::Accepted | TransactionStatus::OnlyFeeAccepted)
     }

+    /// Returns `true` only if the transaction has been fully accepted.
     pub fn is_accepted(&self) -> bool {
         matches!(self, TransactionStatus::Accepted)
     }
crates/engine_types/src/crypto/elgamal.rs (1)

232-232: Consider debug level for balance discovery logs.

The info log at line 232 will fire for each balance found during brute force decryption. If this method is frequently called with large batches, log verbosity could become substantial.

Consider using debug! instead of info! unless operational visibility at the info level is specifically required. Additionally, verify that logging actual balance values is acceptable from a privacy/security perspective in production environments.

Apply this diff to reduce log verbosity:

-                info!(target: LOG_TARGET, "Found encrypted balance: {}", v);
+                debug!(target: LOG_TARGET, "Found encrypted balance: {}", v);
applications/tari_wallet_cli/src/command/transaction.rs (1)

253-255: Owner key derivation is correct.

The error handling properly guards against missing owner key IDs. However, this exact pattern is duplicated in handle_submit_manifest (lines 325-327).

Consider extracting a helper function to reduce duplication:

async fn get_fee_account_owner_key_id(
    client: &mut WalletDaemonClient,
    fee_account_arg: Option<ComponentAddressOrName>,
) -> Result<KeyId, anyhow::Error> {
    let fee_account = if let Some(fee_account_name) = fee_account_arg {
        client.accounts_get(fee_account_name).await?.account
    } else {
        client.accounts_get_default().await?.account
    };
    
    fee_account
        .owner_key_id
        .ok_or_else(|| anyhow!("Fee account does not have an owner key ID"))
}

Then use it in both functions:

let owner_key_id = get_fee_account_owner_key_id(client, common.fee_account.clone()).await?;
applications/tari_walletd/src/handlers/stealth_utxos.rs (1)

181-181: Consider renaming for consistency.

The variable is named balances while the response field is values (line 186). Consider renaming the variable to values for consistency with the public API.

-    let balances = handle.await??;
+    let values = handle.await??;

Then update line 186:

-        values: proofs.into_keys().zip(balances).collect(),
+        values: proofs.into_keys().zip(values).collect(),
applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx (1)

45-45: Good change: Dynamic divisibility with safe fallback.

The derivation correctly uses the resource's divisibility property with a safe fallback to 6 when balance data is unavailable. This enables proper formatting for resources with different decimal places.

Optionally, consider adding a comment explaining why 6 is the default (e.g., XTR's divisibility):

+  // Default to 6 (XTR divisibility) when resource balance is unavailable
   const divisibility = resourceBalance ? resourceBalance.divisibility : 6;
crates/engine_types/src/stealth/transfer.rs (1)

59-68: Consider refining the error message phrasing.

The security logic is sound — requiring None balance proof when there are no stealth inputs/outputs prevents leaking the secret nonce. However, the error message ending with "None is required" is slightly awkward.

Consider this minor phrasing improvement:

-                details: "Balance proof signature verification failed for revealed amount. This indicates that the \
-                          transfer statement provided a balance proof when there are no stealth inputs or outputs, \
-                          None is required."
+                details: "Balance proof must be None when there are no stealth inputs or outputs (providing a proof \
+                          would leak the secret nonce)."
crates/wallet/sdk/src/models/lock_guard.rs (1)

11-33: Consider adding documentation for the public API.

The public struct and methods would benefit from doc comments explaining:

  • The purpose and usage pattern of the guard
  • When and why to call disarm()
  • Whether the guard is Send/Sync and any thread-safety considerations
applications/tari_validator_node/src/cli.rs (1)

108-116: Extract repeated peer_seeds.join() to reduce duplication.

The key path format is correct as-is (matches TOML structure: [nextnet.p2p.seeds], etc.). However, the duplication of self.peer_seeds.join(",") at lines 111 and 115 should be factored out:

         if !self.peer_seeds.is_empty() {
+            let seeds = self.peer_seeds.join(",");
             overrides.push((
                 format!("{}.peer_seeds", PeerSeedsConfig::main_key_prefix()),
-                self.peer_seeds.join(","),
+                seeds.clone(),
             ));
             overrides.push((
                 format!("{}.{}.peer_seeds", network, PeerSeedsConfig::main_key_prefix()),
-                self.peer_seeds.join(","),
+                seeds,
             ));
         }

Note: The same pattern exists in applications/tari_indexer/src/cli.rs (lines 101–106) and should be refactored identically.

utilities/generate_ristretto_value_lookup/src/main.rs (3)

71-78: Buffer and preallocate the output file to reduce blocking and IO syscalls.

Large numbers of 32‑byte writes on a std::fs::File in an async context can block the runtime thread and be slow.

Apply:

-    let writer = fs::File::create(&dest_file)?;
+    let mut file = fs::File::create(&dest_file)?;
+    // Best-effort preallocation; ignore if filesystem doesn't support it
+    let _ = file.set_len(file_size as u64);
+    let writer = std::io::BufWriter::with_capacity(8 * 1024 * 1024, file);

28-37: Speed up validation reads with a buffered reader (optional).

Validation iterates the entire file; using BufReader reduces syscalls and wall time.

Apply:

-        let mut file = fs::File::open(&dest_file)?;
-        let mut lookup = tari_ootle_wallet_crypto::IoReaderValueLookup::load(&mut file)?;
+        let file = fs::File::open(&dest_file)?;
+        let mut reader = std::io::BufReader::with_capacity(8 * 1024 * 1024, file);
+        let mut lookup = tari_ootle_wallet_crypto::IoReaderValueLookup::load(&mut reader)?;

95-100: Optional: flush at the end of write_output_async.

Be explicit to surface IO errors early.

Add before returning Ok(()):

writer.flush()?;
applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx (1)

211-213: Preempt UI to avoid runtime throw when owner_key_id is missing

Good guard. Consider disabling submit (and surfacing a helper text alongside the account selector) if account.account.owner_key_id is null, rather than throwing at execution time. This avoids user-facing exceptions.

crates/template_lib/src/models/stealth.rs (1)

101-112: Enforce value conservation in revealed-only constructor

Add a simple assert to ensure input_amount equals output_amount for revealed-only statements to prevent accidental mismatches at construction time. Ledger will enforce this later, but failing fast here reduces footguns.

 pub fn revealed_only(
     input_amount: Amount,
     output_amount: Amount,
     required_signer: RistrettoPublicKeyBytes,
 ) -> Self {
+    assert!(
+        input_amount == output_amount,
+        "Revealed-only stealth transfer must conserve value (inputs == outputs)"
+    );
     Self {
         inputs_statement: StealthInputsStatement::new_revealed_only(input_amount, required_signer),
         outputs_statement: StealthOutputsStatement::new_revealed_only(output_amount),
         balance_proof: None,
     }
 }
applications/tari_walletd/src/handlers/transaction.rs (1)

256-260: Update comment to reflect locks, not proofs

Comment still references “proofs table”. Please update to “locks”.

-        // update the proofs table with the corresponding transaction hash
+        // update the locks with the corresponding transaction ID for later finalization/release
applications/tari_walletd/src/handlers/accounts.rs (1)

1105-1106: Reject zero-output requests early

Guard against no-op statements to avoid needless locking/work.

Apply this diff:

         let amount_to_spend = req.total_output_amount();
+        if amount_to_spend.is_zero() {
+            return Err(invalid_params("outputs", Some("total output amount must be > 0")));
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7610f95 and 3966133.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (87)
  • Cargo.toml (2 hunks)
  • applications/tari_indexer/src/rest_api/handlers/utxos.rs (3 hunks)
  • applications/tari_indexer/src/rest_api/server.rs (2 hunks)
  • applications/tari_indexer/src/storage_sqlite/reader.rs (2 hunks)
  • applications/tari_indexer/src/store.rs (1 hunks)
  • applications/tari_indexer/src/substate_manager.rs (1 hunks)
  • applications/tari_validator_node/src/cli.rs (2 hunks)
  • applications/tari_wallet_cli/src/command/transaction.rs (6 hunks)
  • applications/tari_walletd/src/handlers/accounts.rs (7 hunks)
  • applications/tari_walletd/src/handlers/helpers.rs (1 hunks)
  • applications/tari_walletd/src/handlers/stealth_utxos.rs (5 hunks)
  • applications/tari_walletd/src/handlers/transaction.rs (9 hunks)
  • applications/tari_walletd/src/jrpc_server.rs (1 hunks)
  • applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx (3 hunks)
  • applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx (2 hunks)
  • applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx (3 hunks)
  • applications/tari_walletd/web_ui/src/routes/Transactions/Inputs.tsx (2 hunks)
  • applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (3 hunks)
  • applications/tari_walletd/web_ui/src/utils/json_rpc.ts (2 hunks)
  • bindings/package.json (1 hunks)
  • bindings/src/index.ts (1 hunks)
  • bindings/src/tari-indexer-client.ts (2 hunks)
  • bindings/src/types/ConfidentialTransferInputSelection.ts (0 hunks)
  • bindings/src/types/StealthTransferStatement.ts (1 hunks)
  • bindings/src/types/UtxoInputSelection.ts (1 hunks)
  • bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1 hunks)
  • bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1 hunks)
  • bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1 hunks)
  • bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/ConfidentialTransferRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/InputSelection.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunRequest.ts (0 hunks)
  • bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/TransferOutput.ts (1 hunks)
  • bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1 hunks)
  • bindings/src/wallet-daemon-client.ts (4 hunks)
  • clients/javascript/indexer_client/package.json (1 hunks)
  • clients/javascript/wallet_daemon_client/package.json (1 hunks)
  • clients/javascript/wallet_daemon_client/src/index.ts (1 hunks)
  • clients/tari_indexer_client/src/rest_api_client.rs (2 hunks)
  • clients/tari_indexer_client/src/types.rs (1 hunks)
  • clients/wallet_daemon_client/src/component_address.rs (1 hunks)
  • clients/wallet_daemon_client/src/lib.rs (3 hunks)
  • clients/wallet_daemon_client/src/types.rs (7 hunks)
  • crates/engine_types/src/crypto/elgamal.rs (3 hunks)
  • crates/engine_types/src/stealth/transfer.rs (5 hunks)
  • crates/epoch_oracles/src/base_layer/mod.rs (1 hunks)
  • crates/epoch_oracles/src/configured/real_time_ticker.rs (4 hunks)
  • crates/p2p/src/conversions/transaction.rs (2 hunks)
  • crates/template_builtin/templates/faucet/src/lib.rs (1 hunks)
  • crates/template_lib/src/models/stealth.rs (2 hunks)
  • crates/template_test_tooling/src/support/stealth.rs (1 hunks)
  • crates/transaction/src/v1/unsigned.rs (2 hunks)
  • crates/wallet/crypto/src/stealth.rs (3 hunks)
  • crates/wallet/crypto/src/value_lookup/header.rs (1 hunks)
  • crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (3 hunks)
  • crates/wallet/crypto/src/value_lookup/mod.rs (1 hunks)
  • crates/wallet/crypto/tests/stealth_transfer_statement.rs (8 hunks)
  • crates/wallet/sdk/src/apis/confidential_outputs.rs (0 hunks)
  • crates/wallet/sdk/src/apis/confidential_transfer.rs (13 hunks)
  • crates/wallet/sdk/src/apis/stealth_crypto.rs (1 hunks)
  • crates/wallet/sdk/src/apis/stealth_outputs.rs (5 hunks)
  • crates/wallet/sdk/src/apis/stealth_transfer/api.rs (9 hunks)
  • crates/wallet/sdk/src/apis/stealth_transfer/error.rs (2 hunks)
  • crates/wallet/sdk/src/apis/stealth_transfer/params.rs (2 hunks)
  • crates/wallet/sdk/src/apis/substate.rs (1 hunks)
  • crates/wallet/sdk/src/models/account.rs (1 hunks)
  • crates/wallet/sdk/src/models/key.rs (1 hunks)
  • crates/wallet/sdk/src/models/lock_guard.rs (1 hunks)
  • crates/wallet/sdk/src/models/mod.rs (2 hunks)
  • crates/wallet/sdk/src/models/wallet_transaction.rs (1 hunks)
  • crates/wallet/sdk/src/sdk.rs (1 hunks)
  • crates/wallet/sdk_services/src/indexer_rest_api.rs (2 hunks)
  • integration_tests/src/wallet_daemon_client.rs (10 hunks)
  • integration_tests/tests/steps/wallet_daemon.rs (2 hunks)
  • utilities/generate_ristretto_value_lookup/Cargo.toml (1 hunks)
  • utilities/generate_ristretto_value_lookup/src/cli.rs (1 hunks)
  • utilities/generate_ristretto_value_lookup/src/main.rs (1 hunks)
  • utilities/traffic-sim/Cargo.toml (1 hunks)
  • utilities/traffic-sim/src/main.rs (1 hunks)
  • utilities/traffic-sim/src/sim.rs (1 hunks)
💤 Files with no reviewable changes (3)
  • crates/wallet/sdk/src/apis/confidential_outputs.rs
  • bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunRequest.ts
  • bindings/src/types/ConfidentialTransferInputSelection.ts
🚧 Files skipped from review as they are similar to previous changes (44)
  • crates/epoch_oracles/src/base_layer/mod.rs
  • crates/wallet/sdk/src/models/account.rs
  • bindings/src/types/tari-indexer-client/ListUtxosRequest.ts
  • clients/javascript/wallet_daemon_client/src/index.ts
  • bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts
  • crates/epoch_oracles/src/configured/real_time_ticker.rs
  • crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs
  • crates/wallet/sdk/src/apis/stealth_crypto.rs
  • bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts
  • applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx
  • bindings/src/index.ts
  • applications/tari_walletd/web_ui/src/utils/json_rpc.ts
  • bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts
  • applications/tari_indexer/src/rest_api/server.rs
  • bindings/src/types/tari-indexer-client/GetUtxosRequest.ts
  • crates/wallet/crypto/src/value_lookup/header.rs
  • crates/wallet/sdk/src/apis/stealth_transfer/params.rs
  • clients/javascript/wallet_daemon_client/package.json
  • crates/transaction/src/v1/unsigned.rs
  • bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts
  • crates/wallet/crypto/src/value_lookup/mod.rs
  • crates/wallet/sdk/src/apis/stealth_outputs.rs
  • utilities/generate_ristretto_value_lookup/src/cli.rs
  • crates/wallet/sdk/src/apis/substate.rs
  • bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts
  • clients/javascript/indexer_client/package.json
  • bindings/src/types/UtxoInputSelection.ts
  • clients/tari_indexer_client/src/types.rs
  • clients/wallet_daemon_client/src/component_address.rs
  • applications/tari_walletd/web_ui/src/routes/Transactions/Inputs.tsx
  • bindings/src/types/tari-indexer-client/ListUtxosResponse.ts
  • crates/template_builtin/templates/faucet/src/lib.rs
  • bindings/src/types/tari-indexer-client/GetUtxosResponse.ts
  • bindings/src/types/StealthTransferStatement.ts
  • applications/tari_walletd/src/jrpc_server.rs
  • bindings/src/wallet-daemon-client.ts
  • bindings/src/types/wallet-daemon-client/InputSelection.ts
  • clients/tari_indexer_client/src/rest_api_client.rs
  • bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts
  • crates/wallet/sdk/src/models/key.rs
  • utilities/traffic-sim/Cargo.toml
  • integration_tests/tests/steps/wallet_daemon.rs
  • bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts
  • applications/tari_indexer/src/store.rs
🧰 Additional context used
🧬 Code graph analysis (31)
crates/wallet/sdk/src/models/wallet_transaction.rs (1)
bindings/src/types/TransactionStatus.ts (1)
  • TransactionStatus (3-11)
applications/tari_walletd/src/handlers/helpers.rs (2)
crates/wallet/sdk/src/sdk.rs (1)
  • accounts_api (228-235)
crates/wallet/sdk/src/storage.rs (1)
  • not_found (156-158)
crates/wallet/sdk/src/apis/stealth_transfer/error.rs (2)
bindings/src/types/ResourceAddress.ts (1)
  • ResourceAddress (6-6)
bindings/src/types/Amount.ts (1)
  • Amount (12-12)
utilities/generate_ristretto_value_lookup/src/main.rs (2)
utilities/generate_ristretto_value_lookup/src/cli.rs (1)
  • init (31-33)
crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (2)
  • lookup (90-101)
  • load (26-35)
clients/wallet_daemon_client/src/lib.rs (4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
  • AccountsCreateStealthTransferStatementRequest (4-4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
  • AccountsCreateStealthTransferStatementResponse (5-9)
clients/validator_node_client/src/lib.rs (1)
  • endpoint (58-60)
bindings/src/types/wallet-daemon-client/ProofsGenerateRequest.ts (1)
  • ProofsGenerateRequest (8-15)
applications/tari_validator_node/src/cli.rs (1)
applications/tari_app_utilities/src/configuration.rs (1)
  • convert_l1_network_to_network (31-40)
applications/tari_indexer/src/substate_manager.rs (5)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (1)
  • list_utxos (116-132)
clients/tari_indexer_client/src/rest_api_client.rs (1)
  • list_utxos (174-176)
bindings/src/types/ResourceAddress.ts (1)
  • ResourceAddress (6-6)
bindings/src/types/UtxoId.ts (1)
  • UtxoId (3-3)
bindings/src/types/Utxo.ts (1)
  • Utxo (4-4)
crates/wallet/sdk_services/src/indexer_rest_api.rs (1)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
  • GetUtxosRequest (6-9)
crates/wallet/crypto/src/stealth.rs (2)
crates/engine_types/src/crypto/messages.rs (1)
  • stealth_statement_metadata64 (74-79)
crates/wallet/crypto/src/balance_proof.rs (1)
  • generate_stealth_balance_proof_signature (38-55)
applications/tari_wallet_cli/src/command/transaction.rs (5)
integration_tests/src/wallet_daemon_client.rs (1)
  • confidential_transfer (877-920)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
crates/wallet/sdk/src/models/account.rs (2)
  • owner_key_id (33-35)
  • owner_key_id (95-97)
crates/wallet/sdk/src/models/key.rs (1)
  • for_account (298-303)
bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1)
  • TransactionSubmitRequest (5-21)
applications/tari_walletd/src/handlers/transaction.rs (5)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/models/account.rs (2)
  • owner_key_id (33-35)
  • owner_key_id (95-97)
applications/tari_walletd/src/handlers/helpers.rs (1)
  • invalid_params (162-173)
crates/wallet/sdk/src/models/key.rs (1)
  • for_account (298-303)
applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (2)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
bindings/src/helpers/consts.ts (1)
  • XTR (10-10)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (6)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
  • GetUtxosRequest (6-9)
bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1)
  • GetUtxosResponse (5-5)
bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1)
  • ListUtxosRequest (5-5)
bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1)
  • ListUtxosResponse (5-5)
applications/tari_indexer/src/substate_manager.rs (1)
  • list_utxos (143-153)
clients/tari_indexer_client/src/rest_api_client.rs (1)
  • list_utxos (174-176)
crates/wallet/crypto/tests/stealth_transfer_statement.rs (3)
crates/template_test_tooling/src/support/stealth.rs (1)
  • inputs (204-215)
crates/wallet/crypto/src/stealth.rs (2)
  • output_statements (123-153)
  • create_outputs_statement (119-162)
crates/wallet/crypto/src/balance_proof.rs (1)
  • generate_stealth_balance_proof_signature (38-55)
applications/tari_indexer/src/storage_sqlite/reader.rs (1)
applications/tari_indexer/src/store.rs (1)
  • utxos_list (153-158)
bindings/src/types/wallet-daemon-client/ConfidentialTransferRequest.ts (3)
bindings/src/types/wallet-daemon-client/ComponentAddressOrName.ts (1)
  • ComponentAddressOrName (4-4)
bindings/src/types/Amount.ts (1)
  • Amount (12-12)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (2)
bindings/src/types/OotleAddress.ts (1)
  • OotleAddress (3-3)
bindings/src/types/Amount.ts (1)
  • Amount (12-12)
crates/wallet/sdk/src/apis/confidential_transfer.rs (3)
crates/wallet/sdk/src/sdk.rs (2)
  • network (189-191)
  • transaction_api (220-222)
crates/wallet/sdk/src/apis/transaction.rs (1)
  • new (40-45)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
crates/p2p/src/conversions/transaction.rs (2)
crates/template_lib_types/src/crypto/scalar.rs (1)
  • from_bytes (32-43)
crates/engine_types/src/substate.rs (3)
  • from_bytes (98-100)
  • from_bytes (197-199)
  • from_bytes (787-789)
utilities/traffic-sim/src/main.rs (5)
bindings/src/types/ComponentAddress.ts (1)
  • ComponentAddress (6-6)
bindings/src/types/ResourceAddress.ts (1)
  • ResourceAddress (6-6)
bindings/src/types/UtxoId.ts (1)
  • UtxoId (3-3)
utilities/traffic-sim/src/sim.rs (1)
  • wallets (113-115)
clients/wallet_daemon_client/src/lib.rs (1)
  • endpoint (166-168)
integration_tests/src/wallet_daemon_client.rs (6)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
bindings/src/types/Account.ts (1)
  • Account (6-14)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
crates/wallet/sdk/src/models/account.rs (3)
  • owner_key_id (33-35)
  • owner_key_id (95-97)
  • account (75-77)
crates/wallet/sdk/src/models/key.rs (1)
  • for_account (298-303)
crates/wallet/sdk/src/apis/stealth_transfer/api.rs (2)
integration_tests/src/wallet_daemon_client.rs (1)
  • confidential_transfer (877-920)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
applications/tari_walletd/src/handlers/accounts.rs (10)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
  • TransferOutput (6-24)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-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/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
  • AccountsCreateStealthTransferStatementRequest (4-4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
  • AccountsCreateStealthTransferStatementResponse (5-9)
crates/wallet/sdk/src/models/account.rs (2)
  • account (75-77)
  • new (71-73)
applications/tari_walletd/src/handlers/helpers.rs (3)
  • get_account (113-124)
  • not_found (183-190)
  • invalid_params (162-173)
crates/wallet/sdk/src/models/key.rs (2)
  • new (294-296)
  • derived (322-324)
crates/wallet/sdk/src/models/lock_guard.rs (1)
  • lock_id (26-28)
crates/template_lib/src/models/stealth.rs (6)
bindings/src/types/StealthOutputsStatement.ts (1)
  • StealthOutputsStatement (9-24)
bindings/src/types/Amount.ts (1)
  • Amount (12-12)
bindings/src/types/RangeProofBytes.ts (1)
  • RangeProofBytes (9-9)
bindings/src/types/StealthTransferStatement.ts (1)
  • StealthTransferStatement (5-13)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
bindings/src/types/StealthInputsStatement.ts (1)
  • StealthInputsStatement (9-22)
utilities/traffic-sim/src/sim.rs (6)
clients/tari_indexer_client/src/rest_api_client.rs (1)
  • connect (53-66)
clients/wallet_daemon_client/src/lib.rs (2)
  • connect (149-164)
  • endpoint (166-168)
crates/wallet/sdk/src/models/account.rs (5)
  • address (83-85)
  • new (71-73)
  • account (75-77)
  • component_address (25-27)
  • component_address (79-81)
crates/transaction/src/v1/unsigned.rs (2)
  • new (41-60)
  • builder (37-39)
crates/engine_types/src/resource.rs (2)
  • divisibility (211-213)
  • token_symbol (207-209)
crates/template_lib_types/src/amount/amount.rs (1)
  • to_decimal_string (322-327)
crates/engine_types/src/stealth/transfer.rs (1)
crates/engine_types/src/crypto/helpers.rs (1)
  • try_decode_to_signature (91-93)
crates/template_test_tooling/src/support/stealth.rs (6)
crates/transaction/src/v1/unsigned.rs (1)
  • inputs (80-82)
crates/transaction/src/v1/transaction.rs (1)
  • inputs (85-87)
crates/transaction/src/unsigned_transaction.rs (1)
  • inputs (78-82)
crates/transaction/src/transaction.rs (1)
  • inputs (123-127)
crates/template_test_tooling/src/support/confidential.rs (1)
  • inputs (170-176)
crates/wallet/sdk/src/apis/stealth_outputs.rs (1)
  • outputs (692-692)
applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx (2)
crates/engine_types/src/resource.rs (1)
  • divisibility (211-213)
applications/tari_walletd/web_ui/src/utils/helpers.tsx (1)
  • bigintToDecimalString (233-253)
applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-10)
applications/tari_walletd/src/handlers/stealth_utxos.rs (5)
applications/tari_walletd/src/handlers/helpers.rs (1)
  • invalid_params (162-173)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1)
  • StealthUtxosDecryptValueRequest (5-11)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
  • StealthUtxosDecryptValueResponse (4-4)
crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (3)
  • lookup (90-101)
  • load (26-35)
  • range (82-84)
crates/wallet/crypto/src/value_lookup/mod.rs (1)
  • lookup (19-21)
clients/wallet_daemon_client/src/types.rs (14)
integration_tests/src/wallet_daemon_client.rs (1)
  • confidential_transfer (877-920)
bindings/src/types/UtxoInputSelection.ts (1)
  • UtxoInputSelection (3-3)
crates/engine/src/runtime/impl.rs (1)
  • stealth_transfer (2760-2776)
crates/template_lib/src/models/bucket.rs (1)
  • stealth_transfer (118-133)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
  • TransferOutput (6-24)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/StealthTransferStatement.ts (1)
  • StealthTransferStatement (5-13)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
  • AccountsCreateStealthTransferStatementRequest (4-4)
bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1)
  • TransferStatementRequest (7-12)
bindings/src/types/wallet-daemon-client/InputSelection.ts (1)
  • InputSelection (5-5)
crates/wallet/sdk/src/apis/stealth_transfer/params.rs (2)
  • total_output_amount (100-102)
  • total_output_amount (124-126)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
  • AccountsCreateStealthTransferStatementResponse (5-9)
bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts (1)
  • StealthTransferRequest (8-17)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
  • StealthUtxosDecryptValueResponse (4-4)
⏰ 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). (6)
  • GitHub Check: test
  • GitHub Check: check stable
  • GitHub Check: check nightly
  • GitHub Check: clippy
  • GitHub Check: machete
  • GitHub Check: file licenses

Comment on lines +952 to 957
seal_signer: BranchAndKeyId::new(KeyBranch::Account, account.owner_key_id.expect("no owner_key_id")),
other_signers: vec![],
detect_inputs: true,
detect_inputs_use_unversioned: use_unversioned_inputs,
proof_ids: vec![],
lock_ids: vec![],
};

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

🧩 Analysis chain

Use BranchAndKeyId::for_account(...) instead of new(...)

Replace the remaining BranchAndKeyId::new(...) with for_account(...) for consistency and to avoid API drift/compile errors.

-        seal_signer: BranchAndKeyId::new(KeyBranch::Account, account.owner_key_id.expect("no owner_key_id")),
+        seal_signer: BranchAndKeyId::for_account(account.owner_key_id.expect("no owner_key_id")),

🏁 Script executed:

#!/bin/bash
# Ensure no other uses of BranchAndKeyId::new remain
rg -nP 'BranchAndKeyId::new\s*\(' -C2

Length of output: 1939


Replace all remaining BranchAndKeyId::new(KeyBranch::Account, ...) with for_account(...) for consistency

Verification found three instances requiring the same refactor pattern:

  • utilities/traffic-sim/src/sim.rs:377
  • integration_tests/tests/steps/wallet_daemon.rs:130
  • integration_tests/src/wallet_daemon_client.rs:952

Update all three to use BranchAndKeyId::for_account(...) instead of the explicit constructor.

🤖 Prompt for AI Agents
In integration_tests/src/wallet_daemon_client.rs around lines 952–957 (and also
update utilities/traffic-sim/src/sim.rs:377 and
integration_tests/tests/steps/wallet_daemon.rs:130), replace the explicit
constructor call BranchAndKeyId::new(KeyBranch::Account,
account.owner_key_id.expect("no owner_key_id")) with the canonical helper
BranchAndKeyId::for_account(account.owner_key_id.expect("no owner_key_id"));
apply the same replacement at the other two locations so all uses are consistent
and retain the existing expect message.

Comment on lines 60 to 67
let file_size = (cli.max - cli.min + 1) * 32 + 20;
// Rough estimate: 200ms per 10,000 values on a "typical" cpu
let est_time = Duration::from_millis((cli.max - cli.min + 1) / 10000 * 200);
println!(
"Generating Ristretto value lookup table from {} to {} and writing to {} ({}). This will take roughly {} to \
complete.",
"Generating Ristretto value lookup table from {} to {} and writing to {} ({}).",
cli.min,
cli.max,
dest_file.display(),
human_bytes(file_size as f64),
humantime::format_duration(est_time)
);

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

Guard against invalid range (min > max) to avoid u64 underflow.

Without a check, (cli.max - cli.min + 1) can underflow and produce a huge file_size.

Apply:

     let dest_file = cli.output_file;
 
+    if cli.min > cli.max {
+        return Err(io::Error::new(
+            io::ErrorKind::InvalidInput,
+            format!("min ({}) must be <= max ({})", cli.min, cli.max),
+        ));
+    }
+
     if cli.validate {

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In utilities/generate_ristretto_value_lookup/src/main.rs around lines 60 to 67,
the computation of file_size uses (cli.max - cli.min + 1) which will underflow
if cli.min > cli.max; add an explicit guard that checks if cli.min > cli.max and
handle it by returning an error (or printing a clear message and exiting with
non-zero status) before computing file_size, or alternatively normalize the
range (swap or use checked subtraction) so the size calculation cannot
underflow; ensure the guard triggers prior to any arithmetic and prevents
continuing with an invalid range.

Comment on lines +92 to +102
async fn write_output_async<W: io::Write>(mut writer: W, min: u64, max: u64, num_threads: usize) -> io::Result<()> {
// Write header VLKP || min_value (8 bytes) || max_value (8 bytes)
writer.write_all(b"VLKP")?;
writer.write_all(&min.to_be_bytes())?;
writer.write_all(&max.to_be_bytes())?;

println!(
"Using {} worker threads to generate Ristretto public keys.",
num_threads
);

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.

🛠️ Refactor suggestion | 🟠 Major

Ensure num_threads >= 1 inside the generator.

Defensive clamp prevents a misconfigured CLI (e.g., 0 jobs) from producing an empty body.

Apply:

-async fn write_output_async<W: io::Write>(mut writer: W, min: u64, max: u64, num_threads: usize) -> io::Result<()> {
+async fn write_output_async<W: io::Write>(mut writer: W, min: u64, max: u64, mut num_threads: usize) -> io::Result<()> {
+    if num_threads == 0 {
+        num_threads = 1;
+    }
🤖 Prompt for AI Agents
In utilities/generate_ristretto_value_lookup/src/main.rs around lines 92 to 102,
the generator assumes num_threads > 0 which allows a misconfigured CLI (e.g., 0
jobs) to produce an empty body; clamp num_threads to at least 1 before using it
in the generator (e.g., replace usage with a local let num_threads = if
num_threads == 0 { 1 } else { num_threads } or use num_threads =
num_threads.max(1)) so the code always spawns at least one worker thread and the
output body is never empty.

Comment on lines +148 to +155
let (i, mut results) = handles.next().await.expect("handles stream end")?;
for pk_bytes in &results {
count += 1;
writer.write_all(pk_bytes)?;
}
results.clear();
scratch_pad[i].replace(results);

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

Fix JoinError propagation; ? doesn’t convert JoinError to io::Error.

Map JoinError to io::Error to compile cleanly.

Apply:

-        let (i, mut results) = handles.next().await.expect("handles stream end")?;
+        let (i, mut results) = handles
+            .next()
+            .await
+            .expect("handles stream end")
+            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let (i, mut results) = handles.next().await.expect("handles stream end")?;
for pk_bytes in &results {
count += 1;
writer.write_all(pk_bytes)?;
}
results.clear();
scratch_pad[i].replace(results);
let (i, mut results) = handles
.next()
.await
.expect("handles stream end")
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
for pk_bytes in &results {
count += 1;
writer.write_all(pk_bytes)?;
}
results.clear();
scratch_pad[i].replace(results);
🤖 Prompt for AI Agents
utilities/generate_ristretto_value_lookup/src/main.rs around lines 148 to 155:
the code uses `?` on the result of the spawned-task join which yields a
JoinError, but `?` cannot convert JoinError into io::Error; change the join
error handling to map the JoinError into an io::Error before using `?` (e.g.,
call `.map_err(|je| std::io::Error::new(std::io::ErrorKind::Other,
je.to_string()))?` on the join result), leaving the rest of the loop (count
increment, writer.write_all, clearing and replacing scratch_pad) unchanged.

Comment on lines +194 to +266
pub async fn send_random_transaction(
&mut self,
id: usize,
resource_address: ResourceAddress,
min_value: u64,
max_value: u64,
) -> anyhow::Result<()> {
if self.wallets.len() < 2 {
return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions"));
}

let mut rng = rand::thread_rng();
let sender_idx = rng.gen_range(0..self.accounts.len());
let mut receiver_idx = rng.gen_range(0..self.accounts.len());

while receiver_idx == sender_idx {
receiver_idx = rng.gen_range(0..self.accounts.len());
}

let sender_account = &self.accounts[sender_idx];
let sender_wallet = &self.wallets[sender_idx];
let receiver_address = &self.accounts[receiver_idx];
let receiver_wallet = &self.wallets[receiver_idx];

let amount_to_send = rng.gen_range(min_value..=max_value);

log::info!(
"Sending {} ootle from {} to {}",
amount_to_send,
sender_wallet.name,
receiver_wallet.name
);

let sender = &self.wallets[sender_idx];
let mut sender_client = sender.client.clone();

let resp = sender_client
.accounts_stealth_transfer(StealthTransferRequest {
owner_account: (*sender_account.component_address()).into(),
fee_input_selection: UtxoInputSelection::PreferConfidential,
input_selection: UtxoInputSelection::ConfidentialOnly,
resource_address,
badge_usage: Default::default(),
transfers: vec![StealthTransfer {
destination_address: receiver_address.address().clone(),
blinded_output_amount: amount_to_send.into(),
revealed_output_amount: Default::default(),
output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()),
}],
max_fee: 1000,
dry_run: false,
})
.await?;

log::info!(
"Tx {} --> {}: {}",
sender_wallet.name,
receiver_wallet.name,
// resp.status,
// resp.result.as_ref().and_then(|r| r.result.any_reject()).display(),
resp.transaction_id,
);

// Placeholder implementation - this will need to be updated based on actual API
log::info!(
"send transaction of {} from {} to {}",
amount_to_send,
sender_account,
receiver_address
);

Ok(())
}

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 | 🟡 Minor

Verify index bounds match.

Lines 206-207 select random indices from self.accounts.len(), but Line 214 and 216 access self.wallets[sender_idx] and self.wallets[receiver_idx]. This assumes wallets.len() == accounts.len(). While setup_accounts() maintains this invariant, add a runtime check at the beginning of this method to prevent potential index out-of-bounds panics.

Apply this diff to add a defensive check:

 pub async fn send_random_transaction(
     &mut self,
     id: usize,
     resource_address: ResourceAddress,
     min_value: u64,
     max_value: u64,
 ) -> anyhow::Result<()> {
     if self.wallets.len() < 2 {
         return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions"));
     }
+    
+    if self.wallets.len() != self.accounts.len() {
+        return Err(anyhow::anyhow!(
+            "Wallets and accounts vectors are misaligned ({} wallets vs {} accounts)",
+            self.wallets.len(),
+            self.accounts.len()
+        ));
+    }

     let mut rng = rand::thread_rng();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub async fn send_random_transaction(
&mut self,
id: usize,
resource_address: ResourceAddress,
min_value: u64,
max_value: u64,
) -> anyhow::Result<()> {
if self.wallets.len() < 2 {
return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions"));
}
let mut rng = rand::thread_rng();
let sender_idx = rng.gen_range(0..self.accounts.len());
let mut receiver_idx = rng.gen_range(0..self.accounts.len());
while receiver_idx == sender_idx {
receiver_idx = rng.gen_range(0..self.accounts.len());
}
let sender_account = &self.accounts[sender_idx];
let sender_wallet = &self.wallets[sender_idx];
let receiver_address = &self.accounts[receiver_idx];
let receiver_wallet = &self.wallets[receiver_idx];
let amount_to_send = rng.gen_range(min_value..=max_value);
log::info!(
"Sending {} ootle from {} to {}",
amount_to_send,
sender_wallet.name,
receiver_wallet.name
);
let sender = &self.wallets[sender_idx];
let mut sender_client = sender.client.clone();
let resp = sender_client
.accounts_stealth_transfer(StealthTransferRequest {
owner_account: (*sender_account.component_address()).into(),
fee_input_selection: UtxoInputSelection::PreferConfidential,
input_selection: UtxoInputSelection::ConfidentialOnly,
resource_address,
badge_usage: Default::default(),
transfers: vec![StealthTransfer {
destination_address: receiver_address.address().clone(),
blinded_output_amount: amount_to_send.into(),
revealed_output_amount: Default::default(),
output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()),
}],
max_fee: 1000,
dry_run: false,
})
.await?;
log::info!(
"Tx {} --> {}: {}",
sender_wallet.name,
receiver_wallet.name,
// resp.status,
// resp.result.as_ref().and_then(|r| r.result.any_reject()).display(),
resp.transaction_id,
);
// Placeholder implementation - this will need to be updated based on actual API
log::info!(
"send transaction of {} from {} to {}",
amount_to_send,
sender_account,
receiver_address
);
Ok(())
}
pub async fn send_random_transaction(
&mut self,
id: usize,
resource_address: ResourceAddress,
min_value: u64,
max_value: u64,
) -> anyhow::Result<()> {
if self.wallets.len() < 2 {
return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions"));
}
if self.wallets.len() != self.accounts.len() {
return Err(anyhow::anyhow!(
"Wallets and accounts vectors are misaligned ({} wallets vs {} accounts)",
self.wallets.len(),
self.accounts.len()
));
}
let mut rng = rand::thread_rng();
let sender_idx = rng.gen_range(0..self.accounts.len());
let mut receiver_idx = rng.gen_range(0..self.accounts.len());
while receiver_idx == sender_idx {
receiver_idx = rng.gen_range(0..self.accounts.len());
}
let sender_account = &self.accounts[sender_idx];
let sender_wallet = &self.wallets[sender_idx];
let receiver_address = &self.accounts[receiver_idx];
let receiver_wallet = &self.wallets[receiver_idx];
let amount_to_send = rng.gen_range(min_value..=max_value);
log::info!(
"Sending {} ootle from {} to {}",
amount_to_send,
sender_wallet.name,
receiver_wallet.name
);
let sender = &self.wallets[sender_idx];
let mut sender_client = sender.client.clone();
let resp = sender_client
.accounts_stealth_transfer(StealthTransferRequest {
owner_account: (*sender_account.component_address()).into(),
fee_input_selection: UtxoInputSelection::PreferConfidential,
input_selection: UtxoInputSelection::ConfidentialOnly,
resource_address,
badge_usage: Default::default(),
transfers: vec![StealthTransfer {
destination_address: receiver_address.address().clone(),
blinded_output_amount: amount_to_send.into(),
revealed_output_amount: Default::default(),
output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()),
}],
max_fee: 1000,
dry_run: false,
})
.await?;
log::info!(
"Tx {} --> {}: {}",
sender_wallet.name,
receiver_wallet.name,
// resp.status,
// resp.result.as_ref().and_then(|r| r.result.any_reject()).display(),
resp.transaction_id,
);
// Placeholder implementation - this will need to be updated based on actual API
log::info!(
"send transaction of {} from {} to {}",
amount_to_send,
sender_account,
receiver_address
);
Ok(())
}

@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 (1)
applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx (1)

57-65: Iterate with Object.entries and fix message text.

Cleaner iteration with better type inference; also fix the copy.

Apply this diff:

-    Object.keys(balance?.values).map((key) => {
-      return (
-        <Box key={key}>
-          <Typography>
-            {key}: {balance.values[key]?.toString() || "Failed not decrypt value"}
-          </Typography>
-        </Box>
-      );
-    });
+    Object.entries(balance.values).map(([key, value]) => (
+      <Box key={key}>
+        <Typography>
+          {key}: {value != null ? value.toString() : "Failed to decrypt value"}
+        </Typography>
+      </Box>
+    ));
♻️ Duplicate comments (5)
applications/tari_indexer/src/storage_sqlite/reader.rs (1)

578-587: Unaddressed past review: NULL subquery returns empty results for invalid from_id.

The past review comment on lines 563-607 correctly identified that if from_id references a non-existent commitment, the subquery yields NULL and id.gt(NULL) returns no rows. This issue remains unaddressed.

As suggested in the previous review, resolve the start_id first:

     if let Some(from_id) = from_id {
-        let uxo = alias!(utxos as uxo);
-        let subquery = uxo
-            .select(uxo.field(utxos::id))
+        let start_id: Option<i32> = utxos::table
+            .select(utxos::id)
             .filter(uxo.field(utxos::commitment).eq(from_id.to_commitment_hex_string()))
-            .limit(1)
-            .single_value()
-            .assume_not_null();
-        query = query.filter(utxos::id.gt(subquery));
+            .first::<i32>(self.connection())
+            .optional()
+            .map_err(|e| StorageError::QueryError {
+                reason: format!("{OPERATION}: failed to resolve from_id: {}", e),
+            })?;
+        
+        if let Some(id) = start_id {
+            query = query.filter(utxos::id.gt(id));
+        }
+        // If start_id is None, pagination starts from the beginning
     }
applications/tari_walletd/src/handlers/accounts.rs (2)

1132-1138: Must sign with account key when revealed funds come FromBucket.

Line 1132 only checks if locked inputs include revealed funds. If revealed funds are provided via FromBucket, the account signer is also required. This is the same issue identified in the previous review.

Apply:

-        let must_sign_with_account_key = inputs.as_ref().is_some_and(|i| i.revealed.is_positive());
+        let must_sign_with_account_key =
+            inputs.as_ref().is_some_and(|i| i.revealed.is_positive()) ||
+            req.input_selection.as_from_bucket().is_some_and(|a| a.is_positive());

Based on learnings


1163-1173: checked_add_positive may reject zero; compute conditionally.

Using checked_add_positive with a zero addend can error. This is the same issue identified in the previous review. Only add when positive, otherwise pass the base amount unchanged.

Apply:

-                input_revealed_amount: req
-                    .input_selection
-                    .as_from_bucket()
-                    .unwrap_or(Amount::zero())
-                    .checked_add_positive(inputs.as_ref().map(|i| i.revealed).unwrap_or(Amount::zero()))
-                    .ok_or_else(|| {
-                        invalid_params(
-                            "input_revealed_amount",
-                            Some("input revealed amount overflowed or was negative"),
-                        )
-                    })?,
+                input_revealed_amount: {
+                    let mut total = req.input_selection.as_from_bucket().unwrap_or(Amount::zero());
+                    if let Some(i) = inputs.as_ref() {
+                        if i.revealed.is_positive() {
+                            total = total.checked_add_positive(i.revealed).ok_or_else(|| {
+                                invalid_params(
+                                    "input_revealed_amount",
+                                    Some("input revealed amount overflowed"),
+                                )
+                            })?;
+                        }
+                    }
+                    total
+                },

Based on learnings

utilities/traffic-sim/src/sim.rs (2)

233-238: Remove duplicate placeholder log.

This duplicates earlier logging and adds little value.

-        log::info!(
-            "send transaction of {} from {} to {}",
-            amount_to_send,
-            sender_account,
-            receiver_address
-        );

179-189: Defend against index misalignment and invalid ranges.

Potential panic if accounts < 2, wallets != accounts, or min_value > max_value. Add guards.

     ) -> anyhow::Result<()> {
-        if self.wallets.len() < 2 {
+        if self.wallets.len() < 2 {
             return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions"));
         }
+        if self.accounts.len() < 2 {
+            return Err(anyhow::anyhow!("Need at least 2 accounts to send transactions"));
+        }
+        if self.wallets.len() != self.accounts.len() {
+            return Err(anyhow::anyhow!(
+                "Wallets and accounts vectors are misaligned ({} wallets vs {} accounts)",
+                self.wallets.len(),
+                self.accounts.len()
+            ));
+        }
+        if min_value > max_value {
+            return Err(anyhow::anyhow!(
+                "min_value ({}) must be <= max_value ({})",
+                min_value,
+                max_value
+            ));
+        }
 
         let mut rng = rand::thread_rng();
         let sender_idx = rng.gen_range(0..self.accounts.len());
         let mut receiver_idx = rng.gen_range(0..self.accounts.len());
🧹 Nitpick comments (5)
utilities/traffic-sim/src/sim.rs (5)

113-116: Return slice instead of &Vec in accessor.

Prefer &[T] to avoid leaking the concrete container type.

-    pub fn wallets(&self) -> &Vec<Wallet> {
-        &self.wallets
-    }
+    pub fn wallets(&self) -> &[Wallet] {
+        &self.wallets
+    }

329-347: Build funding transaction for the exchange wallet’s network.

You’re constructing and submitting the tx with the exchange wallet; use its network to avoid subtle mismatches if wallets differ.

-            let transaction = Transaction::builder()
-                .for_network(wallet.network.as_byte())
+            let transaction = Transaction::builder()
+                .for_network(exchange_wallet.network.as_byte())
                 .fee_transaction_pay_from_component(*exchange_account.component_address(), 500)

Please confirm that all swarm wallets always share the same network; if not, this change is required. Based on context.


423-424: Use warn! for failed transactions.

Failures are noteworthy; prefer warn! over info!.

-                    log::info!("Transaction failed: {:?}", e);
+                    log::warn!("Transaction failed: {:?}", e);

107-111: Drop unnecessary mut binding.

exchange_wallet is not mutated in this scope.

-        let mut exchange_wallet = self.connect_exchange_wallet().await?;
+        let exchange_wallet = self.connect_exchange_wallet().await?;

566-573: Flush CSV writer before returning.

Ensure records are persisted.

-        Ok(())
+        if let Some(writer) = csv.as_mut() {
+            writer.flush()?;
+        }
+        Ok(())
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3966133 and 53db32b.

📒 Files selected for processing (5)
  • applications/tari_indexer/src/storage_sqlite/reader.rs (2 hunks)
  • applications/tari_walletd/src/handlers/accounts.rs (7 hunks)
  • applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx (2 hunks)
  • applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (3 hunks)
  • utilities/traffic-sim/src/sim.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts
🧰 Additional context used
🧬 Code graph analysis (4)
applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx (2)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
  • StealthUtxosDecryptValueResponse (4-4)
applications/tari_walletd/web_ui/src/utils/json_rpc.ts (1)
  • stealthDecryptUtxoBalance (314-316)
applications/tari_indexer/src/storage_sqlite/reader.rs (4)
applications/tari_indexer/src/store.rs (1)
  • utxos_list (153-158)
crates/template_lib/src/models/utxo.rs (2)
  • resource_address (31-33)
  • id (35-37)
bindings/src/types/UtxoId.ts (1)
  • UtxoId (3-3)
bindings/src/types/Utxo.ts (1)
  • Utxo (4-4)
applications/tari_walletd/src/handlers/accounts.rs (7)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
  • BranchAndKeyId (5-5)
bindings/src/types/wallet-daemon-client/KeyId.ts (1)
  • KeyId (3-3)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
  • AccountsCreateStealthTransferStatementRequest (4-4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
  • AccountsCreateStealthTransferStatementResponse (5-9)
applications/tari_walletd/src/handlers/helpers.rs (3)
  • get_account (113-124)
  • not_found (183-190)
  • invalid_params (162-173)
crates/wallet/sdk/src/models/key.rs (2)
  • new (294-296)
  • derived (322-324)
crates/wallet/sdk/src/models/lock_guard.rs (1)
  • lock_id (26-28)
utilities/traffic-sim/src/sim.rs (9)
bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts (1)
  • StealthTransferRequest (8-17)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1)
  • StealthUtxosDecryptValueRequest (5-11)
bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1)
  • TransferStatementRequest (7-12)
clients/tari_indexer_client/src/rest_api_client.rs (1)
  • connect (53-66)
clients/wallet_daemon_client/src/lib.rs (2)
  • connect (149-164)
  • endpoint (166-168)
crates/wallet/sdk/src/models/account.rs (5)
  • address (83-85)
  • new (71-73)
  • account (75-77)
  • component_address (25-27)
  • component_address (79-81)
crates/transaction/src/v1/unsigned.rs (2)
  • new (41-60)
  • builder (37-39)
crates/wallet/crypto/src/memo.rs (1)
  • new_message (42-46)
crates/template_lib_types/src/amount/amount.rs (1)
  • to_decimal_string (322-327)
⏰ 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). (3)
  • GitHub Check: clippy
  • GitHub Check: test
  • GitHub Check: check nightly
🔇 Additional comments (12)
applications/tari_indexer/src/storage_sqlite/reader.rs (2)

417-417: LGTM! Correct use of aliased table reference.

The change to use tr.field(transaction_receipts::address) is the proper Diesel pattern for referencing columns in aliased subqueries.


572-576: Good fix: is_burnt filter now included.

The addition of .filter(utxos::is_burnt.eq(false)) on line 575 correctly addresses the first concern from the past review, ensuring burnt UTXOs are excluded from the listing.

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

4-4: LGTM: Import additions support new functionality.

The new imports are all utilized in the new handle_create_stealth_transfer_statement function and related changes.

Also applies to: 6-6, 29-29, 33-33, 60-61


367-374: LGTM: Improved error handling with explicit not_found.

The change provides a clearer error message when an account is not found, consistent with similar patterns in handle_get_by_key_index (lines 388-390) and handle_create_or_get (lines 160-162).


551-551: LGTM: More idiomatic single-element iterator construction.

Using iter::once is cleaner than array::from_ref for creating single-element iterators.

Also applies to: 553-553


982-982: LGTM: New field wired through correctly.

The fee_input_selection field is properly threaded from the request to StealthTransferParams.


1077-1089: LGTM: Proper batch size validation.

The validation ensures at least one request and enforces a maximum of 16 requests, which is reasonable for batch processing.


1091-1094: LGTM: Lock guard pattern prevents premature unlock.

Using WalletLockDropGuard ensures outputs remain locked if an error occurs before disarm() is called at line 1184. This is critical for preventing double-spend attempts.


1106-1114: LGTM: Resource stealth validation addressed.

This properly validates that the resource is a stealth resource before proceeding, addressing the concern from the previous review.

Based on learnings


1145-1150: LGTM: Output filtering, collection, and response handling are correct.

  • Outputs are properly filtered for positive blinded amounts (line 1148).
  • Signers and statements are collected correctly (lines 1179-1180).
  • Lock guard is disarmed before returning, leaving outputs locked as intended (line 1184).
  • Response structure matches the binding types.

Also applies to: 1179-1180, 1183-1190

applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx (1)

31-31: Bindings import update looks correct.

Import aligns with the updated wallet-daemon bindings and response shape.

utilities/traffic-sim/src/sim.rs (1)

493-500: Confirm view_key_id = 0 is valid.

Hard-coding 0 assumes the default view key; verify against the wallet daemon API and consider making it configurable.

Would you like me to add a CLI/config option for view_key_id?

Also applies to: 546-553

Comment on lines +38 to 40
maximumExpectedValue: 100000000,
keyId: 0,
});

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

Harden BigInt parsing to avoid runtime crashes on blank/invalid input.

BigInt('') and BigInt(non-integer strings) throw; users can clear or type invalid values. Same risk for keyId; minimumExpectedValue also needs validation.

Apply this diff to use a safe parser with sensible fallbacks:

-      minimum_expected_value: formState.minimumExpectedValue ? BigInt(formState.minimumExpectedValue) : null,
-      maximum_expected_value: BigInt(formState.maximumExpectedValue),
-      view_key_id: BigInt(formState.keyId),
+      minimum_expected_value:
+        formState.minimumExpectedValue === null || formState.minimumExpectedValue === ""
+          ? null
+          : safeBigInt(formState.minimumExpectedValue, null),
+      maximum_expected_value: safeBigInt(formState.maximumExpectedValue, 0n),
+      view_key_id: safeBigInt(formState.keyId, 0n),

Add this helper outside the component (or top of file):

function safeBigInt<T extends string | number | null | undefined>(
  v: T,
  fallback: bigint | null,
): bigint | null {
  if (v === null || v === undefined) return fallback;
  const s = typeof v === "number" ? String(Math.trunc(v)) : v.trim();
  if (!/^-?\d+$/.test(s)) return fallback;
  try { return BigInt(s); } catch { return fallback; }
}

Optional: initialize formState fields as empty strings and set TextField type="number" for numeric inputs to reduce invalid entries.

Also applies to: 47-50

keyId: 0,
});
const [balance, setBalance] = useState<any>(null);
const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse>(null);

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

State type must include null to match initialization and guards.

Initial value is null but the state is typed as non-nullable; this will fail type-checking under strict TS.

Apply this diff:

-  const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse>(null);
+  const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse | null>(null);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse>(null);
const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse | null>(null);
🤖 Prompt for AI Agents
In
applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx
around line 41, the useState is initialized with null but typed as
StealthUtxosDecryptValueResponse (non-nullable), causing strict TypeScript
errors; change the state type to allow null (e.g.,
StealthUtxosDecryptValueResponse | null), and update any downstream usage/guards
to handle the null case (keep existing null checks or add conditional
rendering/early returns where state is accessed).

Comment on lines +138 to +163
let response = Client::new()
.post(&self.swarm_url)
.json(&json!({
"jsonrpc": "2.0",
"method": "list_instances",
"params": { "by_type": "TariWalletDaemon" },
"id": 1,
}))
.send()
.await?;

let swarm_response: serde_json::Value = response.json().await?;
let resp = serde_json::from_value::<SwarmResponse>(
swarm_response
.get("result")
.ok_or_else(|| anyhow::anyhow!("No result field in swarm response"))?
.clone(),
)?;
let addrs = resp.instances.into_iter().filter_map(|instance| {
if !instance.is_running {
log::info!("WARN: stopped wallet instance: {}", instance.name);
}
let rpc_port = instance.ports.get("jrpc")?;
Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port)))
});

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

Harden swarm discovery: add HTTP timeout, handle JSON-RPC errors, and skip stopped instances.

Without a timeout and JSON-RPC error handling, discovery may hang or misparse failures. Also, you log stopped instances but still try to connect to them.

Apply this diff:

-        let response = Client::new()
-            .post(&self.swarm_url)
+        let client = reqwest::Client::builder()
+            .timeout(Duration::from_secs(10))
+            .build()?;
+        let response = client
+            .post(&self.swarm_url)
             .json(&json!({
                 "jsonrpc": "2.0",
                 "method": "list_instances",
                 "params": { "by_type": "TariWalletDaemon" },
                 "id": 1,
             }))
             .send()
             .await?;
 
-        let swarm_response: serde_json::Value = response.json().await?;
+        let swarm_response: serde_json::Value = response.json().await?;
+        if let Some(err) = swarm_response.get("error") {
+            return Err(anyhow::anyhow!(format!("Swarm RPC error: {err}")));
+        }
         let resp = serde_json::from_value::<SwarmResponse>(
             swarm_response
                 .get("result")
                 .ok_or_else(|| anyhow::anyhow!("No result field in swarm response"))?
                 .clone(),
         )?;
-        let addrs = resp.instances.into_iter().filter_map(|instance| {
-            if !instance.is_running {
-                log::info!("WARN: stopped wallet instance: {}", instance.name);
-            }
-            let rpc_port = instance.ports.get("jrpc")?;
-            Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port)))
-        });
+        let addrs = resp.instances.into_iter().filter_map(|instance| {
+            if !instance.is_running {
+                log::warn!("Stopped wallet instance: {}", instance.name);
+                return None;
+            }
+            let rpc_port = instance.ports.get("jrpc")?;
+            Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port)))
+        });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let response = Client::new()
.post(&self.swarm_url)
.json(&json!({
"jsonrpc": "2.0",
"method": "list_instances",
"params": { "by_type": "TariWalletDaemon" },
"id": 1,
}))
.send()
.await?;
let swarm_response: serde_json::Value = response.json().await?;
let resp = serde_json::from_value::<SwarmResponse>(
swarm_response
.get("result")
.ok_or_else(|| anyhow::anyhow!("No result field in swarm response"))?
.clone(),
)?;
let addrs = resp.instances.into_iter().filter_map(|instance| {
if !instance.is_running {
log::info!("WARN: stopped wallet instance: {}", instance.name);
}
let rpc_port = instance.ports.get("jrpc")?;
Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port)))
});
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.build()?;
let response = client
.post(&self.swarm_url)
.json(&json!({
"jsonrpc": "2.0",
"method": "list_instances",
"params": { "by_type": "TariWalletDaemon" },
"id": 1,
}))
.send()
.await?;
let swarm_response: serde_json::Value = response.json().await?;
if let Some(err) = swarm_response.get("error") {
return Err(anyhow::anyhow!(format!("Swarm RPC error: {err}")));
}
let resp = serde_json::from_value::<SwarmResponse>(
swarm_response
.get("result")
.ok_or_else(|| anyhow::anyhow!("No result field in swarm response"))?
.clone(),
)?;
let addrs = resp.instances.into_iter().filter_map(|instance| {
if !instance.is_running {
log::warn!("Stopped wallet instance: {}", instance.name);
return None;
}
let rpc_port = instance.ports.get("jrpc")?;
Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port)))
});
🤖 Prompt for AI Agents
In utilities/traffic-sim/src/sim.rs around lines 138 to 163, the swarm discovery
call lacks an HTTP timeout, doesn't check for JSON-RPC errors in the response,
and still attempts to use stopped instances after only logging them; update the
Client request to set a reasonable timeout (e.g., via
Client::builder().timeout(...)), inspect the parsed JSON for an "error" field
and return a contextual anyhow::Error if present, and filter out instances where
is_running is false (skip them instead of building addresses) while preserving
logging for skipped instances and returning useful errors when parsing or
missing fields occur.

Comment on lines +219 to +221
output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()),
}],
max_fee: 1000,

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

Avoid panic: don’t unwrap Memo::new_message.

Memo::new_message returns Option; unwrap() can panic on oversize strings. Pass the Option directly.

-                    output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()),
+                    output_memo: Memo::new_message(format!("Transfer {id}: {amount_to_send}")),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()),
}],
max_fee: 1000,
output_memo: Memo::new_message(format!("Transfer {id}: {amount_to_send}")),
}],
max_fee: 1000,
🤖 Prompt for AI Agents
In utilities/traffic-sim/src/sim.rs around lines 219–221, the code unwraps
Memo::new_message which returns Option and can panic on oversized strings;
remove the unwrap and pass the Option through directly (e.g., set output_memo to
the result of Memo::new_message(format!(...)) rather than Some(...). This keeps
the field as an Option<Memo> and avoids a potential panic when the message is
too large.

Comment on lines +323 to +324
memo: Some(Memo::new_message(format!("Initial Funding: {fund_amount}")).unwrap()),
}],

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: don’t unwrap Memo::new_message in funding statement.

Same unwrap issue as above.

-                            memo: Some(Memo::new_message(format!("Initial Funding: {fund_amount}")).unwrap()),
+                            memo: Memo::new_message(format!("Initial Funding: {fund_amount}")),

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In utilities/traffic-sim/src/sim.rs around lines 323-324, the code calls
Memo::new_message(...).unwrap() which can panic; replace the unwrap with proper
error handling by propagating the Result (use ? if the surrounding function
returns Result) or by handling the Err case explicitly and returning or logging
an error; ensure the created memo field is constructed from the successful
Result (e.g., memo: Some(Memo::new_message(...)?)) or otherwise handle the error
path instead of unwrapping.

@sdbondi
sdbondi merged commit 4aff521 into tari-project:development Oct 29, 2025
12 checks passed
@sdbondi
sdbondi deleted the util-traffic-sim branch October 29, 2025 07:45
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