Skip to content

feat(key-wallet): dashpay contact account funding - #929

Merged
QuantumExplorer merged 3 commits into
devfrom
feat/dashpay-contact-account-funding
Aug 7, 2026
Merged

feat(key-wallet): dashpay contact account funding#929
QuantumExplorer merged 3 commits into
devfrom
feat/dashpay-contact-account-funding

Conversation

@ZocoLini

@ZocoLini ZocoLini commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Adds three AccountTypePreference sources for the coins DashPay contacts sent us —
DashpayFriendshipReceivingFunds (one contact under one of our identities),
DashpayIdentityReceivingFunds (every contact of one identity) and
AllDashpayReceivingFunds — each spanning every account index those accounts sit at.
Only the receiving side — a DashpayExternalAccount holds the contact's own coins — and
they stay out of the default source list, which cannot guess whose funds to spend.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added precise selection of Standard, CoinJoin, and DashPay funds-bearing accounts.
    • Transactions can now draw funds from multiple account sources.
    • Added DashPay friendship, identity, and all-contact receiving-funds options.
    • Added unsigned transaction building while preserving signing information.
  • Bug Fixes

    • Improved account availability and network validation during transaction creation.
    • Prevented address generation for unsupported DashPay account types.
    • Improved handling of specialized account selections across multiple indices.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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

Transaction building now accepts multiple account preferences, including DashPay receiving-funds selectors. The wallet resolves matching accounts, pools UTXOs, preserves derivation paths, and supports unsigned transactions. Account lookup and address handling now cover the supported account types.

Changes

Multi-account funding and account resolution

Layer / File(s) Summary
Exact funds-account resolution
key-wallet/src/managed_account/managed_account_collection.rs, key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs
Managed account collections provide immutable and mutable exact-type lookups for standard, CoinJoin, and DashPay funds accounts. Unsupported account types return None.
DashPay preferences and address handling
key-wallet/src/wallet/managed_wallet_info/transaction_building.rs, key-wallet/src/wallet/managed_wallet_info/mod.rs
Transaction preferences support DashPay receiving-funds accounts identified by user and contact identities. Contact accounts do not produce index-based receive or change addresses.
Multi-source transaction construction
key-wallet/src/wallet/managed_wallet_info/transaction_building.rs
Transaction building accepts multiple preferences, resolves matching accounts, pools UTXOs, preserves derivation paths, and supports unsigned transactions. Tests cover standard and DashPay funding across account indices.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WalletInfoInterface
  participant ManagedWalletInfo
  participant ManagedAccountCollection
  participant TransactionBuilder
  WalletInfoInterface->>ManagedWalletInfo: provide account preference slice
  ManagedWalletInfo->>ManagedAccountCollection: resolve funds accounts
  ManagedWalletInfo->>TransactionBuilder: pool UTXOs from resolved accounts
  TransactionBuilder->>ManagedAccountCollection: collect derivation paths and change data
  TransactionBuilder-->>ManagedWalletInfo: return signed or unsigned transaction
Loading

Possibly related PRs

Suggested labels: ready-for-review

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding DashPay contact account funding support.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/dashpay-contact-account-funding

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

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs (1)

500-507: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Correct the release guidance: one account no longer holds the whole reservation.

assemble_unsigned now reserves each account's own share of the selected inputs in that account's ReservationSet. The first funding account holds only the outpoints it contributed. A caller that follows this doc and releases on the first funding account alone leaves every other contributing account's inputs reserved until the 24-block TTL sweep reclaims them.

State that the caller must call release_reservation_if_owner on every account that funded the build, as build_signed_reserved already does at Lines 571-574.

📝 Proposed doc fix
-    /// [`ManagedCoreFundsAccount::release_reservation_if_owner`] on the first
-    /// funding account, whose set holds the whole build's reservation. See
+    /// [`ManagedCoreFundsAccount::release_reservation_if_owner`] on *every*
+    /// account passed to [`Self::add_funding`]: each one reserves only the
+    /// inputs it contributed, so releasing on one account leaves the rest
+    /// reserved until the TTL backstop reclaims them. See
     /// `ReservationSet::release_if_owner` for why owner-guarded release is
     /// required (`dashpay/platform#4185`).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs` around
lines 500 - 507, Update the documentation for the reservation token near
assemble_unsigned to state that callers must invoke
ManagedCoreFundsAccount::release_reservation_if_owner on every funding account
that contributed inputs, not only the first account. Align the guidance with the
existing build_signed_reserved release behavior.
🧹 Nitpick comments (3)
key-wallet/src/managed_account/managed_account_collection.rs (1)

621-621: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the catch-all arm with explicit non-funds variants.

_ => None also absorbs any future funds-bearing AccountType variant. Such a variant would then silently return no funding account instead of failing to compile. List the keys-only and PlatformPayment variants explicitly so the compiler flags new variants here. insert_funds_bearing_account already handles PlatformPayment explicitly, so the two methods would also stay aligned.

Also applies to: 663-663

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@key-wallet/src/managed_account/managed_account_collection.rs` at line 621,
Replace the catch-all `_ => None` arms in the affected account-type matching
methods with explicit keys-only variants and `PlatformPayment`, matching the
variants handled by `insert_funds_bearing_account`. Preserve the existing `None`
behavior while making future funds-bearing variants require a compile-time match
update.
key-wallet/src/wallet/managed_wallet_info/transaction_building.rs (1)

130-147: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Expose the reservation token for unsigned builds.

build_unsigned_transaction discards the ReservationToken returned by build_unsigned_reserved. A caller that abandons the unsigned transaction cannot then call release_if_owner, so the selected inputs stay reserved until the 24-block TTL sweep reclaims them. The doc comment states this, but the signed path already returns the token through build_signed_reserved.

Add a build_unsigned_transaction_reserved variant that returns the token, and keep this method as the convenience wrapper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@key-wallet/src/wallet/managed_wallet_info/transaction_building.rs` around
lines 130 - 147, Add a `build_unsigned_transaction_reserved` method alongside
`build_unsigned_transaction` that performs the existing builder flow and returns
`(Transaction, u64, ReservationToken)` from `build_unsigned_reserved`. Update
`build_unsigned_transaction` to remain the convenience wrapper by delegating to
the reserved variant and discarding only the token; preserve its current return
type and behavior.
key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs (1)

105-136: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Deduplicate funding candidates and clarify change selection.

Exclude outpoints already present in self.inputs before extending it. Coin selection does not deduplicate candidates, and assembly can emit duplicate transaction inputs. Repeated sources can reach this path.

Update the documentation to state that the first funding account that successfully generates a change address supplies change. DashPay accounts return Err from next_change_address, so a later standard account can provide it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs` around
lines 105 - 136, Update add_funding to filter candidates whose outpoints already
exist in self.inputs before extending the input set or recording funding
metadata. Revise the surrounding documentation so change comes from the first
funding account that successfully generates an address, allowing later accounts
to provide it when next_change_address returns Err.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@key-wallet/src/wallet/managed_wallet_info/transaction_building.rs`:
- Around line 236-289: The funding flow around fund must cover the DashPay-only
source case where change exceeds dust: add a regression test demonstrating the
current NoChangeAddress result, or document and enforce that a standard account
source is required for change. Use the existing account-preference and
transaction-building test setup, and ensure mixed sources with a standard
account retain valid change behavior.

---

Outside diff comments:
In `@key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs`:
- Around line 500-507: Update the documentation for the reservation token near
assemble_unsigned to state that callers must invoke
ManagedCoreFundsAccount::release_reservation_if_owner on every funding account
that contributed inputs, not only the first account. Align the guidance with the
existing build_signed_reserved release behavior.

---

Nitpick comments:
In `@key-wallet/src/managed_account/managed_account_collection.rs`:
- Line 621: Replace the catch-all `_ => None` arms in the affected account-type
matching methods with explicit keys-only variants and `PlatformPayment`,
matching the variants handled by `insert_funds_bearing_account`. Preserve the
existing `None` behavior while making future funds-bearing variants require a
compile-time match update.

In `@key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs`:
- Around line 105-136: Update add_funding to filter candidates whose outpoints
already exist in self.inputs before extending the input set or recording funding
metadata. Revise the surrounding documentation so change comes from the first
funding account that successfully generates an address, allowing later accounts
to provide it when next_change_address returns Err.

In `@key-wallet/src/wallet/managed_wallet_info/transaction_building.rs`:
- Around line 130-147: Add a `build_unsigned_transaction_reserved` method
alongside `build_unsigned_transaction` that performs the existing builder flow
and returns `(Transaction, u64, ReservationToken)` from
`build_unsigned_reserved`. Update `build_unsigned_transaction` to remain the
convenience wrapper by delegating to the reserved variant and discarding only
the token; preserve its current return type and behavior.
🪄 Autofix

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 Plus

Run ID: 4322716a-03c5-4696-b5e5-35850ee90ba0

📥 Commits

Reviewing files that changed from the base of the PR and between 2b1f744 and ddbaf6b.

📒 Files selected for processing (11)
  • dash-spv/tests/dashd_sync/tests_transaction.rs
  • key-wallet-ffi/src/transaction.rs
  • key-wallet-manager/src/lib.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/reservation.rs
  • key-wallet/src/tests/spent_outpoints_tests.rs
  • key-wallet/src/wallet/managed_wallet_info/asset_lock_builder.rs
  • key-wallet/src/wallet/managed_wallet_info/mod.rs
  • key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs
  • key-wallet/src/wallet/managed_wallet_info/transaction_building.rs
  • key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs

Comment thread key-wallet/src/wallet/managed_wallet_info/transaction_building.rs
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.07087% with 43 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.30%. Comparing base (09904a6) to head (9f5b1d2).

Files with missing lines Patch % Lines
.../src/managed_account/managed_account_collection.rs 46.34% 22 Missing ⚠️
...wallet/managed_wallet_info/transaction_building.rs 91.86% 17 Missing ⚠️
key-wallet/src/wallet/managed_wallet_info/mod.rs 0.00% 2 Missing ⚠️
...allet/managed_wallet_info/wallet_info_interface.rs 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #929      +/-   ##
==========================================
+ Coverage   75.23%   75.30%   +0.07%     
==========================================
  Files         328      328              
  Lines       77767    77982     +215     
==========================================
+ Hits        58507    58726     +219     
+ Misses      19260    19256       -4     
Flag Coverage Δ
core 77.29% <ø> (ø)
ffi 49.85% <ø> (+<0.01%) ⬆️
rpc 20.00% <ø> (ø)
spv 91.36% <ø> (-0.04%) ⬇️
wallet 76.85% <83.07%> (+0.26%) ⬆️
Files with missing lines Coverage Δ
key-wallet/src/wallet/managed_wallet_info/mod.rs 74.22% <0.00%> (-0.78%) ⬇️
...allet/managed_wallet_info/wallet_info_interface.rs 77.20% <0.00%> (+0.84%) ⬆️
...wallet/managed_wallet_info/transaction_building.rs 93.52% <91.86%> (-0.29%) ⬇️
.../src/managed_account/managed_account_collection.rs 63.07% <46.34%> (+0.31%) ⬆️

... and 8 files with indirect coverage changes

@ZocoLini
ZocoLini force-pushed the feat/dashpay-contact-account-funding branch from ddbaf6b to 38a9519 Compare August 7, 2026 08:32
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 7, 2026
@github-actions github-actions Bot added the ready-for-review CodeRabbit has approved this PR label Aug 7, 2026
@ZocoLini
ZocoLini force-pushed the feat/dashpay-contact-account-funding branch from 38a9519 to b481600 Compare August 7, 2026 09:17
@github-actions github-actions Bot removed the ready-for-review CodeRabbit has approved this PR label Aug 7, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 7, 2026
@github-actions github-actions Bot added the ready-for-review CodeRabbit has approved this PR label Aug 7, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 7, 2026
@github-actions github-actions Bot removed the ready-for-review CodeRabbit has approved this PR label Aug 7, 2026
@ZocoLini
ZocoLini force-pushed the feat/dashpay-contact-account-funding branch from f199177 to 3cf2653 Compare August 7, 2026 10:49
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 7, 2026
@ZocoLini
ZocoLini force-pushed the feat/dashpay-contact-account-funding branch from 3cf2653 to 229b671 Compare August 7, 2026 10:51
@ZocoLini
ZocoLini marked this pull request as draft August 7, 2026 11:29
ZocoLini and others added 2 commits August 7, 2026 04:38
Funds received from a DashPay contact (DIP-15) were unreachable from
`build_and_sign_transaction`: `AccountTypePreference` only named the
standard families, so a contact account could hold a balance the wallet
could never spend.

`AccountTypePreference::DashpayReceivingFunds` names one contact by its
identity pair. A contact may hold funds at several account indices, so the
source covers all of them and ignores `source_index` — unlike the standard
families, an index alone does not identify a contact account. Only the
receiving side is offered: a `DashpayExternalAccount` tracks what we sent
*to* the contact and its keys are theirs, so it can never fund a spend of
ours. Contact accounts also stay out of the implicit (empty) source list,
which cannot guess which contact to spend from.

The account lookup now goes through `AccountType`, which both sides of the
wallet already key on: `AccountCollection::account_of_type` on the wallet
side, and a new `ManagedAccountCollection::funds_account{,_mut}` on the
managed side, which addresses any funds-bearing account including the
DashPay ones (keyed by identity pair plus index).

Contact accounts keep a single address pool with no internal branch, so
they cannot supply change: a contact-only build fails with
`NoChangeAddress` unless a Standard account comes along to take it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ToH2xGXqVcxiwMkNYaWkh7
@ZocoLini
ZocoLini force-pushed the feat/dashpay-contact-account-funding branch from 229b671 to 9f5b1d2 Compare August 7, 2026 12:02
@ZocoLini
ZocoLini marked this pull request as ready for review August 7, 2026 12:02
@QuantumExplorer
QuantumExplorer merged commit 944e53a into dev Aug 7, 2026
37 checks passed
@QuantumExplorer
QuantumExplorer deleted the feat/dashpay-contact-account-funding branch August 7, 2026 12:12
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