Skip to content

fix(platform-wallet): build our receiving account for one-way DashPay contacts - #5256

Open
HashEngineering wants to merge 8 commits into
v5.1-devfrom
fix/dashpay-one-way-contact-receival
Open

HashEngineering wants to merge 8 commits into
v5.1-devfrom
fix/dashpay-one-way-contact-receival

Conversation

@HashEngineering

@HashEngineering HashEngineering commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

Suppose we send a DashPay contact request and the contact never sends one back. That contact never got a DashpayReceivingFunds account. DIP-15 puts our receiving xpub inside the request we send, so the contact can pay us on that chain without ever reciprocating. Two places assumed the opposite:

  • collect_account_build_candidates (contact_requests.rs) walks established_contacts() only, so the sweep never queued a receiving account for a one-way contact.
  • reconcile_dashpay_rescan (payments.rs) skips every receival account whose contact is not established. Even with the account built, the history before it was registered would never be rescanned.

Together, payments on that chain stay invisible at any rescan depth. The live send path (send_contact_request_with_external_signer) registers the account itself. The gap therefore hits wallets that learned of the sent request from Platform (restore from seed, a second device), plus any live registration that failed after the request had been saved.

Seen on testnet (topple wallet 7dc06ad3…):

  • Transaction e5169bfc4989585abd4b0476188611b981e3c750539da5b8a39fe135e3bbb957, height 1,475,820: 0.001 DASH to yMNNc2UZz62V9N7SZfQnsk79G5okCP7eSN. That is our receiving chain 15'/0'/(us)/(4193bbe6…)/0 for contact 5QzA7GnST….
  • The store holds one request for that contact: ours, at core height 1,475,801, 19 blocks before the payment. There is no incoming request and no DashPay account.
  • The payment is missing from every archived SDK store (int6 through int27). dashj's wallet dump has it.
  • Its later spend 6ac8356c… is stored with netAmount = +99734, because the funding transaction is unknown. The balance is right today only because the coin has been spent.
  • Two more contacts on the same wallet are in the same one-way state.

Fixes #5246.

What was done?

  • Sweep: a new step (3b) runs enqueue_receiving_account_builds after the existing account builds. It calls collect_receiving_account_candidates, which lists every contact that holds a request we sent, in sent_contact_requests() or established_contacts(), and has no receival account. Each one gets a RegisterReceiving queue entry, and only that. The gate is on our side alone, because our receiving account depends only on our own request: it needs our identity, theirs and the signer, never their xpub. Besides the one-way contact, that covers two established cases the regular gate skips for good: a contact whose channel is marked payment_channel_broken (the failure was in decrypting their xpub, which our receiving side never touches, and RegisterReceiving makes no fetch and no decrypt, so it cannot retry without bound), and a contact whose external account was built but whose receiving build failed once (the external row survives a relaunch, so the regular has_external gate then skips it forever; this is gap 2 of platform-wallet: restored wallets miss historical DashPay contact payments — no registration-time rescan, and failed receival-account builds are never re-enqueued #4475). The external account keeps its own gate: it still needs the contact's xpub from a request they send us. Overlap with the regular candidates is harmless, since enqueueing is idempotent per (owner, contact, kind). Identities without an HD index are skipped. Because the queue is not restored on load (platform-wallet: restore the deferred DashPay contact-crypto queue on load #5091), re-discovering candidates every sweep is what carries a pending build across a relaunch.
  • Rescan: reconcile_dashpay_rescan rewinds a sent-only receival account to our request's core_height_created_at (the request carries our xpub). It no longer skips such accounts. Established contacts keep min(outgoing, incoming).
  • A contact who only sent us a request gets nothing new: they never received our xpub, so they cannot pay us on a chain of ours.
  • collect_account_build_candidates and AccountBuildCandidate are unchanged on purpose (see "How this composes" below). Folding the receiving-only case into that struct would be cleaner, but fix(platform-wallet)!: persist DashPay coreHeight backfill coverage so a relaunch resumes instead of rewinding again #5026 makes both pub(super) and uses them in tests; that consolidation is better done once the open work lands.

How this composes with open work

How Has This Been Tested?

New tests:

  • one_way_contact_tests::should_build_receiving_account_for_one_way_contact_on_sweep runs the real sync_contact_requests_reporting on a mock SDK that answers both contact-request queries with no documents, over a wallet that holds a one-way sent request. It asserts both fetches were answered, then that exactly one RegisterReceiving is queued. After draining with a seed provider, it asserts the receival account exists.
  • payments::tests::rescan_backfills_a_one_way_contact_from_our_sent_request_height: a one-way contact's receival account rewinds synced_height from 1,561,776 to 1,475,801, and only once.
  • one_way_contact_tests::should_collect_every_contact_holding_our_request_as_receiving_candidate covers which contacts are candidates: one-way sent and established are, one-way received is not.
  • one_way_contact_tests::should_still_build_receiving_account_when_channel_is_broken: an established contact with payment_channel_broken and no accounts is skipped by the regular gate and listed by the receiving gate.
  • one_way_contact_tests::should_queue_a_payload_free_receiving_op_for_one_way_contact checks that re-enqueueing is idempotent and the queued op carries no payload.

Without the fix: I reverted only the sweep's new call and the rescan change, keeping the helpers so the test module still compiled. Both regression tests failed:

  • the sweep test queued [] instead of [RegisterReceiving]
  • the rescan test got None instead of Some(1475801)

With the fix:

  • cargo test -p platform-wallet --features shielded: 1,413 lib tests plus all integration test binaries pass (the full lib suite was re-run after the second commit; the integration binaries after the first).
  • cargo test -p platform-wallet-ffi --features shielded: 430 lib tests plus all integration test binaries pass.
  • cargo check --tests -p platform-wallet-storage: clean.

Known limitation. The rescan hunk uses the tracked (newest) sent request's height. After a rotation re-send, that misses the span between the first publication of our xpub and the re-send. The established path on v5.1-dev has the same limitation, and #4740 fixes both with its earliest-height checkpoint.

Build note. This branch is based on v5.1-dev at 218cb89f18, whose tip did not compile: packages/rs-platform-version/src/version/v15.rs still imported drive_abci_query_versions::v3::DRIVE_ABCI_QUERY_VERSIONS_V3 after #5057 folded V3 into V2. #5212 (662c1fc945) has since fixed that on v5.1-dev. The local runs above used an equivalent uncommitted patch (both references changed to V2), which is not part of this PR. The branch merges into the current v5.1-dev tip (1ebcedb028) without conflicts, so it was left unrebased.

QA on a device (topple, testnet)

Run by the kotlin-sdk int28 integration build (integration/v42int28-pin @ 4dd8e3d0a2 on the HashEngineering fork), upgraded in place over int27 on the topple wallet (7dc06ad3…) on 2026-10-02. What that build contains, checked with git range-diff against this branch:

Results, from the SDK store captured two minutes after launch (store-after1) and the logcat:

int27 (before) int28 (after)
e5169bfc… in transactions absent present: received, +100000 duffs, height 1,476,252
e5169bfc:0 in txos absent present, marked spent by 6ac8356c…
6ac8356c… netAmount +99734 −266 (the fee)
receival accounts for the three one-way contacts (4193bbe6…, c7037829…, ce3cff2f…) none all three
  • The sweep drained three RegisterReceiving builds; the reconcile logged lowered SPV synced_height … floor=1475801 rewound_from=1564627 contacts=3. 1,475,801 is our sent request's height for 4193bbe6…. SPV climbed back to the tip in about 27 s.
  • The balance stayed at 168.96778705, as expected: the 0.001 DASH receive is credited and the same coin's spend is now accounted, so the two offset.
  • After a force-stop and relaunch, fix(platform-wallet)!: persist DashPay coreHeight backfill coverage so a relaunch resumes instead of rewinding again #5026's record reported the three contacts covered and no rewind happened.

Caveats: the run exercised this PR's rescan fallback inside #5026's function, not inside v5.1-dev's; the fallback as it sits in this PR has unit-test coverage only (rescan_backfills_a_one_way_contact_from_our_sent_request_height). Whichever of #5026 and this PR lands second conflicts in that one function; fc9142a30d on int28 is the resolution. One host-side observation, not an SDK defect: dash-wallet's WalletTransactionMetadataProvider later logged "DROPPED — no wallet tx and no fallback row" for e5169bfc… although the SDK store holds it; filed as dashpay/dash-wallet#1598.

Breaking Changes

None.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

PR Hygiene · 6709b29

  • Bots — coderabbitai skipped after the window · thepastaclaw ✓
  • Self-review — posted; again after any push
  • Build green
  • Approvals
    • rs-platform-wallet (packages/rs-platform-wallet/src/wallet/identity/network/contact_requests.rs, packages/rs-platform-wallet/src/wallet/identity/network/contacts.rs, packages/rs-platform-wallet/src/wallet/identity/network/payments.rs) — ZocoLini or llbartekll or romchornyi

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

HashEngineering and others added 2 commits October 1, 2026 16:26
… contacts

A contact we sent a contact request to, who never sent one back, got no
DashpayReceivingFunds account. DIP-15 puts our receiving xpub in the
request we send, so that contact can pay us without reciprocating. But
the sweep built accounts only for established contacts, and the rescan
reconcile skipped every contact that was not established. Payments on
that chain were never seen, at any rescan depth. The live send path
registers the account itself, so this hit wallets that learned of the
sent request from Platform (restore from seed, a second device) or whose
live registration failed after the request was saved.

Seen on a topple testnet wallet: a 0.001 DASH receive (e5169bfc…, height
1,475,820) on our chain for a contact whose only request is ours, sent
19 blocks earlier. It is missing from every archived SDK store and
present in dashj's, and its later spend is recorded with a positive net
amount because the funding transaction is unknown.

The sweep now queues RegisterReceiving, and only that, for each
unreciprocated sent request that has no receival account. There is no
xpub of theirs to decrypt, so no external account can be built until
they reciprocate. The rescan reconcile rewinds a sent-only receival
account to our request's core height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… alone

The previous commit queued our receiving account for a contact whose
request we sent and who never replied. Two established contacts were
still left without one: a contact whose payment channel is marked broken,
and a contact whose external account was built but whose receiving build
failed once. The regular candidate gate skips both for good, and it is
the only thing that re-queues a build after a relaunch.

Our receiving account needs our identity, theirs and the signer. It never
touches their xpub, so neither failure is a reason to skip it. The
receiving-side collector now lists every contact that holds a request we
sent, in sent_contact_requests or established_contacts, with no receival
account, and ignores the broken flag. RegisterReceiving makes no fetch
and no decrypt, so it cannot retry without bound. The external account
keeps its own gate, and the overlap with the regular candidates is
harmless because enqueueing is idempotent per (owner, contact, kind).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: dashpay/platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 447bab47-9d05-4ed5-9dfc-d59cc50abc5e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions github-actions Bot added this to the v5.1.0 milestone Oct 2, 2026
@thepastaclaw

thepastaclaw commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit 6709b29) · triage: normal

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. labels Oct 6, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Final validation — Phase 1 + Phase 2

Verified the supplied findings against head de7bfa8. The receiving-only enqueue and sent-request rescan fallback match the PR's goal; no blocking issues were confirmed, and one method-documentation nitpick remains. Validation was static only: in the supplied CI snapshot, Rust workspace tests were still running and the dedicated Rust wallet tests were skipped.

💬 1 nitpick(s)

1 finding(s) not shown inline (the lines are not part of this PR's diff)

💬 Nitpick: Sweep method docs omit the new receiving-only step
packages/rs-platform-wallet/src/wallet/identity/network/contact_requests.rs:1334-1338

The per-sweep documentation on sync_contact_requests, whose implementation delegates to sync_contact_requests_reporting, describes account builds only for established contacts missing a sending account. The reporting implementation now also calls enqueue_receiving_account_builds for contacts holding our sent request, including unreciprocated contacts and established contacts excluded by the external-account gate. Add that receiving-only step to the method documentation so its behavior summary covers the recovery path introduced by this PR.

    /// 4. For **every** established contact missing a sending account
    ///    (not only newly-established ones — this also repairs
    ///    restore-from-seed and best-effort-accept gaps), rebuilds both
    ///    the `DashpayReceivingFunds` and `DashpayExternalAccount`
    ///    accounts, with the transient/permanent failure policy.
    /// 5. For every contact holding a request we sent, reciprocated or not,
    ///    and missing a receiving account, enqueues a
    ///    `DashpayReceivingFunds` build alone for the signer-backed drain.
    ///    This receiving-only step does not depend on the contact's xpub
    ///    or the external-account gate.

source: muse-spark-1.3-contributor (phase1-reviewer: general)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: normal by gpt-6.1-sol (effort low) — The diff adds receiving-account candidate discovery and queueing in contact_requests.rs and adjusts rescan eligibility in payments.rs, but does not change funds movement, coin selection, cryptography, key derivation, or storage migrations.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 15% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-platform-wallet/src/wallet/identity/network/contact_requests.rs`:
- [NITPICK] packages/rs-platform-wallet/src/wallet/identity/network/contact_requests.rs:1334-1338: Sweep method docs omit the new receiving-only step
  The per-sweep documentation on `sync_contact_requests`, whose implementation delegates to `sync_contact_requests_reporting`, describes account builds only for established contacts missing a sending account. The reporting implementation now also calls `enqueue_receiving_account_builds` for contacts holding our sent request, including unreciprocated contacts and established contacts excluded by the external-account gate. Add that receiving-only step to the method documentation so its behavior summary covers the recovery path introduced by this PR.

HashEngineering and others added 2 commits October 7, 2026 12:48
The step list on sync_contact_requests described account builds for
established contacts only. Add the receiving-account step the sweep now
runs for every contact holding a request we sent.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@HashEngineering HashEngineering self-assigned this Oct 7, 2026
@HashEngineering

Copy link
Copy Markdown
Collaborator Author

/self-review

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai not yet · thepastaclaw ✓. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. labels Oct 7, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review — Final validation — Phase 1 + Phase 2

The complete diff at e968545 addresses receiving-account discovery and rescan eligibility for one-way DashPay contacts without introducing a confirmed production defect. One new regression assertion does not actually exercise the single-shot rescan guard; the prior documentation finding is fixed. Validation was static only: no builds or tests were run, and the supplied CI snapshot still shows build and validation checks pending or running.

🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: normal by gpt-6.1-sol (effort low) — The diff adds receiving-account discovery and deferred registration plus rescan eligibility changes in contact_requests.rs and payments.rs, but does not alter funds movement, coin selection, cryptography, or key derivation itself.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 15% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-platform-wallet/src/wallet/identity/network/payments.rs`:
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/payments.rs:2962-2970: Advance the scan height before asserting the rescan is single-shot
  After the first reconciliation, synced_height equals the sent request's funding height. The second call therefore returns None even if this one-way contact was never inserted into rescan_triggered, because funding < synced_height is already false. The assertion cannot detect a regression in the single-shot behavior it claims to verify. Advance synced_height before reconciling again and assert that the advanced height is preserved; without the guard, that call would rewind the wallet again.

Comment thread packages/rs-platform-wallet/src/wallet/identity/network/payments.rs
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. and removed waiting-bots Waiting for the review bots to report on this head labels Oct 9, 2026
…o fail

The second reconcile ran with synced_height still at the contact's
funding height, so it returned None whether or not the contact was marked
in rescan_triggered: nothing was below the scan to rewind for. Let the
scan climb back to the tip first, then check the second reconcile leaves
it there. With the guard insert removed, the test now fails with
Some(1475801).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai not yet · thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed labels Oct 10, 2026
@github-actions github-actions Bot removed the bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. label Oct 10, 2026
@HashEngineering

Copy link
Copy Markdown
Collaborator Author

/self-reviewed

@github-actions

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai not yet · thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

…ts.rs

Co-authored-by: Lil Claw <pasta+claw@dashboost.org>
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai not yet · thepastaclaw ✓. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review — Final validation — Phase 1 + Phase 2

The complete diff addresses receiving-account discovery and historical rescanning for one-way DashPay contacts without changing the external-account gate. Both prior findings are fixed; one redundant test assertion remains as a non-blocking nitpick. Validation was static only: the supplied CI snapshot shows Kotlin SDK checks passing, Rust wallet tests still running, and Rust workspace tests skipped.

💬 1 nitpick(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: normal by gpt-6.1-sol (effort low) — The production diff adds receiving-account eligibility and deferred registration plus a rescan fallback in contact_requests.rs and payments.rs, but does not change funds movement, coin selection, cryptography, or key derivation itself.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 14% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-platform-wallet/src/wallet/identity/network/payments.rs`:
- [NITPICK] packages/rs-platform-wallet/src/wallet/identity/network/payments.rs:2978-2987: Duplicated synced_height assertion in one-way rescan test
  These consecutive assertions both check that synced_height remains 1,561,776 after the second reconciliation. The helper only reads the height, and this mock-wallet test has no intervening mutation or background scan, so the second assertion adds no coverage. Keep one assertion; the restored scan height and second reconciliation already make the single-shot guard test effective.

Comment thread packages/rs-platform-wallet/src/wallet/identity/network/payments.rs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. and removed waiting-bots Waiting for the review bots to report on this head labels Oct 11, 2026
The applied review suggestion re-added the scan-height checks the test
already made, so each height was asserted twice. Keep one of each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai not yet · thepastaclaw ✓. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. labels Oct 13, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review — Final validation — Phase 1 + Phase 2

The complete diff at 6709b29 correctly separates receiving-account recovery from the counterparty-dependent external-account gate and extends rescanning to sent-only contacts; no blocking defects were verified. All three prior findings are fixed, and one nonblocking regression-coverage gap remains for established contacts whose external account exists but receiving account is missing. Validation was static only: the supplied exact-head CI snapshot reports successful Rust wallet, Swift SDK, and Kotlin SDK checks, with workspace tests skipped and PR Hygiene pending.

🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: normal by gpt-6.1-sol (effort low) — The diff adds receiving-account candidate discovery, deferred registration, and rescan eligibility with extensive tests, but does not itself change funds movement, coin selection, cryptography, key derivation, or storage migrations.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 14% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-platform-wallet/src/wallet/identity/network/contact_requests.rs`:
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/contact_requests.rs:5690-5698: Pin recovery when only the external account survives
  The new tests cover established contacts with neither account, broken channels, and sent-only contacts, but none exercises the explicitly supported recovery case where an established contact already has an external account and lacks its receiving account. The regular collector skips contacts with an external account, so accidentally introducing that same gate into the receiving collector would strand this case without failing the current new tests. Add a focused sweep-and-drain regression with an existing external account and `external_account_reference` matching `incoming_request.account_reference`; otherwise the sweep's stale-account teardown would mask the scenario. Assert that the regular collector is empty, the sweep queues exactly `RegisterReceiving`, and draining creates the receiving account while preserving the external account.

Comment on lines +5690 to +5698
async fn should_collect_every_contact_holding_our_request_as_receiving_candidate() {
let owner = id(0xAA);
let one_way_out = id(0xB1);
let one_way_in = id(0xB2);
let established = id(0xB3);
let sdk = dash_sdk::SdkBuilder::new_mock().build().expect("mock sdk");
let (_manager, iw) = wallet_with_owner(sdk, owner).await;
seed_requests(
&iw,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 Suggestion: Pin recovery when only the external account survives

The new tests cover established contacts with neither account, broken channels, and sent-only contacts, but none exercises the explicitly supported recovery case where an established contact already has an external account and lacks its receiving account. The regular collector skips contacts with an external account, so accidentally introducing that same gate into the receiving collector would strand this case without failing the current new tests. Add a focused sweep-and-drain regression with an existing external account and external_account_reference matching incoming_request.account_reference; otherwise the sweep's stale-account teardown would mask the scenario. Assert that the regular collector is empty, the sweep queues exactly RegisterReceiving, and draining creates the receiving account while preserving the external account.

source: gpt-6.1-sol (phase2-reviewer: rust-quality)

@HashEngineering

Copy link
Copy Markdown
Collaborator Author

/self-reviewed

@github-actions

Copy link
Copy Markdown
Contributor

Ready for review — rs-platform-wallet: ZocoLini or llbartekll or romchornyi.
Full checklist in the description.

@github-actions github-actions Bot added ready-for-human Bots have reported, the author has self-reviewed, and the build is green: this needs a human. bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. and removed waiting-bots Waiting for the review bots to report on this head labels Oct 13, 2026

This branch has not been deployed

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

Labels

bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. ready-for-human Bots have reported, the author has self-reviewed, and the build is green: this needs a human.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants