Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,19 @@ use crate::wallet::identity::network::contact_requests::ContactCryptoProvider;

use super::*;

/// Hard cap on the amount an invitation can lock (0.05 DASH). The voucher is a
/// Hard cap on the amount an invitation can lock (0.26 DASH). The voucher is a
/// bearer credential, so the blast radius of a leaked link is bounded here in
/// Rust — not just in the UI. Sized for onboarding: the invitee spends the
/// voucher on identity creation **plus** a normal DPNS name (~0.03 DASH — the
/// legacy `DASH_PAY_FEE`), so the previous 0.01 cap was actually below a usable
/// invitation and rejected its own onboarding default. The contested/premium-name
/// tier (~0.25 DASH) is deferred until contested-name-via-invite claim exists;
/// raise this cap when it does.
pub const MAX_INVITATION_DUFFS: u64 = 5_000_000;
/// Rust — not just in the UI. Sized for onboarding at BOTH username tiers: the
/// invitee spends the voucher on identity creation **plus** a DPNS name — a
/// normal name (~0.03 DASH, the legacy `DASH_PAY_FEE`) or a contested/premium
/// name (~0.25 DASH, `DASH_PAY_FEE_CONTESTED`), with the 0.01 margin covering
/// the create/claim fees. The earlier 0.05 value deferred the contested tier
/// "until contested-name-via-invite claim exists" — the claim path is
/// amount-agnostic and contested-invite claims are verified working, and the
/// 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;
Comment on lines +48 to +60

@coderabbitai coderabbitai Bot Aug 9, 2026

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Update the downstream invitation limits.

The Rust cap now accepts up to 26_000_000 duffs, but downstream contracts still use 5_000_000.

  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/CreateInvitationSheet.swift, Lines 24-26: update the local validation limit. Otherwise, the Swift flow rejects valid contested invitations before calling Rust.
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/tokens/Dashpay.kt, Lines 405-421: update the SDK documentation to prevent an incorrect public contract.

Prefer exposing the Rust limit through the client APIs instead of maintaining independent literals. Add client-level boundary coverage for an amount between the old and new caps.

🤖 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 `@packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs` around
lines 48 - 60, Update the invitation amount validation in CreateInvitationSheet
and the public limit documentation in Dashpay to reflect MAX_INVITATION_DUFFS
(26,000,000 duffs), preferably exposing and reusing the Rust limit through
client APIs instead of duplicating literals. Add client-level boundary coverage
for an amount between 5,000,000 and 26,000,000 duffs, ensuring it is accepted.

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.

The Swift cap and Kotlin KDoc mismatches are valid. The obsolete contract also remains in docs/dashpay/DIP15_INVITATIONS_SPEC.md, the Kotlin example's displayed range and test plan, and the Swift Info.plist security note; the Rust guard also lacks direct coverage for 25,000,000, 26,000,000, and 26,000,001 duffs.

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.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- invitation limit references ---'
rg -n -i -C 3 \
  -e '5_000_000' \
  -e '5000000' \
  -e '0\.05[[:space:]]*DASH' \
  -e 'MAX_INVITATION_DUFFS' \
  -e 'invitation.*(amount|limit|range|duff)' \
  packages docs

printf '%s\n' '--- candidate Swift and Kotlin files ---'
fd -t f -i \
  -g 'CreateInvitationSheet.swift' \
  -g 'Dashpay.kt' \
  -g 'Info.plist' \
  -g '*Invitation*Test*.swift' \
  -g '*Invitation*Test*.kt' \
  packages

printf '%s\n' '--- Rust module outline ---'
ast-grep outline packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs \
  --items all --type function --view expanded

Length of output: 201001


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- exact obsolete invitation-limit contracts ---'
rg -n -i -C 4 \
  -e 'MAX_INVITATION_DUFFS' \
  -e '5_000_000' \
  -e '0\.05[[:space:]]*DASH' \
  -e '5000000' \
  packages/swift-sdk packages/kotlin-sdk docs/dashpay/DIP15_INVITATIONS_SPEC.md \
  -g '!**/test/data/**' -g '!**/*.lock'

printf '%s\n' '--- relevant file excerpts ---'
sed -n '1,180p' \
  packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/DashPay/CreateInvitationSheet.swift
sed -n '25,55p' packages/swift-sdk/SwiftExampleApp/Info.plist
sed -n '380,440p' \
  packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/tokens/Dashpay.kt

printf '%s\n' '--- invitation-related Swift/Kotlin test candidates ---'
find packages/swift-sdk packages/kotlin-sdk -type f \
  \( -iname '*invitation*test*.swift' -o -iname '*invitation*test*.kt' \
     -o -iname '*dashpay*test*.swift' -o -iname '*dashpay*test*.kt' \) \
  -print | sort

printf '%s\n' '--- binding/API references for invitation limits ---'
rg -n -C 2 \
  -e 'platform_wallet_create_invitation' \
  -e 'createInvitation' \
  -e 'MAX_INVITATION_DUFFS' \
  -e 'minInvitationDuffs|maxInvitationDuffs' \
  packages/swift-sdk packages/kotlin-sdk \
  -g '!**/build/**' -g '!**/node_modules/**'

printf '%s\n' '--- Rust amount-validation test seams ---'
rg -n -C 4 \
  -e 'amount_duffs.*(MAX_INVITATION_DUFFS|MIN_INVITATION_DUFFS)' \
  -e 'create_invitation\(' \
  -e 'UnreachableSigner' \
  packages/rs-platform-wallet \
  -g '*.rs'

Length of output: 91544


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Kotlin invitation UI validation ---'
sed -n '1,230p' \
  packages/kotlin-sdk/KotlinExampleApp/app/src/main/java/org/dashfoundation/example/ui/dashpay/CreateInvitationSheet.kt

printf '%s\n' '--- Kotlin invitation-related unit and UI tests ---'
sed -n '1,260p' \
  packages/kotlin-sdk/KotlinExampleApp/app/src/test/java/org/dashfoundation/example/ui/dashpay/InvitationReclaimLogicTest.kt
sed -n '1,260p' \
  packages/kotlin-sdk/KotlinExampleApp/app/src/androidTest/java/org/dashfoundation/example/DashPayTabUITest.kt

printf '%s\n' '--- Swift example test target membership and invitation test sources ---'
rg -n -C 3 \
  -e 'CreateInvitationSheet\.swift' \
  -e 'ReclaimInvitationClassifierTests\.swift' \
  -e 'SwiftExampleAppTests' \
  packages/swift-sdk \
  -g '*.pbxproj' -g '*.xctestplan' -g '*.swift'
sed -n '1,180p' \
  packages/swift-sdk/SwiftExampleApp/SwiftExampleAppTests/ReclaimInvitationClassifierTests.swift
sed -n '1,180p' \
  packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/DashPayTabUITests.swift

printf '%s\n' '--- Kotlin constant and parser definitions ---'
rg -n -C 5 \
  -e 'MAX_INVITATION|MIN_INVITATION' \
  -e 'maxInvitation|minInvitation' \
  -e 'amountDuffs' \
  packages/kotlin-sdk/KotlinExampleApp/app/src/main/java/org/dashfoundation/example/ui/dashpay/CreateInvitationSheet.kt

printf '%s\n' '--- invitation FFI public API candidates ---'
rg -n -C 3 \
  -e 'platform_wallet_create_invitation' \
  -e 'MAX_INVITATION_DUFFS|MIN_INVITATION_DUFFS' \
  packages/rs-platform-wallet packages/rs-platform-ffi \
  -g '*.rs' -g '*.h' \
  || true

Length of output: 60015


@thepastaclaw, confirmed. The expanded scope is valid.

  • CreateInvitationSheet.swift has the actual stale Swift upper-bound validation. It rejects every amount above 5_000_000 duffs.
  • The Kotlin example does not enforce an upper bound locally. Its 0.003–0.05 range is stale display text. Rust remains the enforcement point.
  • The obsolete contract also appears in:
    • packages/swift-sdk/SwiftExampleApp/Info.plist
    • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/AI_QA/QA004_invitation_reclaim.md
    • packages/kotlin-sdk/KotlinExampleApp/app/src/main/java/org/dashfoundation/example/ui/dashpay/CreateInvitationSheet.kt
    • packages/kotlin-sdk/KotlinExampleApp/TEST_PLAN.md
    • packages/kotlin-sdk/PARITY.md
    • docs/dashpay/DIP15_INVITATIONS_SPEC.md, including the old deferred contested-name statement and the obsolete 0.01 DASH leak-cap text.
  • No existing Swift or Kotlin client API exposes MAX_INVITATION_DUFFS.

The focused fix should update all user-visible contracts to 26_000_000 duffs (0.26 DASH). It should extract the Rust amount guard into a direct test seam. Tests should accept 25_000_000 and 26_000_000 duffs, and reject 26_000_001 duffs. Swift should also test that its local validation accepts 25_000_000 duffs.


✏️ Learnings added
Learnt from: thepastaclaw
Repo: dashpay/platform PR: 4351
File: packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs:48-60
Timestamp: 2026-08-09T21:50:25.116Z
Learning: For DashPay DIP-13 invitations, `packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs` enforces `MAX_INVITATION_DUFFS = 26_000_000` (0.26 DASH). The cap supports contested username invitations funded at 0.25 DASH plus create and claim fee margin. Swift and Kotlin user-visible invitation funding limits, security notes, test plans, and DIP-15 documentation must remain aligned with this Rust-enforced cap.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

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 regression coverage for the contested invitation boundary

The reported failure was specifically caused by 25,000,000 duffs being rejected, but no test references MAX_INVITATION_DUFFS or exercises the updated range. The existing durability test submits only 1,000,000 duffs and would still pass if this constant reverted to 5,000,000. Add boundary tests showing that 25,000,000 and exactly 26,000,000 proceed past amount validation to the later persistence error, while 26,000,001 returns PlatformWalletError::InvalidIdentityData before persistence or funding is attempted.

source: ['codex']


/// Floor on the amount an invitation can lock (0.003 DASH). A voucher funds a
/// Platform identity operation, and creating an identity — which is what the
Expand Down
Loading