Skip to content

Fix displaying previous shapeshift bitcoin transaction - #18

Merged
QuantumExplorer merged 1 commit into
developfrom
fix/prev-transaction-price
Dec 1, 2018
Merged

Fix displaying previous shapeshift bitcoin transaction#18
QuantumExplorer merged 1 commit into
developfrom
fix/prev-transaction-price

Conversation

@podkovyrin

Copy link
Copy Markdown
Contributor

No description provided.

@QuantumExplorer
QuantumExplorer merged commit 5406425 into develop Dec 1, 2018
@QuantumExplorer
QuantumExplorer deleted the fix/prev-transaction-price branch December 1, 2018 08:32
llbartekll added a commit that referenced this pull request May 21, 2026
PR 1 of the row #16 migration (new-user identity + DPNS username from
DashSync to SwiftDashSDK). Scaffolding only, behind a disabled
`DASHPAY_SWIFT_SDK_REGISTRATION` flag — nothing calls these files yet,
DashSync remains the live path. PR 2 wires `DWDashPayModel.m` +
`DWCheckExistenceUsernameValidationRule.m` into the new path.

Migration doc updates (re-verified 2026-05-20):

- Row #16 / #17 / #19 flipped to 🟢 ready; row #18 flipped from 🔴 to
  🟡 (SDK APIs exist, no example walkthrough). Earlier "6+ FFI signature
  mismatches" claim resolved upstream via 33fde4e67f (cbindgen ABI),
  e22f816a2e (asset-lock proofs), c556a86db2 (KeychainSigner sweep),
  e9e56f3636 (account_index plumbed through).
- Hard Blockers: struck through #16 with the four resolving commits.
- Recommended order Wave 3 marked unblocked for #16/#17/#19.

New files in `DashWallet/Sources/Infrastructure/SwiftDashSDK/Identity/`:

- `DWRegistrationPhaseAdapter.swift` — pure mapping collapsing the SDK's
  5 internal phases (controller phase + `PersistentAssetLock.statusRaw`)
  onto the existing 3-state `DWDPRegistrationState` UI enum. Unit-tested.
- `DWIdentityRegistrationController.swift` — `@MainActor ObservableObject`
  phase holder (idle / preparingKeys / inFlight / completed / failed),
  ported from the SwiftExampleApp reference and stripped to a pure state
  carrier (v1 pins identityIndex=0; coordinator drives transitions).
- `DWIdentityAuthorizer.swift` — async PIN/biometric gate wrapping
  `DSAuthenticationManager.authenticate`. Mirrors the private
  `SendAuthorizer` pattern from `WalletSendService.swift:129-172`.
- `DWIdentityRegistrationCoordinator.swift` — `@MainActor` singleton
  orchestrating the full chain: PIN gate → `prePersistIdentityKeysForRegistration`
  → `registerIdentityWithFunding` → `registerDpnsName`. Polls
  `PersistentAssetLock.statusRaw` every 0.5s while `.inFlight` for the
  3-state UI mapping. Mirrors success into
  `DWGlobalOptions.dashpayUsername` + `dashpayRegistrationCompleted` so
  the 87 existing Obj-C identity-read sites keep working until row #17
  migrates them individually.
- `DWIdentityRegistrationBridge.swift` — `@objc @mainactor @objcMembers`
  facade for `DWDashPayModel.m` / `DWCheckExistenceUsernameValidationRule.m`.
  Cached `@objc` state mirrored from the coordinator via one
  `Publishers.CombineLatest($phase, $assetLockStatus)` subscription
  (passing emitted values directly avoids the `@Published` willSet
  re-read race). Posts `DWDashPayRegistrationStatusUpdatedNotification`
  on every transition.

Tests: `DashWalletTests/DWRegistrationPhaseAdapterTests.swift` — 12 cases
covering the full mapping matrix plus the failure-classification edge.

Project file:
- `DASHPAY_SWIFT_SDK_REGISTRATION=0` appended to all 5 GCC blocks that
  already contain `DASHPAY=1` (defined-but-falsy; PR 3 flips per-config).
- New Swift files registered on the `dashpay` target only — they reference
  DashPay-only Obj-C symbols (`DWDP_MIN_BALANCE_TO_CREATE_USERNAME`,
  `DWGlobalOptions.dashpayUsername` / `dashpayRegistrationCompleted`),
  which don't exist in the `dashwallet` target build.
- Test file registered on the `DashWalletTests` target.

v1 scope (documented for follow-up):
- Invitations stay on DashSync (no SDK equivalent for
  `DSBlockchainInvitation`).
- Existing DashSync identities not migrated — keys live in DashSync's
  keychain, not in `WalletStorage`. Future "import identity" stage.
- No crash-resume via `resumeIdentityWithAssetLock` (deferred to v2).
- Platform Payment funding path (`registerIdentityFromAddresses`) not
  wired — users with Platform credits but no Core balance still see the
  0.03 Dash error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
llbartekll added a commit that referenced this pull request May 25, 2026
Centralise DashPay current-user reads behind DWCurrentUserIdentityInfo
and route profile writes through SwiftDashSDK. Row #17 stage A already
surfaced SDK identities on the home-screen avatar + tap — this commit
finishes the in-scope read sites (avatar render, profile display,
invitation link, payment-side identity gate) and the profile editor's
write path. Pre-existing DashSync identities (rare in this branch)
keep working via fallbacks; full retirement lands with Row #25.

New infrastructure (dashpay target):
- DWCurrentUserIdentityInfo: @objc @mainactor lookup. Snapshot of
  (username, displayName, avatarURL, publicMessage, identityIdHex)
  invalidated on DWDashPayRegistrationStatusUpdated and
  DWIdentityRegistrationBridge.stateChangedNotification. Resolves
  PersistentIdentity from SwiftData, reads via
  wallet.managedIdentity(identityId:) → getDpnsNames() +
  getDashPayProfile(). Falls back to DWGlobalOptions.dashpayUsername
  for the post-register sync gap.
- DWProfileUpdateCoordinator: async @mainactor write path with PIN
  gate, KeychainSigner, and create-vs-update verb flip on cache-
  mismatch error from the SDK.
- DWProfileUpdateBridge: @objc completion-based facade. JPEG-encodes
  the cropped UIImage at quality 0.8 for DashPayProfileUpdate.avatarBytes.

Migrated reads:
- DWDPAvatarView: configureAsCurrentUser. Contact-side
  setBlockchainIdentity: kept for Row #18.
- DWEditProfileAvatarView: setImageForCurrentUser.
- DWCurrentUserProfileView: reloadFromCurrentUser. The legacy
  setBlockchainIdentity: setter now forwards to it. reloadAttributedData
  reads via a new DWCurrentUserTitleSubtitleAttributedString free
  function alongside the existing DSBlockchainIdentity+DWDisplayTitleSubtitle
  category.
- DWEditProfileViewController: displayName / aboutMe / avatar URL all
  prefill from the helper. Drops the non-MOCK assertion that
  blockchainIdentity is non-nil. unsavedAvatarImage retains the
  cropped UIImage so the SDK write path can hand bytes downstream.
- DWInvitationLinkBuilder: inviter profile fields from the helper.
- DWDashPayModel.username: prefer helper, fall back to DashSync +
  DWGlobalOptions.
- DWPayModel.refreshOptions: DashPay send-button gate via
  helper.hasIdentity.

Migrated write:
- DWDPUpdateProfileModel.updateWithDisplayName:aboutMe:avatarURLString:avatarImage:
  branches on wallet.defaultBlockchainIdentity. non-nil → legacy
  DashSync sign-and-publish. nil → DWProfileUpdateBridge. The new
  avatarImage parameter threads from RootEditProfileViewControllerDelegate
  through HomeViewController + MainMenuViewController's DelegateInternal.
- SDKIdentityProfileSheet: optional onEditTapped callback drives a
  new Edit button. HomeViewController.profileAction chains into
  RootEditProfileViewController on the tap so SDK identities can
  edit their profile end-to-end now.

Out of scope (Row #18 / Row #25 / future):
- DWUserProfileHeaderView, InvitationBottomView, DWNotificationsProvider,
  DWDashPayContactsUpdater, DWDashPayContactsActions — contact-side
  rendering and contacts subsystem.
- DWPaymentProcessor + DWPaymentOutput+DWView identity reads — pass
  DSBlockchainIdentity into deeper BIP-70 / friend-status machinery.
- Contested-name voting (still bypassed since PR 3).

Carveouts preserved untouched per user request:
- MainMenuViewController FIXME: TEMPORARY debug edits
- JoinDashPayViewModel.checkUsername
- HomeViewModel.checkJoinDashPay

Verified: dashpay scheme builds clean. End-to-end testnet verification
pending; the read paths render via the helper's snapshot + SDWebImage
URL load, and the write path calls into the existing SDK profile
APIs proven by the SwiftExampleApp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
llbartekll added a commit that referenced this pull request May 25, 2026
Detect contested-eligible labels client-side via the SDK FFI helper
`dash_sdk_dpns_is_contested_username`, warn the user with an orange
callout + confirmation alert in Create Username, and defer the
`DWGlobalOptions.dashpayUsername` + `dashpayRegistrationCompleted`
mirror writes until vote resolution.

- `DWContestedNameStatusService` — thin UserDefaults wrapper:
  `pendingLabel`, `recordSubmission(label:)`, `clearPending()`,
  static `isContestedLabel(_:)` FFI predicate. Single in-flight
  contested submission per identity (v1).
- `DWIdentityRegistrationCoordinator` branches after successful
  `registerDpnsName`: contested → service.recordSubmission + best-
  effort `syncContestedDpnsNames`; `handlePhaseChange` skips the
  global-mirror writes when the bookmark matches.
- `DWCurrentUserIdentityInfo.computeSnapshot` filters the pending
  contested label out of `getDpnsNames()` results so Edit Profile /
  SDK profile sheet / invitation links / payment memos don't surface
  a contested-but-not-yet-owned name.
- `HomeViewController.viewDidAppear` calls a new `syncFromNetwork()`
  on the helper to refresh blockchain DPNS names — exposes the
  upstream `GetDataContractsRequest.version = None` SDK bug which
  blocks `syncDpnsNames` (same root cause as profile writes).
- StorageExplorer `FieldRow` gets tap-to-copy with brief checkmark
  feedback — useful for copying identity IDs / Platform addresses
  out of the debug view.
- `DWDPUpdateProfileModel.update(...)` reads the *real*
  `defaultBlockchainIdentity` (not the MOCK_DASHPAY synthetic
  getter) so the SDK-vs-DashSync branch picks the right path under
  `MOCK_DASHPAY=YES`.

Status view + per-vote refresh deliberately omitted — both rely on
`fetchContestVoteState` / `syncDpnsNames` which hit the same data-
contracts gRPC bug. Can come back once the upstream fix lands.

Carveouts respected (per repeated user instruction): MainMenu FIXME
debug edits, JoinDashPayViewModel.checkUsername(),
HomeViewModel.checkJoinDashPay(), UsernameRequestsDAO,
UsernamePrefs.requestedUsernameId, RequestDetailsViewController,
VerifyIdentityScreen, VotingViewModel — none touched.

Side effects of those carveouts during voting: Join DashPay banner
stays visible, home-screen avatar stays hidden
(`dashpayRegistrationCompleted` stays NO until resolution).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
llbartekll added a commit that referenced this pull request May 28, 2026
- Mark "Known SDK issues §1" (`could not decode data contracts query`)
  as RESOLVED 2026-05-27 via the Platform protocol v11 pin
  (`SwiftDashSDKHost.swift` → `SDK(network: protocolVersion: 11)`,
  backed by upstream PR #3734).
- Row #17 stage B "Where we are": drop the "blocked by upstream
  SwiftDashSDK bug" caveat; profile editing is end-to-end verified.
- Row #17 functional-table row: same cleanup.
- Row #18a entry: rephrase the "status view comes back once
  upstream is fixed" line — it's now a scope/product decision, not
  a blocker.
- Add a new "Where we are" entry covering the v11 pin + DPNS lookup
  finalisation: `usernames: [String]` exposure, cold-launch cache
  fix, wallet-side query, Edit Profile entry-point gate on
  `hasIdentity`, tab-bar restore workaround, and the
  `DASHPAY_SWIFT_SDK_REGISTRATION` flag retirement.
- Row #19 (DPNS lookup) flips from "—" to 🌗 Flipped; consumers
  column splits availability check (done) vs. prefix search
  (`DWUserSearchModel`, travels with #18 because the consumer
  factory expects `DSBlockchainIdentity`).
- Wave 3 row: update from "not started" to "Flipped for #16/#17/#19,
  #18 still pending".
- Row #16 "Where we are": flag retirement footnote so a future
  reader doesn't grep for it and find only stale references.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
llbartekll added a commit that referenced this pull request Jun 18, 2026
CoinJoin row #20 corrected: mixing is being dropped (legacy mixing UI already retired), not migrated. The one capability that moves over — recovering/sweeping already-mixed coins into spendable balance — is implemented on both sides via ManagedCoreWallet.sweepCoinJoinAccount (platform PR #3817, awaiting merge). CoinJoin is no longer the 'keep DashSync linked indefinitely' hard blocker. Updated the functional table, 'Where we are', Hard blockers, and Wave 6.

Easy-win status promotions:
- #13 Backup seed phrase: Flipped -> Done (backup read is 100% SwiftDashSDK, no fallback; adapter already retired).
- #19 DPNS username lookup: Flipped -> Done (availability check fully on SDK; prefix search carved out to #18; dead request residue removed).
- #10 PIN-change half: close-out note (mirror retired permanently, stays on DashSync by decision).
- #7: isMinimal noted as removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
llbartekll added a commit that referenced this pull request Jul 6, 2026
New "Where we are" entry for the five reader groups moved off
DSWallet.allTransactions (tax CSV, ZenLedger, gift-card details,
CrowdNode withdrawal limits + online-account scans, request-amount
receive); #6-satellites deferred list and the #11 audit-correction
reader inventory updated — the deprecated DSTransaction filter adapter
is gone and the only remaining allTransactions consumers are the
DashPay profile data source (#18) and the onboarding stub.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QuantumExplorer added a commit that referenced this pull request Jul 8, 2026
… DashSync subsystem

Migration Row #18 — the contacts feature (dead at runtime since the
post-M6 DashSync freeze) is rebuilt end-to-end on SwiftDashSDK and the
entire DashSync implementation is removed in the same change.
E2E-verified on testnet against SwiftExampleApp driving the far side:
request sent → reciprocated → established → paid both directions.

New SDK boundary (Sources/Infrastructure/SwiftDashSDK/Contacts/):
- SwiftDashSDKContactsService: SwiftData read model (established =
  both direction rows, single row = pending; debounced
  NSManagedObjectContextDidSave refresh), PIN-gated send/accept via
  DWIdentityAuthorizer + KeychainSigner, ignoreSender (replaces the
  legacy decline, which was a TODO stub that faked failure), DPNS
  prefix search + reverse lookup (dpnsGetUsername, base58), contact
  meta (alias/note/hide via EstablishedContact + flushPersist),
  notifications read-state on the legacy DWGlobalOptions slot, and
  the payments projection (see below).
- DWIdentityKeyUpgrader: dashwallet registration derives
  AUTHENTICATION keys only, so identities registered here could not
  send contact requests. Before the first contact action, one
  IdentityUpdate adds the missing ENCRYPTION + DECRYPTION keys
  (ECDSA, MEDIUM, bounds SingleContractDocumentType(DashPay,
  "contactRequest") — Drive rejects unbound or contract-level bounds).
- DashPay background sync (15s six-step pass) start/stop wired into
  PlatformAddressSyncCoordinator alongside BLAST + shielded.
- SDK.enableLogging installed at host init — the app previously ran
  the whole SDK with Rust diagnostics muted.

Payments correctness (found live-testing):
- PersistentDashpayPayment rows exist only via the app-pulled
  projection (PlatformWalletManager.refreshDashPayPayments); the Rust
  persister never pushes them, and Sent entries are unrecoverable if
  the app dies before a projection. The service now projects on every
  sync pass, at most once a minute on snapshot refresh, on profile
  open, and immediately after every successful send.
- WalletSendService.sendToContact: pay-to-contact through the send
  boundary — spend-auth gate, then the single-shot SDK
  sendDashPayPayment (derives the DIP-15 address Rust-side), invoked
  only after the user's explicit Pay tap. Returns the exact network
  fee of the broadcast transaction (requires the platform fee-
  threading commit; see the DASHSYNC_MIGRATION.md platform pin).

SwiftUI screens (UI/DashPay/Contacts/SwiftUI/), styled to the Android
dash-wallet DashPay design (dashpay_contact_row.xml et al.): contacts
home (card rows, Accept pill + round ignore, golden pending state,
Android empty state), add-contact (debounced DPNS search, collision
detection, DashPay-key eligibility marking via identityGetKeys
mirroring the send path's key predicate), contact profile (Pay CTA,
tap-the-header collapsible contact settings, payments history, green
accept / ignore pane), notifications (New/Earlier, inline accept),
and the Android HSV avatar algorithm (hue = charIndex/36, S 0.3,
V 0.6). DPNS names render without the implied ".dash" suffix.

Deleted (163 files): the DWDP* item/factory hierarchy, contacts
VCs/models/FRC data sources, GlobalSearch, DWDashPayContactsUpdater/
Actions, DWNotificationsProvider/Data/VC/cells, the other-user
profile stack, DWDPAmount*View, dead DWFilterHeaderView, and the
pay-to-user payment plumbing (paymentInputWithUserItem — a frozen
DSIncomingFundsDerivationPath read — plus the performPayToUser chain;
the payment-confirm accept-contact checkbox is now honestly hidden).
Kept: Items/Protocols headers (type the always-nil payment userItem;
fall with the C8 processor rewrite), DWDPAvatarView (current-user
surfaces), the invitation flow (out of scope per Row #16).

The Contacts/Explore tabs now gate on
DWCurrentUserIdentityInfo.hasIdentity — the old DashSync
defaultBlockchainIdentity gate hid them from SDK-registered
identities.

Requires ../platform on local/tx-decode-plus-v4.1-dev (see the
platform pin note in DASHSYNC_MIGRATION.md) and an xcframework
rebuild.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QuantumExplorer added a commit that referenced this pull request Jul 8, 2026
From a deleted-vs-new gap audit of the Row #18 contacts rebuild, restore
the four legacy behaviors worth keeping:

1. Un-cap DPNS search (limit 10 → 0 = SDK default 100, the legacy page
   size); move eligibility checks to lazy per-row onAppear so a large
   result set doesn't fan out a key query per hit.
2. Enrich the contact-profile payment rows: current-rate fiat, tap
   through to the standard tx-detail screen (reusing TXDetailVCWrapper
   via navigationDestination), and the 'direct-to-address payments
   aren't retained' caption. Non-resolving txs stay non-tappable.
3. Add outgoing 'You sent a contact request to X' notification entries.
4. Add a search-result preview/confirm sheet (avatar, name, framing,
   collision-appropriate CTA) as the single send/accept surface.

Honest limitation: the SDK has no on-chain profile fetch for an
arbitrary identity (cache-only reads), so a true stranger shows
username + placeholder, not a fetched bio.

Deliberately not restored: the pay-confirm accept-contact checkbox and
post-payment profile modal (superseded), and the invitation promos
(blocked on the not-yet-migrated DashSync invitation flow).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QuantumExplorer added a commit that referenced this pull request Jul 9, 2026
… DashSync subsystem

Migration Row #18 — the contacts feature (dead at runtime since the
post-M6 DashSync freeze) is rebuilt end-to-end on SwiftDashSDK and the
entire DashSync implementation is removed in the same change.
E2E-verified on testnet against SwiftExampleApp driving the far side:
request sent → reciprocated → established → paid both directions.

New SDK boundary (Sources/Infrastructure/SwiftDashSDK/Contacts/):
- SwiftDashSDKContactsService: SwiftData read model (established =
  both direction rows, single row = pending; debounced
  NSManagedObjectContextDidSave refresh), PIN-gated send/accept via
  DWIdentityAuthorizer + KeychainSigner, ignoreSender (replaces the
  legacy decline, which was a TODO stub that faked failure), DPNS
  prefix search + reverse lookup (dpnsGetUsername, base58), contact
  meta (alias/note/hide via EstablishedContact + flushPersist),
  notifications read-state on the legacy DWGlobalOptions slot, and
  the payments projection (see below).
- DWIdentityKeyUpgrader: dashwallet registration derives
  AUTHENTICATION keys only, so identities registered here could not
  send contact requests. Before the first contact action, one
  IdentityUpdate adds the missing ENCRYPTION + DECRYPTION keys
  (ECDSA, MEDIUM, bounds SingleContractDocumentType(DashPay,
  "contactRequest") — Drive rejects unbound or contract-level bounds).
- DashPay background sync (15s six-step pass) start/stop wired into
  PlatformAddressSyncCoordinator alongside BLAST + shielded.
- SDK.enableLogging installed at host init — the app previously ran
  the whole SDK with Rust diagnostics muted.

Payments correctness (found live-testing):
- PersistentDashpayPayment rows exist only via the app-pulled
  projection (PlatformWalletManager.refreshDashPayPayments); the Rust
  persister never pushes them, and Sent entries are unrecoverable if
  the app dies before a projection. The service now projects on every
  sync pass, at most once a minute on snapshot refresh, on profile
  open, and immediately after every successful send.
- WalletSendService.sendToContact: pay-to-contact through the send
  boundary — spend-auth gate, then the single-shot SDK
  sendDashPayPayment (derives the DIP-15 address Rust-side), invoked
  only after the user's explicit Pay tap. Returns the exact network
  fee of the broadcast transaction (requires the platform fee-
  threading commit; see the DASHSYNC_MIGRATION.md platform pin).

SwiftUI screens (UI/DashPay/Contacts/SwiftUI/), styled to the Android
dash-wallet DashPay design (dashpay_contact_row.xml et al.): contacts
home (card rows, Accept pill + round ignore, golden pending state,
Android empty state), add-contact (debounced DPNS search, collision
detection, DashPay-key eligibility marking via identityGetKeys
mirroring the send path's key predicate), contact profile (Pay CTA,
tap-the-header collapsible contact settings, payments history, green
accept / ignore pane), notifications (New/Earlier, inline accept),
and the Android HSV avatar algorithm (hue = charIndex/36, S 0.3,
V 0.6). DPNS names render without the implied ".dash" suffix.

Deleted (163 files): the DWDP* item/factory hierarchy, contacts
VCs/models/FRC data sources, GlobalSearch, DWDashPayContactsUpdater/
Actions, DWNotificationsProvider/Data/VC/cells, the other-user
profile stack, DWDPAmount*View, dead DWFilterHeaderView, and the
pay-to-user payment plumbing (paymentInputWithUserItem — a frozen
DSIncomingFundsDerivationPath read — plus the performPayToUser chain;
the payment-confirm accept-contact checkbox is now honestly hidden).
Kept: Items/Protocols headers (type the always-nil payment userItem;
fall with the C8 processor rewrite), DWDPAvatarView (current-user
surfaces), the invitation flow (out of scope per Row #16).

The Contacts/Explore tabs now gate on
DWCurrentUserIdentityInfo.hasIdentity — the old DashSync
defaultBlockchainIdentity gate hid them from SDK-registered
identities.

Requires ../platform on local/tx-decode-plus-v4.1-dev (see the
platform pin note in DASHSYNC_MIGRATION.md) and an xcframework
rebuild.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QuantumExplorer added a commit that referenced this pull request Jul 9, 2026
From a deleted-vs-new gap audit of the Row #18 contacts rebuild, restore
the four legacy behaviors worth keeping:

1. Un-cap DPNS search (limit 10 → 0 = SDK default 100, the legacy page
   size); move eligibility checks to lazy per-row onAppear so a large
   result set doesn't fan out a key query per hit.
2. Enrich the contact-profile payment rows: current-rate fiat, tap
   through to the standard tx-detail screen (reusing TXDetailVCWrapper
   via navigationDestination), and the 'direct-to-address payments
   aren't retained' caption. Non-resolving txs stay non-tappable.
3. Add outgoing 'You sent a contact request to X' notification entries.
4. Add a search-result preview/confirm sheet (avatar, name, framing,
   collision-appropriate CTA) as the single send/accept surface.

Honest limitation: the SDK has no on-chain profile fetch for an
arbitrary identity (cache-only reads), so a true stranger shows
username + placeholder, not a fetched bio.

Deliberately not restored: the pay-confirm accept-contact checkbox and
post-payment profile modal (superseded), and the invitation promos
(blocked on the not-yet-migrated DashSync invitation flow).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QuantumExplorer added a commit that referenced this pull request Jul 9, 2026
…subsystem (#787)

* fix(tx): pass ManagedPlatformWallet to the core TransactionBuilder calls

setFunding/addInputs/buildSigned take ManagedPlatformWallet on every
published platform ref (v4.1-dev's #3970 API); the ManagedCoreWallet
overloads the call sites were written against never shipped. The
platform wallet is already in scope; ManagedCoreWallet stays for
broadcastTransaction only.

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

* feat(contacts)!: rebuild DashPay contacts on SwiftDashSDK, delete the DashSync subsystem

Migration Row #18 — the contacts feature (dead at runtime since the
post-M6 DashSync freeze) is rebuilt end-to-end on SwiftDashSDK and the
entire DashSync implementation is removed in the same change.
E2E-verified on testnet against SwiftExampleApp driving the far side:
request sent → reciprocated → established → paid both directions.

New SDK boundary (Sources/Infrastructure/SwiftDashSDK/Contacts/):
- SwiftDashSDKContactsService: SwiftData read model (established =
  both direction rows, single row = pending; debounced
  NSManagedObjectContextDidSave refresh), PIN-gated send/accept via
  DWIdentityAuthorizer + KeychainSigner, ignoreSender (replaces the
  legacy decline, which was a TODO stub that faked failure), DPNS
  prefix search + reverse lookup (dpnsGetUsername, base58), contact
  meta (alias/note/hide via EstablishedContact + flushPersist),
  notifications read-state on the legacy DWGlobalOptions slot, and
  the payments projection (see below).
- DWIdentityKeyUpgrader: dashwallet registration derives
  AUTHENTICATION keys only, so identities registered here could not
  send contact requests. Before the first contact action, one
  IdentityUpdate adds the missing ENCRYPTION + DECRYPTION keys
  (ECDSA, MEDIUM, bounds SingleContractDocumentType(DashPay,
  "contactRequest") — Drive rejects unbound or contract-level bounds).
- DashPay background sync (15s six-step pass) start/stop wired into
  PlatformAddressSyncCoordinator alongside BLAST + shielded.
- SDK.enableLogging installed at host init — the app previously ran
  the whole SDK with Rust diagnostics muted.

Payments correctness (found live-testing):
- PersistentDashpayPayment rows exist only via the app-pulled
  projection (PlatformWalletManager.refreshDashPayPayments); the Rust
  persister never pushes them, and Sent entries are unrecoverable if
  the app dies before a projection. The service now projects on every
  sync pass, at most once a minute on snapshot refresh, on profile
  open, and immediately after every successful send.
- WalletSendService.sendToContact: pay-to-contact through the send
  boundary — spend-auth gate, then the single-shot SDK
  sendDashPayPayment (derives the DIP-15 address Rust-side), invoked
  only after the user's explicit Pay tap. Returns the exact network
  fee of the broadcast transaction (requires the platform fee-
  threading commit; see the DASHSYNC_MIGRATION.md platform pin).

SwiftUI screens (UI/DashPay/Contacts/SwiftUI/), styled to the Android
dash-wallet DashPay design (dashpay_contact_row.xml et al.): contacts
home (card rows, Accept pill + round ignore, golden pending state,
Android empty state), add-contact (debounced DPNS search, collision
detection, DashPay-key eligibility marking via identityGetKeys
mirroring the send path's key predicate), contact profile (Pay CTA,
tap-the-header collapsible contact settings, payments history, green
accept / ignore pane), notifications (New/Earlier, inline accept),
and the Android HSV avatar algorithm (hue = charIndex/36, S 0.3,
V 0.6). DPNS names render without the implied ".dash" suffix.

Deleted (163 files): the DWDP* item/factory hierarchy, contacts
VCs/models/FRC data sources, GlobalSearch, DWDashPayContactsUpdater/
Actions, DWNotificationsProvider/Data/VC/cells, the other-user
profile stack, DWDPAmount*View, dead DWFilterHeaderView, and the
pay-to-user payment plumbing (paymentInputWithUserItem — a frozen
DSIncomingFundsDerivationPath read — plus the performPayToUser chain;
the payment-confirm accept-contact checkbox is now honestly hidden).
Kept: Items/Protocols headers (type the always-nil payment userItem;
fall with the C8 processor rewrite), DWDPAvatarView (current-user
surfaces), the invitation flow (out of scope per Row #16).

The Contacts/Explore tabs now gate on
DWCurrentUserIdentityInfo.hasIdentity — the old DashSync
defaultBlockchainIdentity gate hid them from SDK-registered
identities.

Requires ../platform on local/tx-decode-plus-v4.1-dev (see the
platform pin note in DASHSYNC_MIGRATION.md) and an xcframework
rebuild.

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

* feat(dashpay): restore four legacy contact affordances on SwiftDashSDK

From a deleted-vs-new gap audit of the Row #18 contacts rebuild, restore
the four legacy behaviors worth keeping:

1. Un-cap DPNS search (limit 10 → 0 = SDK default 100, the legacy page
   size); move eligibility checks to lazy per-row onAppear so a large
   result set doesn't fan out a key query per hit.
2. Enrich the contact-profile payment rows: current-rate fiat, tap
   through to the standard tx-detail screen (reusing TXDetailVCWrapper
   via navigationDestination), and the 'direct-to-address payments
   aren't retained' caption. Non-resolving txs stay non-tappable.
3. Add outgoing 'You sent a contact request to X' notification entries.
4. Add a search-result preview/confirm sheet (avatar, name, framing,
   collision-appropriate CTA) as the single send/accept surface.

Honest limitation: the SDK has no on-chain profile fetch for an
arbitrary identity (cache-only reads), so a true stranger shows
username + placeholder, not a fetched bio.

Deliberately not restored: the pay-confirm accept-contact checkbox and
post-payment profile modal (superseded), and the invitation promos
(blocked on the not-yet-migrated DashSync invitation flow).

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

* feat(home): testnet faucet shortcut, default over Spend on testnet

New 'Request 1 tDash' shortcut (testnet only): copies the wallet's
receive address and opens the testnet faucet in-app, mirroring the
Explore screen's get-test-dash flow. On testnet it replaces Spend as
the default fourth shortcut and joins the customization list; a saved
faucet shortcut degrades to Spend while on mainnet (config untouched).

The request itself stays in the web page — the faucet API requires its
anti-bot challenge token, which only the page can produce (verified:
bare POST to /api/core-faucet returns 400 'Captcha token required').

Also fixes the Explore faucet link: the faucet no longer answers on
port 80, so the http:// URL opened nothing.

The new enum case is appended last — raw values persist in
DWGlobalOptions.shortcuts.

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

* style(home): shorten the faucet shortcut label to '1 tDash'

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

* feat(home): faucet shortcut drives the request in-app, web only as fallback

The '1 tDash' shortcut now calls the SDK's TestnetFaucet client
(promoted from SwiftExampleApp — platform 5f53767be7): solve the
faucet's soft cap.js proof-of-work on-device, POST the receive address
to /api/core-faucet, show the result in a HUD. No web page on the
happy path. Rate limit or any failure falls back to the previous
behavior: copy the address, open the web faucet in-app, log why.

Mechanism live-verified against faucet.thepasta.org: challenge ->
solve -> redeem -> 200, 1 tDash delivered (txid 395eeb08...).

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

* fix(dashpay): enforce the spending limit and reject overflowing amounts on pay-to-contact

Review fixes (llbartekll):
- sendToContact now passes spendAmount to authorizeSend, engaging the
  C7.4 biometric spending limit; without it the gate was non-monetary
  and Face ID alone authorized a contact payment of any size.
- PayContactSheet validates the entered amount in Decimal space before
  the UInt64 conversion; NSDecimalNumber.uint64Value wraps modulo
  2^64, so 2^64+1 duffs aliased to 1 duff, passed the range check, and
  broadcast the wrong amount while the success screen echoed the
  typed text.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
llbartekll added a commit that referenced this pull request Jul 9, 2026
…etailCellView

With the userItem plumbing gone, the DWDP item protocol layer lost its
last consumers. Deleted: the 12 protocol/associated-data headers under
UI/DashPay/Items/Protocols (7 were orphaned since the #787 contacts
teardown; DWDPBasicUserItem/DWDPBasicItem/DWDPBlockchainIdentityBackedItem
fell with the plumbing — DWDPBasicUserItem itself was DS-tainted via
DSFriendRequestEntity/DSBlockchainIdentity returns), the ObjC
DWTitleDetailCellView.{h,m} (zero code/xib consumers — the confirm
sheet renders through the Swift TitleValueCell), and its sole dependent
DWDPSmallContactView.{h,m}.

DWTitleDetailItem drops the userItem member and the _User style;
DWTitleDetailCellModel drops the user initializer. Bridging header and
pbxproj (38 lines; DWTitleDetailCellView.m had build-file entries in
both targets) scrubbed; plutil -lint OK.

Kept deliberately: DWDPAvatarView (live on Home/invites/username/profile
surfaces; its blockchainIdentity property is Row #18 scope).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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