Skip to content

fix(platform-wallet): local-ledger ownership guard (V27-007)#3648

Open
lklimek wants to merge 1 commit into
v3.1-devfrom
fix/platform-wallet-ledger-ownership-guard-v27-007
Open

fix(platform-wallet): local-ledger ownership guard (V27-007)#3648
lklimek wants to merge 1 commit into
v3.1-devfrom
fix/platform-wallet-ledger-ownership-guard-v27-007

Conversation

@lklimek
Copy link
Copy Markdown
Contributor

@lklimek lklimek commented May 15, 2026

Issue being fixed or feature implemented

The SDK returns post-transition state for every address touched by a transfer transition — both inputs and outputs. When the source wallet sends credits to a foreign address (e.g. a bank's primary receive address), the response includes that foreign address's post-credit balance. Without an ownership check, transfer wrote the foreign balance into the source wallet's local ledger via set_address_credit_balance, corrupting total_credits().

Symptom chain (PA-004b / PA-009c teardown, QA-010):

  1. Test wallet trims residual credits to a bank's primary address.
  2. transfer writes the bank's balance into the source wallet's ledger.
  3. total_credits() is inflated; the dust-gate passes; a sweep begins.
  4. Sweep selects the bank's address (now in the source ledger), tries to sign, and fails (No private key for address P2pkh(...)).
  5. Failure cascades through teardown.

This is a standalone correctness fix carved out of #3549 (source commit 16636f01c0). It is not present in the #3554 stack base — it is introduced by #3549 only and is self-contained.

What was done?

  • transfer: guard set_address_credit_balance with account.contains_platform_address(&p2pkh), mirroring the identical guard already present in fund_from_asset_lock. Foreign output addresses are silently skipped; the recipient wallet's own syncer is responsible for observing its inbound credits.
  • withdrawal: applied the same guard defensively. Withdrawals carry no foreign platform output addresses today, so the guard is never expected to fire, but it keeps the local-ledger ownership invariant consistent with transfer.
  • Added a method-level # Local-ledger ownership invariant (V27-007 / QA-010) doc section on transfer documenting the invariant.

Net change: +27 LOC across 2 files, no e2e tests, no rust-dashcore bump, no Cargo.lock churn.

How Has This Been Tested?

  • cargo build -p platform-wallet on origin/v3.1-dev — clean (rust-dashcore stays at base rev 53130869; contains_platform_address is available on key-wallet@53130869, no dependency on the excluded cluster-A bump).
  • cargo clippy -p platform-wallet — clean, zero warnings on the changed crate.
  • Behavioral validation rides in the test(rs-platform-wallet): e2e suite, Found-025 fix + triage pins #3549 e2e suite (PA-004b / PA-009c teardown, QA-010) which stays in the parent PR.

Breaking Changes

None. Internal post-broadcast ledger-update behavior only; public API is unchanged.

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

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Source: extracted from #3549 (cluster F — local-ledger ownership guard, source commit 16636f01c0).

🤖 Generated with Claude Code

The SDK returns post-transition state for every address touched by a
transfer transition — both inputs and outputs. When the source wallet
sends credits to a foreign address (e.g. bank's primary receive address),
the response includes the bank's post-credit balance. Without an ownership
check, `transfer` wrote that foreign balance into the source wallet's local
ledger via `set_address_credit_balance`, corrupting `total_credits()`.

Symptom chain (PA-004b / PA-009c teardown, QA-010):
1. Test wallet trims residual credits to bank's primary address.
2. `transfer` writes bank's balance into the source wallet's ledger.
3. `total_credits()` is inflated; dust-gate passes; sweep begins.
4. Sweep selects bank's address (now in the source ledger), tries to
   sign, fails ("No private key for address P2pkh(...)").
5. Failure cascade in teardown.

Fix: guard `set_address_credit_balance` with `contains_platform_address`
in `transfer`, mirroring the identical guard already present in
`fund_from_asset_lock`. The recipient wallet's syncer observes inbound
credits on its own addresses; the source wallet must not.

Also applied the same guard defensively to `withdrawal` (no foreign
platform output addresses appear there today, but consistency with the
local-ledger ownership invariant is cleaner than a latent risk).

Carved out of #3549 (source commit 16636f0) as a
standalone production fix on v3.1-dev. No e2e tests, no dependency
bumps included.

References: V27-007, QA-010

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

Warning

Rate limit exceeded

@lklimek has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 57 minutes and 39 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2fa7f76f-806b-4f61-8d3b-a4f3d5780018

📥 Commits

Reviewing files that changed from the base of the PR and between 54322f7 and cac51fa.

📒 Files selected for processing (2)
  • packages/rs-platform-wallet/src/wallet/platform_addresses/transfer.rs
  • packages/rs-platform-wallet/src/wallet/platform_addresses/withdrawal.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/platform-wallet-ledger-ownership-guard-v27-007

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.

@github-actions github-actions Bot added this to the v3.1.0 milestone May 15, 2026
@lklimek lklimek changed the title fix(rs-platform-wallet): local-ledger ownership guard (V27-007) fix(platform-wallet): local-ledger ownership guard (V27-007) May 15, 2026
@lklimek lklimek marked this pull request as ready for review May 15, 2026 11:01
@lklimek lklimek requested a review from QuantumExplorer as a code owner May 15, 2026 11:01
@lklimek lklimek added the ready for final review Ready for the final review. If AI was involved in producing this PR, it has already had a reviewer. label May 15, 2026
@thepastaclaw
Copy link
Copy Markdown
Collaborator

thepastaclaw commented May 15, 2026

Review Gate

Commit: cac51fa3

  • Debounce: 1617m ago (need 30m)

  • CI checks: build failure: PR title

  • CodeRabbit review: comment found

  • Off-peak hours: off-peak (06:48 AM PT Saturday)

  • Run review now (check to override)

Copy link
Copy Markdown
Member

@QuantumExplorer QuantumExplorer left a comment

Choose a reason for hiding this comment

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

We haven't been using the platform_payment_managed_account, and have plans to get rid of it entirely. Instead we use the thing in platform wallet.

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

Labels

ready for final review Ready for the final review. If AI was involved in producing this PR, it has already had a reviewer.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants