Skip to content

fix(platform-wallet): raise the invitation cap to cover the contested username tier - #4362

Merged
QuantumExplorer merged 3 commits into
v4.2-devfrom
fix/invitation-cap-contested
Aug 11, 2026
Merged

fix(platform-wallet): raise the invitation cap to cover the contested username tier#4362
QuantumExplorer merged 3 commits into
v4.2-devfrom
fix/invitation-cap-contested

Conversation

@bfoss765

Copy link
Copy Markdown
Collaborator

Supersedes #4351 — same change, recreated on a dashpay/platform branch per repo policy (no more personal-fork PRs). Commits and authorship unchanged; full review history on #4351.

Required for existing Android functionality

The Android wallet has funded contested (premium-name) invitations at 0.25 DASH since 2024 (DASH_PAY_FEE_CONTESTED, dash-wallet Constants.java:332). Its legacy dashj invitation path imposes no cap, so contested invitations have always worked pre-cutover. The moment a wallet commits the dashj→SDK cutover, create_invitation becomes the only route — and every contested invitation is rejected pre-broadcast:

Invalid identity data: invitation amount 25000000 exceeds the cap 5000000 duffs

Observed on a device 2026-08-09 as an endless confirm/retry loop (the app-side loop is fixed separately; the capability gap is this cap). A contested L1 invitation has never succeeded through the SDK path — the 0.25-vs-0.05 contradiction has existed since the path was first wired.

Why raising is safe and sanctioned

  • The constant's own doc deferred the contested tier "until contested-name-via-invite claim exists; raise this cap when it does." That condition is met: claim_invitation is amount-agnostic (no cap at claim), and contested-invite claims are verified working in QA.
  • The cap is a client-side leaked-link bound, not consensus — registration/top-up have no equivalent.
  • Both the dashj legacy path and the shielded invitation path already mint 0.25 bearer links today, so 0.05 on this one path protected nothing while breaking path parity post-cutover.

0.26 = the 0.25 contested fee + margin for the create/claim fees, matching the Android wallet's rounded contested guidance. MIN_INVITATION_DUFFS and all boundary tests are relative to the constant and unchanged; platform-wallet lib: 610 passed / 0 failed.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Increased the maximum invitation funding limit to support both standard and contested DPNS-name onboarding scenarios.

… username tier

MAX_INVITATION_DUFFS 5_000_000 -> 26_000_000 (0.05 -> 0.26 DASH).

Required for existing Android functionality: the Android wallet has funded
contested (premium-name) invitations at 0.25 DASH since 2024
(DASH_PAY_FEE_CONTESTED, dash-wallet Constants.java). Its legacy dashj path
imposes no cap, so contested invitations have always worked pre-cutover; the
moment a wallet commits the dashj->SDK cutover, create_invitation becomes the
only route and every contested invitation is rejected pre-broadcast with
'invitation amount 25000000 exceeds the cap 5000000 duffs' - observed on
device 2026-08-09, an endless-retry loop in the field.

The 0.05 value's own doc deferred the contested tier 'until
contested-name-via-invite claim exists; raise this cap when it does'. That
condition is met: claim_invitation is amount-agnostic and contested-invite
claims are verified working in QA. The cap remains a client-side leaked-link
bound, not consensus; both the dashj and shielded invitation paths already
mint 0.25 bearer links today, so 0.05 here protected nothing while breaking
path parity. 0.26 = 0.25 contested fee + margin for the create/claim fees,
matching the Android wallet's rounded contested guidance.

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

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@QuantumExplorer, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 06b9d4ec-689b-40d8-9cfe-25392b75141f

📥 Commits

Reviewing files that changed from the base of the PR and between 86f3878 and 7b6ca46.

📒 Files selected for processing (12)
  • docs/dashpay/DIP15_INVITATIONS_SPEC.md
  • packages/kotlin-sdk/KotlinExampleApp/app/src/main/java/org/dashfoundation/example/ui/dashpay/CreateInvitationSheet.kt
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/ffi/DashpayNative.kt
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/tokens/Dashpay.kt
  • packages/rs-platform-wallet-ffi/src/invitation.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/mod.rs
  • packages/rs-unified-sdk-jni/src/dashpay.rs
  • packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformWallet.swift
  • packages/swift-sdk/SwiftExampleApp/Info.plist
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/AI_QA/QA004_invitation_reclaim.md
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/CreateInvitationSheet.swift

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

@thepastaclaw

thepastaclaw commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

🕓 Ready for review — next in queue (commit 7b6ca46)
Queue position: 1/1

@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 — Codex/Sol only (Phase 2 disabled)

The Rust cap change correctly allows the 25,000,000-duff contested tier and remains client-side rather than consensus-critical. Two in-scope follow-ups remain: synchronize repository consumers that mirror the old cap, and add regression coverage for the changed boundary.
Source: codex general reviewer backend gpt-5.6-sol; codex rust-quality reviewer backend gpt-5.6-sol; final codex verifier backend gpt-5.6-sol; openclaw-agent/cliproxy/gpt-5.6-sol was orchestration-only and is not reviewer evidence.

Validated zero-blocker Codex/Sol precheck evidence was promoted to final because Phase 2 (Sonnet/Opus) is temporarily disabled. This is Codex/Sol-only final validation, not Codex + Sonnet/Opus coverage.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet/Opus: not run (Phase 2 disabled — temporary Codex/Sol-only final)
  • Secondary pass: disabled (temporary_phase2_sonnet_disable)

🟡 2 suggestion(s)

🤖 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/invitation.rs`:
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs:60: Update clients that still mirror the old invitation cap
  This change makes the repository's explicit cap mirrors inconsistent with the Rust source of truth. `packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/CreateInvitationSheet.swift` still defines `maxInvitationDuffs` as `5_000_000`, and its amount parser rejects larger values, so that bundled client cannot create a 0.25 DASH contested invitation even though the corrected Rust API accepts it. The associated Swift text, Kotlin KDoc and example guidance, `Info.plist`, and `docs/dashpay/DIP15_INVITATIONS_SPEC.md` also still advertise the old 0.05 DASH limit. Update these mirrors to 26,000,000 duffs so the client behavior and documentation match the newly raised cap.
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs:60: Add a regression test for the contested invitation amount
  No test independently exercises the amount-cap branch or references `MAX_INVITATION_DUFFS`, so reverting this constant to 5,000,000 would reproduce the reported regression while leaving the existing suite green. Extend the durability-gate harness with independently stated boundaries: 25,000,000 duffs should pass amount validation and reach the expected persistence-capability error, while `MAX_INVITATION_DUFFS + 1` should fail immediately with `InvalidIdentityData`. This directly pins both the contested tier and the upper-bound rejection without broadcasting funds.

/// Android wallet has funded contested invitations at 0.25 since 2024, so the
/// deferral is over. (The pre-merge 0.01 iteration was below even a usable
/// non-contested invitation and rejected its own onboarding default.)
pub const MAX_INVITATION_DUFFS: u64 = 26_000_000;

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: Update clients that still mirror the old invitation cap

This change makes the repository's explicit cap mirrors inconsistent with the Rust source of truth. packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/CreateInvitationSheet.swift still defines maxInvitationDuffs as 5_000_000, and its amount parser rejects larger values, so that bundled client cannot create a 0.25 DASH contested invitation even though the corrected Rust API accepts it. The associated Swift text, Kotlin KDoc and example guidance, Info.plist, and docs/dashpay/DIP15_INVITATIONS_SPEC.md also still advertise the old 0.05 DASH limit. Update these mirrors to 26,000,000 duffs so the client behavior and documentation match the newly raised cap.

source: ['codex']

/// Android wallet has funded contested invitations at 0.25 since 2024, so the
/// deferral is over. (The pre-merge 0.01 iteration was below even a usable
/// non-contested invitation and rejected its own onboarding default.)
pub const MAX_INVITATION_DUFFS: u64 = 26_000_000;

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: Add a regression test for the contested invitation amount

No test independently exercises the amount-cap branch or references MAX_INVITATION_DUFFS, so reverting this constant to 5,000,000 would reproduce the reported regression while leaving the existing suite green. Extend the durability-gate harness with independently stated boundaries: 25,000,000 duffs should pass amount validation and reach the expected persistence-capability error, while MAX_INVITATION_DUFFS + 1 should fail immediately with InvalidIdentityData. This directly pins both the contested tier and the upper-bound rejection without broadcasting funds.

source: ['codex']

QuantumExplorer and others added 2 commits August 11, 2026 16:05
… FFI

Review follow-up: the SwiftExampleApp mirrored MAX_INVITATION_DUFFS (and the
floor) as hardcoded constants, so the bundled iOS client still rejected the
contested tier this PR unlocks. Rust now owns the only copy:

- FFI getters platform_wallet_invitation_max_duffs / _min_duffs return the
  library constants (pinned by a bridge test); MIN_INVITATION_DUFFS joins the
  network module re-export.
- SwiftDashSDK bridges them as ManagedPlatformWallet.maxInvitationDuffs /
  minInvitationDuffs; CreateInvitationSheet reads those and renders its help
  copy from the values, so no numeric mirror remains in Swift.
- Stale textual mentions of the old 0.05 cap updated (Info.plist comment,
  Kotlin KDoc, QA004, DIP15 spec).

Verified: platform-wallet-ffi + platform-wallet tests green, clippy clean,
build_ios.sh sim+mac (incl. SwiftExampleApp simulator build) and swift test
pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Android counterpart of the Swift single-sourcing commit: the Kotlin example
app's help copy re-typed the 0.003-0.05 DASH bounds and went stale when the
cap moved. Rust stays the only copy:

- JNI exports DashpayNative.invitationMaxDuffs/invitationMinDuffs bridging
  platform_wallet_invitation_max_duffs/_min_duffs.
- Dashpay companion exposes maxInvitationDuffs/minInvitationDuffs; the
  createInvitation KDoc references them instead of restating the numbers.
- KotlinExampleApp CreateInvitationSheet renders its bounds copy from the
  values (BigDecimal, locale-independent) — no numeric mirror remains.

Verified: rs-unified-sdk-jni clippy clean, gradle :sdk:assembleDebug +
:sdk:testDebugUnitTest + :app:assembleDebug all pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@QuantumExplorer
QuantumExplorer merged commit 08edcfd into v4.2-dev Aug 11, 2026
7 checks passed
@QuantumExplorer
QuantumExplorer deleted the fix/invitation-cap-contested branch August 11, 2026 09:17
@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.63%. Comparing base (6373e00) to head (7b6ca46).
⚠️ Report is 7 commits behind head on v4.2-dev.

Additional details and impacted files
@@            Coverage Diff            @@
##           v4.2-dev    #4362   +/-   ##
=========================================
  Coverage     87.63%   87.63%           
=========================================
  Files          2670     2670           
  Lines        339449   339516   +67     
=========================================
+ Hits         297467   297533   +66     
- Misses        41982    41983    +1     
Components Coverage Δ
dpp 88.86% <ø> (ø)
drive 86.25% <ø> (ø)
drive-abci 89.66% <ø> (-0.01%) ⬇️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.88% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 48.02% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

3 participants