Repository navigation
fix: separate usdt recovery backups from paykit - #1118
Draft
ben-kaufman wants to merge 6 commits into
Draft
ben-kaufman wants to merge 6 commits into
ben-kaufman wants to merge 6 commits into
Conversation
1 task
Collaborator
|
Triage: 3.1.0. It fixes shipped USDT recovery backups, and 3.1.0 is due 28 Oct. |
4 tasks done
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Twin: synonymdev/bitkit-android#1681
Dependency: #1115
This PR separates acknowledged USDT recovery backups from the full wallet backup, so an ordinary transfer does not export Paykit state or acquire a Pubky lock before broadcast.
Description
0.8.0-rc11, including the restore-order fix from fix: preserve USDT application identity across backup merges bitkit-core#179 and its regenerated bindings.Out of Scope
Native Pubky authentication recovery is tracked in pubky/pubky-homeserver#741. This PR does not release SDK artifacts, replay uncertain contact mutations or establish the historical contact-error cause.
Design
N/A — no new design supplied; Retry uses the existing send-screen controls.
Preview
Unavailable for the backup-failure screen: the controlled funded device fixture is not available. Unit tests are not presented as visual verification.
QA Notes
Setup
Use the committed app dependency pins for automated tests. The complete device journey requires an owned disposable test wallet and recipient, controlled USDT RPC/bundler, encrypted VSS endpoint and Pubky homeserver with fault injection. Standard staging does not provide this combined fixture. Do not use production funds or reset an existing wallet. Record operation IDs, signed bytes, acknowledgement and broadcast counts; see the committed USDT recovery backup document and journey prerequisites.
For the native protocol subset, follow the pinned loopback fixture recipe in synonymdev/bitkit-core#180. It uses a public test mnemonic without funds, real native signing and encrypted VSS, and separate prepare/resume/restore processes. The earlier combined run below used local Core
c393f8e0, Paykite79b7bbband Pubky65a331e0bindings; these overrides are not the committed release pins.For the deployed-contract UI subset, use the fork provider at Core
c393f8e0with Anvil v1.8.6 on loopback port18545, chain42161, Prague hardfork and Arbitrum block517943110; run its Node provider on18546 using the public fixture mnemonic. RunUsdtWalletUITests/testPaymentUsesUsdtOnLocalArbitrumForkon a newly created dedicated simulator. All funds and transactions stay in the local fork. This subset uses the normal VSS endpoint and does not inject backup or Pubky faults.Journeys
usdt-independent-recovery.xml— Pubky outage with working VSS, actual backup failure before broadcast, lost acknowledgements, repeated/automatic retry, closing/restarting, interrupted restore/migration and concurrent writers; uses the same actions on both platforms.Manual Tests
N/A — the controlled device cases are specified in J1; backend fault injection is an explicit prerequisite.
Automated Checks
UsdtNativeRecoveryIntegrationTests.swift— real encrypted backup rejection/lost acknowledgements, separate-process restart, fresh-database restore and the original signed operation before and after retry.UsdtRecoveryBackupTests.swift— independent uploads, immutable concurrent writers, lost acknowledgements, byte-order/hash compatibility and fail-closed restore.UsdtWalletUITests.swift— targets the current address and swipe controls while preserving the local-fork payment, cancellation and offline restart assertions.BackupServiceTests.swift,PaykitPaymentStateBackupTests.swift,UsdtWalletManagerTests.swiftandUsdtSendFailureTests.swift— migration checkpoints, retained work, proof revalidation and same-transfer recovery feedback.Evidence
At
aeeaa020, Xcode 26.1 / iPhone 17 / iOS 26.5 ran the CI-equivalent selection: 2,889 unit tests passed; UI results were 38 passed, four fixture-dependent skips and one failure. The failing comma-region manual-entry case waited on the Bitcoin node's startup screen, with both recovery gates absent. It reproduced on the unchanged signed parent008b2e5e; a diagnostic 90-second wait also failed and was discarded. The underlying node-startup delay remains unknown; that historical run did not pass the full UI target. The later complete current-head run below passed with explicit fixture skips.SwiftFormat 0.64 full-tree lint has an empty report (0/846 files, 77 excluded). Translation validation has zero errors; all 15 warnings were verified against the parent after line-number normalization. Journey XML parses. Independent review and bounded rechecks found no remaining actionable issues.
At test commit
9a763eb4, the combined local SDK build passed 2,889 unit tests and changed-file SwiftFormat lint. Native rejection and lost-acknowledgement sequences passed prepare, resume and restore; bidirectional iOS/Android encrypted snapshot restore also passed. iOS calls the actual BackupService recovery handler, checks zero unrelated backup captures and counts every attempted broadcast. The initial interrupted rejection run is not counted; a fresh complete sequence passed.Each native failure phase verifies zero broadcast attempts before its own recovery acknowledgement, unchanged signed operation bytes on retry and one unique payment. Full-wallet sentinel bytes remain unchanged. This verifies the native protocol subset, not the complete J1 journey.
At adoption commit
646670df, the normal published Core RC11 package resolves to22e0acc3; its downloaded archive matches the manifest SHA256f7ef2ffb625498c651111cb0f5a177893c5abd91c89b077e11abf0ee289cd544. With no local SDK overrides, all 2,889 unit tests passed and full SwiftFormat 0.64 lint reported zero violations across 847 files. Native rejected-backup and lost-acknowledgement cases each passed prepare, resume and restore on the owned iOS simulator. The final documentation-only wording correction was independently reviewed and checked; production and package inputs were unchanged after the unit run. All four PR commits are signed and GitHub reportsverified=true,reason=valid.With Android
258bf9e5b, fresh encrypted restore passed in both directions using each app's normal published Core RC11 dependency. Across both platforms, all 16 native failure/recovery/restore phases preserved the same signed operation and acknowledgement-before-submission ordering. This remains protocol-subset evidence, not completion of J1.At acknowledgement fix
5851185c, a successful refresh with no backup callback no longer clears recovery feedback. Progress advances only after the native backup callback is acknowledged; failed persistence retains the error and Retry action. The focused regression fails on unchanged646670dfand passes with the repair. Final CI-equivalent unit selection passed 2,890 tests, zero failures/skips; full SwiftFormat 0.64 reported zero violations across 847 files. Complete diagnostics were inspected: compiler metadata warnings and negative-fixture runtime diagnostics are inherited. Independent review found no remaining issue. All five commits against the live parent are signed and GitHub reportsverified=true,reason=valid. This follow-up has component/adapter coverage; the earlier native protocol evidence remains tied to the commits above.A later diagnostic launch at
5851185ccompleted LDK construction in 1.08 seconds and subsequently synchronized and uploaded recovery data. The unchanged comma-region manual-entry UI test then passed in 35 seconds on the owned simulator. This does not establish the earlier delay's cause. A subsequent complete current UI target finished with exit code zero; the finalized XCTest bundle confirms 39 passing executions (ten test methods, including 30 dynamic runs), four opt-in fixture skips and zero failures. The skips are three Trezor emulator cases and the local Arbitrum fork payment case. Compiler metadata and simulator accessibility warnings match the prior run. Hosted SwiftFormat for this head also passed with zero violations across 847 files.At signed test repair
6ead1895, the previously skipped local Arbitrum fork payment test ran on a new dedicated iPhone 17 / iOS 26.5 simulator and passed with zero skips. The test now targets the actual address button and draggable confirmation knob, retaining the exact recipient assertion and cancel-then-confirm checks. It sent one synthetic USDT, confirmed, retained zero native ETH and displayed saved activity after an offline restart. The local Anvil receipt contains one successful user operation and exactly one recipient token transfer. This executes deployed contract code in a fork; it does not validate production paymaster pricing or the complete Paykit/fault-injection J1 journey. The final unit selection passed 2,890 tests with no failures/skips; full SwiftFormat reported zero violations across 847 files. Complete diagnostics and independent review were clean apart from unchanged AppIntents metadata warnings. All six actual-base PR commits are signed and GitHub reportsverified=true,reason=valid.Gaps
J1 has not run as a complete UI/Paykit/deployed-contract journey. The protocol fixture does not execute deployed contracts or exercise a real Pubky outage. Full wallet migration and concurrent state changes remain covered by component tests rather than this native fixture; Android's native store test does not exercise all BackupRepo orchestration.
This remains draft pending the remaining integrated validation and published Paykit/Pubky adoption. Core #179 and RC11 preparation #181 are merged, and the published Core RC11 dependency is adopted and validated here. The Android twin adopted the published Maven package in
258bf9e5band now includes the acknowledgement repair atdc5a47d90; its native libraries match the published debug symbols. Local combination builds and native tests passed with Paykit lease-expiry safety from pubky/paykit-rs#211 and authentication recovery from pubky/pubky-homeserver#741; compatible published Paykit/Pubky artifacts are still unavailable. No app release or deployment is part of this PR.The later device-sleep lease repair at Paykit
461864a4passed 1,557 Rust tests, both native binding builds and full generated Android checks, but has not been adopted in this app. The combined app/native evidence above used Paykite79b7bbb. Core RC11 does not contain the Pubky authentication or Paykit lease fixes.The legacy complete wallet format remains supported. Older apps cannot read journal-only operations; downgrade recovery is limited to the last complete wallet backup. Records are not pruned, and immutable writes do not make multi-page listing atomic or coordinate simultaneous spending by multiple devices.
Models used
gpt-6-astra(reasoning:xhigh)gpt-6-astra(reasoning:xhigh)gpt-6-astra(reasoning:xhigh)