Skip to content

feat: add bulk UTXO lock control to Transaction Details (#661)#693

Open
gitsofaryan wants to merge 19 commits intobitcoinppl:masterfrom
gitsofaryan:bulk-utxo-lock-661
Open

feat: add bulk UTXO lock control to Transaction Details (#661)#693
gitsofaryan wants to merge 19 commits intobitcoinppl:masterfrom
gitsofaryan:bulk-utxo-lock-661

Conversation

@gitsofaryan
Copy link
Copy Markdown
Contributor

@gitsofaryan gitsofaryan commented Apr 19, 2026

solves : (#661)

Summary

Implementing a transaction-level bulk lock shortcut in the Transaction Details view. This allows users to quickly secure all unspent outputs created by a specific transaction, preventing them from being automatically spent in future "Send" flows.

Parent Issue

Acceptance Criteria Met

  • Control is hidden when there are no wallet-owned unspent outputs for the transaction.
  • Control shows the correct aggregate state (Unlocked, Locked, Mixed).
  • Tapping in Unlocked or Mixed locks all wallet-owned unspent outputs for that transaction.
  • Tapping in Locked unlocks all wallet-owned unspent outputs for that transaction.
  • External outputs and already-spent outputs are strictly ignored.

Technical Changes

Rust Backend

  • Labels Database: Added set_outputs_spendable for bulk updating the BIP329 spendable flag in OUTPUT_TABLE.
  • Wallet Actor:
    • Implemented compute_lock_state and transaction_lock_state for aggregate analysis.
    • Implemented toggle_transaction_lock with actor-safe logic (avoids self-async-recursion).
    • Scoped operations to list_unspent() to ensure only relevant wallet UTXOs are targeted.
  • FFI: Exposed methods through RustWalletManager and Uniffi.

Android UI

  • TransactionDetailsScreen:
    • Added a reactive lock icon to the CenterAlignedTopAppBar.
    • Premium Animations: Added AnimatedContent for smooth icon transitions.
    • Refresh Logic: Integrated with pull-to-refresh to keep state synchronized.
    • Feedback: Integrated snackbar confirmations for successful toggles.

Testing

  • Verified 3-state logic with various UTXO combinations.
  • Verified that external outputs in a transaction are not labeled or locked.
  • Verified that the icon correctly disappears once all outputs from a transaction are spent.

Platform Coverage

  • Tested on Android simulator

Checklist

Summary by CodeRabbit

  • New Features
    • Transaction lock/unlock control in transaction details, fetched on load and via pull-to-refresh.
    • Visual lock status indicator with animated icon and a warning tint for partial ("Mixed") state.
    • Lock toggle disables during updates and shows success/error snackbars.
    • Locked outputs are excluded from coin selection when creating transactions.

- Implement 3-state aggregate lock logic (Unlocked, Locked, Mixed) in WalletActor
- Add bulk UTXO lock control to Transaction Details Top Bar
- Include snackbar feedback and animated transitions for better UX
- Exclude already-spent and external outputs from the lock scope
- Refresh lock state on screen load and pull-to-refresh
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough
📝 Walkthrough
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature addition: bulk UTXO lock control in Transaction Details view, with a clear reference to the issue.
Description check ✅ Passed The description comprehensively covers summary, technical changes, testing, and acceptance criteria. Platform coverage and checklist items are completed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 19, 2026

Greptile Summary

This PR adds a bulk UTXO lock/unlock control to the Transaction Details screen, scoped to wallet-owned unspent outputs of a specific transaction. The Rust backend introduces compute_lock_state, toggle_transaction_lock, and set_outputs_spendable with correct 3-state (Unlocked/Mixed/Locked) aggregate logic; the Android UI adds an animated lock icon in the top bar with snackbar feedback. All findings are P2 style/cleanup suggestions with no blocking correctness issues.

Confidence Score: 5/5

Safe to merge — all findings are P2 style/efficiency suggestions with no correctness or data-integrity impact.

The core toggle logic is correct, UTXO scoping via list_unspent() is correct, and FFI wiring is straightforward. The four findings are unused variable, polling-loop staleness, a redundant BDK scan, and unnecessary no-op DB records — none affect correctness or data integrity.

No files require special attention for merge safety.

Important Files Changed

Filename Overview
android/app/src/main/java/org/bitcoinppl/cove/flows/SelectedWalletFlow/TransactionDetails/TransactionDetailsScreen.kt Adds reactive lock icon to the top app bar with AnimatedContent transitions; lock state fetched on load and pull-to-refresh but not inside the background polling loop, and an unused previousState variable is declared.
rust/src/manager/wallet_manager/actor.rs Implements transaction_lock_state, toggle_transaction_lock, compute_lock_state, and wallet_unspent_outputs_for_tx; logic is correct but wallet_unspent_outputs_for_tx is called twice inside toggle_transaction_lock.
rust/src/database/wallet_data/label.rs Adds set_outputs_spendable for bulk spendable flag updates; creates unnecessary no-op records when unlocking outputs that have no existing label record.
rust/src/transaction/transaction_details.rs Introduces TransactionLockState enum (Unlocked, Locked, Mixed, None) as a uniffi-exported type; straightforward and correct.
rust/src/manager/wallet_manager.rs Exposes transaction_lock_state and toggle_transaction_lock through RustWalletManager as uniffi async methods; wiring is correct.

Comments Outside Diff (1)

  1. android/app/src/main/java/org/bitcoinppl/cove/flows/SelectedWalletFlow/TransactionDetails/TransactionDetailsScreen.kt, line 188-231 (link)

    P2 Lock state not refreshed in background polling loop

    The LaunchedEffect(txId) polling loop refreshes transaction details and confirmation counts on a regular interval but never updates lockState. If a UTXO becomes spent while the screen is open (e.g., another outgoing transaction confirms), the lock icon can remain visible with a stale state until the user manually pulls to refresh. Consider adding lockState = manager.rust.transactionLockState(txId = txId) alongside the existing manager.updateTransactionDetailsCache(...) call inside the polling loop body.

Reviews (1): Last reviewed commit: "feat: add bulk UTXO lock control to Tran..." | Re-trigger Greptile

IconButton(onClick = {
scope.launch {
try {
val previousState = lockState
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Unused previousState variable

previousState is assigned from lockState but is never read afterward — the snackbar message is derived from newState. This will generate a Kotlin compiler warning and can be removed.

Suggested change
val previousState = lockState
try {
manager.rust.toggleTransactionLock(txId = txId)

Comment thread rust/src/manager/wallet_manager/actor.rs
Comment thread rust/src/database/wallet_data/label.rs Outdated
Comment on lines +362 to +368
let mut record = table.get(key.clone())?.map(|r| r.value()).unwrap_or_else(|| {
Record::new(OutputRecord {
ref_: outpoint,
label: None,
spendable: true,
})
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 No-op records written during bulk unlock

When set_outputs_spendable is called with spendable = true (unlock path) and an outpoint has no existing record, a new OutputRecord is created with spendable: true — which is the default. This writes a semantically empty record to the database, adding unnecessary cloud-backup churn. A small guard would avoid the write:

let existing = table.get(key.clone())?.map(|r| r.value());
let mut record = match existing {
    Some(r) => r,
    None => {
        if spendable { continue; }
        Record::new(OutputRecord { ref_: outpoint, label: None, spendable: true })
    }
};

- Implement 3-state aggregate lock logic (Unlocked, Locked, Mixed) in WalletActor
- Add bulk UTXO lock control to Transaction Details Top Bar
- Include snackbar feedback and animated transitions for better UX
- Exclude already-spent and external outputs from the lock scope
- Refresh lock state on screen load and pull-to-refresh
IconButton(onClick = {
scope.launch {
try {
<<<<<<< HEAD
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.

conflicts

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SelectedWalletFlow/TransactionDetails/TransactionDetailsScreen.kt`:
- Around line 349-399: Add a local boolean "isToggling" state and guard the
IconButton so it is disabled while a toggle is in flight: set isToggling = true
immediately before calling manager.rust.toggleTransactionLock(txId = txId) in
the scope.launch block and ensure you set isToggling = false in a finally block
after the network call (both on success and in the catch). Update the IconButton
to pass enabled = !isToggling (or return early from onClick when isToggling),
keep updating lockState from manager.rust.transactionLockState(txId = txId) and
showing snackbars as before; optionally show a small progress indicator when
isToggling is true.

In `@rust/src/database/wallet_data/label.rs`:
- Line 367: The changed region around the `if spendable {` hunk fails rustfmt;
run rustfmt (e.g., cargo fmt) and reformat the block so it conforms to the
project's formatting rules, then update the PR with the formatted code ensuring
the `if spendable {` block and surrounding lines match rustfmt's output.
- Around line 350-392: set_outputs_spendable currently leaves synthetic empty
OutputRecord rows (label: None) behind when unlocking outputs; update it so when
spendable is true and an existing record has label == None you remove the row
instead of updating/inserting it. In the loop inside set_outputs_spendable
(using OutPointKey, OUTPUT_TABLE, Record/OutputRecord and table variable) check
for Some(record) with record.item.label.is_none() && spendable == true and call
table.remove(key) (instead of modifying/inserting), preserving the existing
behavior that continues when there is no record and spendable is true.
- Around line 212-221: The locked_outpoints function currently swallows
iteration errors via filter_map(|r| r.ok()), which can hide unreadable/corrupt
record errors; change the iteration to propagate errors so callers get a
Result::Err on read failures: after read_table(OUTPUT_TABLE)? call table.iter()?
and instead of filter_map(|r| r.ok()) use a fallible mapping that returns Err
when any r is Err (e.g., map(|r| r?) or collect into Result) so the function
returns the first iteration/read error rather than silently dropping records;
keep the existing filtering of !r.item.spendable and mapping to r.item.ref_ but
ensure the final collect produces Result<Vec<bitcoin::OutPoint>, Error> from
locked_outpoints.

In `@rust/src/manager/wallet_manager.rs`:
- Around line 591-596: The current WalletManager::toggle_transaction_lock uses
call!(self.actor.toggle_transaction_lock(Arc::unwrap_or_clone(tx_id))).await but
ignores the inner Result returned by WalletActor::toggle_transaction_lock, so DB
write errors are lost; change the flow to await the call!, map the outer call
failure to Error as you already do, then inspect and propagate the inner Result
from WalletActor::toggle_transaction_lock (e.g. use ? on that inner Result or
map its Err into your uniffi Error) so any actor-level application error is
returned to the caller instead of being treated as success; keep the
Arc::unwrap_or_clone(tx_id) and the call! invocation but ensure both the call!
failure and the actor method’s Result are converted into the method’s Result<(),
Error> and returned.

In `@rust/src/manager/wallet_manager/actor.rs`:
- Around line 322-346: The hunk in the async method toggle_transaction_lock has
formatting issues flagged by rustfmt; run rustfmt on the file or reformat the
function body to match project style (consistent indentation, spacing around
operators and arrows, and blank lines). Specifically, reformat the
toggle_transaction_lock function (including the let outputs = ..., the if
outputs.is_empty() block, the current_state calculation, the spendable
assignment, the chained DB call to
labels.set_outputs_spendable(...).map_err_str(...), and the
CLOUD_BACKUP_MANAGER.handle_wallet_backup_change(...) call) so it passes
rustfmt.
- Around line 317-371: compute_lock_state currently swallows DB errors by
treating get_output_record errors as None; change its signature to fn
compute_lock_state(&self, outputs: &[OutPoint]) -> Result<TransactionLockState,
Error> and return Err when any self.db.labels.get_output_record(outpoint) fails,
preserving existing semantics for empty outputs; update callers
transaction_lock_state and toggle_transaction_lock to propagate the Result
(i.e., transaction_lock_state should return ActorResult<TransactionLockState> by
returning Produces::ok(...) or an Err on DB failure, and toggle_transaction_lock
should early-return Err on compute_lock_state failure before deciding spendable
and calling self.db.labels.set_outputs_spendable and
CLOUD_BACKUP_MANAGER.handle_wallet_backup_change) so that DB read errors do not
silently mark outputs as unlocked.
- Around line 322-339: toggle_transaction_lock only updates labels but
transaction construction via build_tx (call site: self.wallet.bdk.build_tx())
still uses all UTXOs; ensure locked outputs are excluded by making the
coin-selection path consult the label DB. Change the coin selection wrapper
CoveDefaultCoinSelection (or the build_tx wrapper) to call the label DB method
locked_outpoints() and filter those out of the UTXO set passed into BDK (or set
the spendable flag when constructing the tx request), so BDK's default algorithm
never sees label-marked locked outputs; update references to
wallet.bdk.build_tx() to use the filtered UTXO list or a selection hook that
respects labels.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1d95d31e-072f-43fa-bc1e-f6395fc8c3ad

📥 Commits

Reviewing files that changed from the base of the PR and between ba61cd2 and 20f3eb0.

📒 Files selected for processing (6)
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SelectedWalletFlow/TransactionDetails/TransactionDetailsScreen.kt
  • rust/src/database/wallet_data/label.rs
  • rust/src/manager/wallet_manager.rs
  • rust/src/manager/wallet_manager/actor.rs
  • rust/src/transaction.rs
  • rust/src/transaction/transaction_details.rs

Comment thread rust/src/database/wallet_data/label.rs
Comment thread rust/src/database/wallet_data/label.rs
Comment thread rust/src/database/wallet_data/label.rs
Comment thread rust/src/manager/wallet_manager.rs
Comment thread rust/src/manager/wallet_manager/actor.rs Outdated
Comment thread rust/src/manager/wallet_manager/actor.rs
Comment thread rust/src/manager/wallet_manager/actor.rs
@gitsofaryan
Copy link
Copy Markdown
Contributor Author

Hey @praveenperera the Rust changes are all passing (clippy, rustfmt, tests), but the Android/iOS binding regeneration requires just build-android (Linux + NDK) and just build-ios (macOS), which I can't run from my Windows dev environment.

Would it be okay if I set up a CI workflow (or a manual workflow_dispatch) that auto-regenerates the UniFFI bindings when Rust source changes? This would help any contributor who doesn't have the full cross-platform toolchain locally.

@praveenperera
Copy link
Copy Markdown
Contributor

@gitsofaryan ya thats sounds good, make it manual and have it commit the generated files after running, thanks

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
.github/workflows/regenerate-bindings.yml (1)

52-52: Heads-up: commits pushed with GITHUB_TOKEN will not trigger downstream workflows.

By GitHub's default, events triggered by the built-in GITHUB_TOKEN do not kick off other workflows (no PR checks / CI will re-run on the regenerated-bindings commits). For a manual workflow_dispatch that lands on a feature branch this is usually desired, but contributors should be aware the regenerated commit will not re-trigger the standard PR validation. If re-running PR checks on the auto-commit is desired, use a PAT or GitHub App token instead.

Also applies to: 89-89

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/regenerate-bindings.yml at line 52, The workflow currently
uses the built-in GITHUB_TOKEN for the git push step which prevents downstream
workflows from being triggered; replace the push authentication to use a
repository secret holding a PAT or a GitHub App installation token (e.g.,
SECRET_PAT) instead of GITHUB_TOKEN, update the git push step that contains "git
push" to authenticate with that secret, and ensure the workflow-level
permissions include write access to contents (permissions: contents: write) so
the PAT/App token can push and trigger downstream workflows again.
android/app/src/main/java/org/bitcoinppl/cove/flows/SelectedWalletFlow/TransactionDetails/TransactionDetailsScreen.kt (1)

363-374: Localize snackbar messages and content descriptions.

"Transaction outputs locked", "Transaction outputs unlocked", "Remaining outputs locked", "Failed to update lock state", and the contentDescription values ("Unlock all outputs", "Lock remaining outputs", "Lock all outputs") are hardcoded English. Content descriptions in particular are read aloud by TalkBack, so they should go through stringResource(...). Not a regression (file already has some hardcoded strings), but worth adding with this feature while string IDs are still fresh.

Also applies to: 397-401

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SelectedWalletFlow/TransactionDetails/TransactionDetailsScreen.kt`
around lines 363 - 374, Replace the hardcoded snackbar messages and TalkBack
contentDescription literals with localized string resources: use
stringResource(...) for the messages produced in the TransactionLockState
when-block (the "Transaction outputs locked", "Transaction outputs unlocked",
"Remaining outputs locked" branches) and for the error snackbar in the catch
("Failed to update lock state"), and replace the hardcoded contentDescription
values ("Unlock all outputs", "Lock remaining outputs", "Lock all outputs") with
stringResource(...) calls; add corresponding entries to strings.xml (e.g.,
tx_outputs_locked, tx_outputs_unlocked, tx_remaining_locked,
tx_lock_update_failed, tx_cd_unlock_all, tx_cd_lock_remaining, tx_cd_lock_all)
and ensure you import androidx.compose.ui.res.stringResource and use those
stringResource(...) references in the UI (also update the other occurrence
mentioned around lines ~397-401).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rust/src/manager/wallet_manager/actor.rs`:
- Around line 322-341: Replace the explicit closure-based error mappings in
transaction_lock_state and toggle_transaction_lock that use .map_err(|e|
Error::UnknownError(e.to_string())) with the repo utility .map_err_str from
cove_util::ResultExt (ResultExt is already imported in this file); update the
two calls inside functions transaction_lock_state and toggle_transaction_lock so
they call .map_err_str(Error::UnknownError) instead of the closure to follow the
repo convention.
- Around line 197-199: The current code calls
self.db.labels.locked_outpoints().unwrap_or_default() which masks DB errors and
can let locked UTXOs be spent; change both build_tx (the tx construction path
shown) and build_ephemeral_drain_tx to propagate the error instead of
defaulting: call self.db.labels.locked_outpoints()?, map its Err into the
appropriate BuildTxError (or return the existing error type used by
compute_lock_state) and return early on failure so tx_builder.unspendable only
receives a definitive list; mirror the error-handling and return-path used by
compute_lock_state to ensure DB read failures surface to the caller.
- Around line 197-199: The missing helper methods (self.do_build_tx,
self.do_build_manual_tx, self.do_build_ephemeral_tx,
self.do_build_ephemeral_drain_tx, self.do_build_manual_ephemeral_tx) must be
implemented as async functions that create and return the same transaction
builders/results as their callers expect; each must fetch locked_outpoints
exactly like the public path (e.g., let locked_outpoints =
self.db.labels.locked_outpoints().unwrap_or_default()) and apply
tx_builder.unspendable(locked_outpoints) to the builder before finishing, so
ephemeral/manual builds respect locked UTXO filtering and avoid fee/UTXO
disagreements when callers use .await?.

---

Nitpick comments:
In @.github/workflows/regenerate-bindings.yml:
- Line 52: The workflow currently uses the built-in GITHUB_TOKEN for the git
push step which prevents downstream workflows from being triggered; replace the
push authentication to use a repository secret holding a PAT or a GitHub App
installation token (e.g., SECRET_PAT) instead of GITHUB_TOKEN, update the git
push step that contains "git push" to authenticate with that secret, and ensure
the workflow-level permissions include write access to contents (permissions:
contents: write) so the PAT/App token can push and trigger downstream workflows
again.

In
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SelectedWalletFlow/TransactionDetails/TransactionDetailsScreen.kt`:
- Around line 363-374: Replace the hardcoded snackbar messages and TalkBack
contentDescription literals with localized string resources: use
stringResource(...) for the messages produced in the TransactionLockState
when-block (the "Transaction outputs locked", "Transaction outputs unlocked",
"Remaining outputs locked" branches) and for the error snackbar in the catch
("Failed to update lock state"), and replace the hardcoded contentDescription
values ("Unlock all outputs", "Lock remaining outputs", "Lock all outputs") with
stringResource(...) calls; add corresponding entries to strings.xml (e.g.,
tx_outputs_locked, tx_outputs_unlocked, tx_remaining_locked,
tx_lock_update_failed, tx_cd_unlock_all, tx_cd_lock_remaining, tx_cd_lock_all)
and ensure you import androidx.compose.ui.res.stringResource and use those
stringResource(...) references in the UI (also update the other occurrence
mentioned around lines ~397-401).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b39255af-8da2-4197-abee-3a4191fa18f8

📥 Commits

Reviewing files that changed from the base of the PR and between 20f3eb0 and 45e79fe.

📒 Files selected for processing (5)
  • .github/workflows/regenerate-bindings.yml
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SelectedWalletFlow/TransactionDetails/TransactionDetailsScreen.kt
  • rust/src/database/wallet_data/label.rs
  • rust/src/manager/wallet_manager.rs
  • rust/src/manager/wallet_manager/actor.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • rust/src/database/wallet_data/label.rs

Comment thread rust/src/manager/wallet_manager/actor.rs Outdated
Comment thread rust/src/manager/wallet_manager/actor.rs Outdated
@praveenperera
Copy link
Copy Markdown
Contributor

@gitsofaryan open a new PR for the github ci changes

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
rust/src/manager/wallet_manager/actor.rs (1)

351-352: Minor: prefer a use over the fully-qualified path.

Resolving crate::manager::cloud_backup_manager::CLOUD_BACKUP_MANAGER inline is noisy; a top-of-file use (or at least a scoped one) reads more cleanly and matches the rest of the imports in this module. Non-blocking.

♻️ Proposed refactor
@@ top of file imports
+use super::cloud_backup_manager::CLOUD_BACKUP_MANAGER;
@@ toggle_transaction_lock
-        crate::manager::cloud_backup_manager::CLOUD_BACKUP_MANAGER
-            .handle_wallet_backup_change(self.wallet.id.clone());
+        CLOUD_BACKUP_MANAGER.handle_wallet_backup_change(self.wallet.id.clone());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust/src/manager/wallet_manager/actor.rs` around lines 351 - 352, Replace the
fully-qualified call to
crate::manager::cloud_backup_manager::CLOUD_BACKUP_MANAGER.handle_wallet_backup_change(...)
with a simple reference by adding a use for CLOUD_BACKUP_MANAGER (e.g. add `use
crate::manager::cloud_backup_manager::CLOUD_BACKUP_MANAGER;` near the top of the
module or a scoped use) and then call
CLOUD_BACKUP_MANAGER.handle_wallet_backup_change(self.wallet.id.clone()); keep
the existing handle_wallet_backup_change and CLOUD_BACKUP_MANAGER identifiers
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rust/src/manager/wallet_manager/actor.rs`:
- Line 197: The DB call mapping in build_tx incorrectly maps a failure of
self.db.labels.locked_outpoints() to Error::UnknownError; change the error
mapping to Error::BuildTxError so DB failures during transaction construction
are classified as tx-build errors. Update the map_err_str on the
locked_outpoints() call in build_tx (and the similar mapping at the other
build_tx location around line 220) to return Error::BuildTxError, keeping the
existing error text handling.

---

Nitpick comments:
In `@rust/src/manager/wallet_manager/actor.rs`:
- Around line 351-352: Replace the fully-qualified call to
crate::manager::cloud_backup_manager::CLOUD_BACKUP_MANAGER.handle_wallet_backup_change(...)
with a simple reference by adding a use for CLOUD_BACKUP_MANAGER (e.g. add `use
crate::manager::cloud_backup_manager::CLOUD_BACKUP_MANAGER;` near the top of the
module or a scoped use) and then call
CLOUD_BACKUP_MANAGER.handle_wallet_backup_change(self.wallet.id.clone()); keep
the existing handle_wallet_backup_change and CLOUD_BACKUP_MANAGER identifiers
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 14d488f9-f446-4846-aaf1-33016b19fc84

📥 Commits

Reviewing files that changed from the base of the PR and between 45e79fe and 0855a1c.

📒 Files selected for processing (1)
  • rust/src/manager/wallet_manager/actor.rs

Comment thread rust/src/manager/wallet_manager/actor.rs Outdated
@gitsofaryan gitsofaryan mentioned this pull request Apr 23, 2026
7 tasks
@gitsofaryan
Copy link
Copy Markdown
Contributor Author

@praveenperera cc : #704

@praveenperera
Copy link
Copy Markdown
Contributor

@gitsofaryan merge master and resolve conflicts

@praveenperera
Copy link
Copy Markdown
Contributor

can you use the new ci action on your fork to regen the bindings now? @gitsofaryan

@gitsofaryan
Copy link
Copy Markdown
Contributor Author

Just merged master! I'm triggering the Regenerate Bindings workflow on my fork for this branch now. Once the bot commits the fresh bindings, the CI should turn green.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
rust/src/manager/wallet_manager/actor.rs (1)

334-403: Lock-state actor methods look correct.

  • 3-state toggle logic at Line 356 (Locked → unlock; Unlocked/Mixed → lock) matches the acceptance criteria.
  • Empty-output early return at Lines 348-350 avoids spurious DB writes and cloud-backup notifications.
  • compute_lock_state now propagates label-DB read errors via Result<_, label::Error> (no more fail-open) and the callers map to Error::UnknownError per guideline.
  • wallet_unspent_outputs_for_tx correctly scopes to wallet-owned, still-unspent outputs of the given txid, honoring the "external outputs and already-spent outputs are ignored" requirement.
  • Since the actor serializes messages, the read-in-compute_lock_state / write-in-set_outputs_spendable sequence is free from intra-actor TOCTOU.

One very minor, optional efficiency note: compute_lock_state opens a new read transaction per outpoint via get_output_record. For typical txs with a handful of outputs this is negligible, but if you ever want to consolidate, a single read-table scan (or reusing locked_outpoints() as a HashSet lookup) would fold all N lookups into one table open. Not worth changing now.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust/src/manager/wallet_manager/actor.rs` around lines 334 - 403, The review
finds no functional issues: the actor methods transaction_lock_state,
toggle_transaction_lock, compute_lock_state, and wallet_unspent_outputs_for_tx
are correct and follow requirements (3-state toggle, early return on empty
outputs, proper error propagation and wallet-scoped UTXO filtering); no code
changes required—merge as-is, optional future optimization: consolidate
per-outpoint DB reads in compute_lock_state into a single scan or HashSet lookup
if you later profile it as a hotspot.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@rust/src/manager/wallet_manager/actor.rs`:
- Around line 334-403: The review finds no functional issues: the actor methods
transaction_lock_state, toggle_transaction_lock, compute_lock_state, and
wallet_unspent_outputs_for_tx are correct and follow requirements (3-state
toggle, early return on empty outputs, proper error propagation and
wallet-scoped UTXO filtering); no code changes required—merge as-is, optional
future optimization: consolidate per-outpoint DB reads in compute_lock_state
into a single scan or HashSet lookup if you later profile it as a hotspot.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 332db88e-aaa3-4c46-908a-233d88c76780

📥 Commits

Reviewing files that changed from the base of the PR and between 0855a1c and b6344a4.

📒 Files selected for processing (2)
  • rust/src/manager/wallet_manager.rs
  • rust/src/manager/wallet_manager/actor.rs

@gitsofaryan
Copy link
Copy Markdown
Contributor Author

@praveenperera LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants