Skip to content

feat: add spark via breez sdk - #1128

Draft
ovitrif wants to merge 6 commits into
masterfrom
feat/breez-spark-lightning
Draft

ovitrif wants to merge 6 commits into
masterfrom
feat/breez-spark-lightning

Conversation

@ovitrif

@ovitrif ovitrif commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Twin: synonymdev/bitkit-android#1697

This PR keeps Lightning in Bitkit after Blocktank stopped selling channels: on top of the Blocktank sunset (#1127), Spark becomes the easy option where Transfer to Spending now leads to manual setup. Savings to Spending funds a Breez SDK on Spark wallet, and Lightning sends and receives fall back to it whenever no channel can carry the payment. Existing channels keep working until they close, and ldk-node keeps running the on-chain wallet.

Description

  • Fits Spark onto the sunset shape: while Spark is ready, the Funding screen leads with Transfer from Savings and Use Other Wallet, above Manual Setup, and the Savings and Spending transfer buttons open a Spark-only Transfer to Spending flow (amount, confirm, deposit) instead of the Transfer Unavailable sheet. Without Spark, everything stays as the sunset left it. Transfer from a hardware wallet stays unavailable.
  • Claims deposits early: once Spark lists the deposit, the deposit screen asks the provider for its early-claim quote once. When the provider offers to credit it now (0 confirmations) or after 1 or 2, and the fee is above the wallet's cap, the screen offers both fees: use it now for the early fee, or wait for 3 confirmations, about 30 minutes, for the standard one. Accepting calls claimDeposit with that fee as the deposit's own ceiling, so the SDK keeps retrying the early claim as confirmations arrive. An early quote within the cap is claimed by the SDK with no question; with no early quote, the screen shows the standard claim and its fee.
  • Adds the Breez SDK on Spark (breez-sdk-spark-swift 0.27.2, exact) with SparkManager, so that a Spark wallet starts beside the node from the same recovery phrase and passphrase. Spark derives its own keys on m/8797555', so there is no new phrase to back up.
  • Routes Lightning receives to Spark when no ready channel has the inbound capacity, so the receive sheet shows a Lightning invoice again without channels.
  • Routes Lightning sends and their fee estimates to Spark when no channel has the outbound capacity and the Spark balance covers the amount, so users without channels can pay invoices.
  • Raises Spark payments as the node's own payment events while the node runs and records them as Lightning activity, so the received sheet, send success screen and activity list work for both rails. Routing goes through a hook in LightningService that only the app sets, so the notification extension never loads Breez.
  • Adds the Spark balance to the Spending balance; the most a payment can send is the larger of the channel and Spark balances, since one payment cannot split across rails. Deposits Spark has seen but not yet claimed show as in transfer to Spending.
  • Funds Spark in Savings to Spending, so that it sends on-chain at the fast fee rate to the Spark deposit address with no service fee and no channel options.
  • Withdraws the whole Spark balance to an on-chain address in Spending to Savings before closing channels, so that the transfer works for users with only a Spark balance.
  • Reads a BREEZ_API_KEY build setting, so that mainnet builds without a key keep Spark off; regtest builds use Lightspark's hosted regtest, which needs no key.
  • Shows Spark at the top of Lightning Connections like a channel: its balance and each deposit in progress with its confirmations and a link to the transaction. Its detail screen shows the provider with a short trust note, pending and claimed deposits with the claim fee, and Transfer to Savings.
  • Pays a Lightning invoice from another Spark wallet as a Spark transfer on regtest, where Spark has no Lightning network, so two dev builds can pay each other's invoices; dev builds also show Spark's deposit address on the Spark screen, to fund it from Lightspark's regtest faucet.
  • Shows the expected Spark claim fee on the Transfer to Spending confirm screen in place of the service fee, and what reaches Spending after it, so the user sees the full cost before the swipe.
  • Lists a Transfer to Spending deposit as pending in Lightning Connections and the Spending balance as soon as the app broadcasts it, from the txid it already has, and asks Spark to sync at once; Spark's own deposit state takes over when the SDK lists it. Before, the deposit showed only after the SDK's next background sync, up to 60 seconds later.
  • Draws Spark's balance bar as one full-width spending bar and shows receiving as No limit in the Lightning Connections header, in the same style and with the same arrow as the spending figure, whenever Spark is ready, whatever its balance or channels, because Spark receives without inbound liquidity; Receive's amount check no longer asks for more liquidity or a CJIT while Spark can receive; hides "Set up in background" (Blocktank's order-paid push) and Learn More (channel liquidity costs) on Spark's Transfer to Spending confirm.
  • Publishes the Spark invoice as Bitkit's Paykit Lightning endpoint when no channel can receive, so a Spark-only wallet still lists a Lightning endpoint; Paykit requests paid over Lightning already go through Spark when no channel can carry them.
  • Reads BREEZ_API_KEY from an optional, gitignored Secrets.xcconfig through a new Bitkit.xcconfig base config; copy Secrets.xcconfig.template and paste the key (README, Build secrets). Without the file the app builds with Spark off on mainnet. TestFlight is archived locally (Docs/RELEASE.md §2), so the releaser adds the file first; a Release-only build phase fails the build when the key is empty, so Spark can't ship switched off, and Docs/RELEASE.md and the release command carry the step.
  • Backs up Spark's unilateral exit data to VSS as its own category, SPARK_EXIT, encrypted like the other backups. It is exported again when Spark connects and whenever the SDK reports UnilateralExitStateChanged, and on restore it is imported right after Spark connects, without contacting the operators, so a wallet restored on a new device can still exit on-chain while the operators are unreachable. The category shows in Backup settings only where Spark runs.
  • Pays a scanned Lightning invoice through Spark when there are no channels: the scan check no longer rejects it before Spark is considered, and the insufficient-balance toasts count Spark's balance. Drops the connection counter on Settings › Advanced › Lightning Connections, as on Android.
  • Settles a Spark payment from Spark's completion event, which now reaches the send screen and Paykit, and makes the remaining Lightning flows count Spark where they assumed channels (see Channel-only audit under QA Notes).
  • Records a Spark send's fee when Spark's next sync reports it, since its completion event carries a fee of 0.
  • Shows a Spark deposit and a Spark withdrawal's arrival in Savings as transfers, not as plain sent and received payments, lists each withdrawal with the fee Spark kept on the Spark screen, and draws the Spark bar empty at a 0 balance.
  • Shows the most Spark may keep to claim a deposit on the Transfer to Spending confirm screen, from the fee cap the wallet sets, since the provider quotes the real claim fee only once the deposit exists. Mainnet claims of 198 and 297 sats sat above the old estimate of 99.
  • Finishes a Transfer to Savings that only withdraws Spark without waiting for a Lightning peer or a fixed pause, so the success screen shows as soon as the withdrawal is sent.
  • Settles a Spark send that finished inside the send call, as Spark-to-Spark payments do, by checking Spark's payment list once the send screen starts watching, so a paid Paykit request no longer stays on Payment Pending.
  • Stops loading a payment request the user opened when its payment details fail to resolve, and shows that the contact's payment details aren't ready yet, instead of spinning through 14 retries.

Out of Scope

  • Push notifications for Spark receives: Blocktank's wake notifications go away, and Breez's per-payment webhook is tied to its Lightning address server.
  • Spark status: the SDK reports Spark outages; the Spending card doesn't show them yet.
  • Running a unilateral exit: the exit data is backed up and restored, but no screen runs the SDK's prepare_recover_funds / recover_funds yet.
  • Transfer to Spending from a hardware wallet through Spark.
  • Raising the wallet-wide claim fee cap so every deposit claims early by itself; the fee is shown and accepted per deposit instead.
  • Spark-specific copy and design across transfer and receive screens.
  • Lightning address, LNURL and BOLT12 through Spark.
  • bitkit-core: the integration lives in the app, since Breez ships its own Android and iOS bindings and both build beside ldk-node.

Risks for review

  • Trust model. Spark is not self-custody in the channel sense: funds are safe while at least one of three operators (Lightspark, Breez, Flashnet) deletes old keys, and 2 of 3 sign. The operator code has a per-wallet freeze switch, and Spark's terms let Lightspark suspend access.
  • Exit data backup size. A unilateral exit needs leaf data the SDK keeps on the device, and it can reach several MB. This PR backs it up to VSS as SPARK_EXIT; upstream VSS accepts request bodies up to 1 GiB by default, but a large wallet's upload against Synonym's VSS is untested.
  • Fees. Sending Lightning costs 0.25% plus routing; receiving is free for the user (the payer pays 0.15% through route hints). The deposit claim may pay up to the recommended fee plus 2 sat/vB plus 0.2% of the deposit. Withdrawing costs 250 × sat/vB + 750 sats.
  • Savings to Spending costs more for small amounts. On mainnet (case 3), a 15,000 sat transfer paid 610 sats on-chain and Spark kept 297 sats to claim it, so Spending got 14,703 sats: 907 sats, about 6% of the transfer. The claim fee is the SDK's standard claim, the fastest recommended fee rate times a 99 vbyte claim transaction (CLAIM_TX_SIZE_VBYTES, deposits.rs), so it is a flat cost that weighs heavily on small transfers. The confirm screen now shows it as Claim fee and shows what reaches Spending after it.
  • Slower Savings to Spending without an early claim (UX regression). Blocktank opened a zero-conf channel, so only the order payment needed 1 confirmation, about 10 minutes. Spark claims a deposit after 3 confirmations by default, about 30 minutes. Breez documents faster claims (Claiming on-chain deposits): an instant claim at 0 confirmations, offered for some deposits only, and an expedited claim at 1 or 2 confirmations, both fronted by the Spark Service Provider for a higher fee. The SDK takes the fastest claim whose fee fits the max deposit claim fee (config); the default is sized for the standard claim, and this PR raises it to the recommended rate plus 2 sat/vB plus 0.2% of the deposit. On Android's mainnet run that cap did not buy an early claim, so this PR now quotes each deposit and lets the user accept the early fee, which gives that deposit its own higher cap. Whether a deposit gets an early quote, and at which depth, is the provider's call per deposit, so some top-ups still wait for 3 confirmations.
  • E2E on regtest. Dev builds connect Spark to Lightspark's hosted regtest with no key, so once this PR leaves draft, E2E specs that expect the Transfer Unavailable sheet take the Spark route whenever that regtest is reachable from CI.
  • Closed-app receive. A payment received while the app is closed is claimed on the next sync; it is not signalled by push, so no notification arrives until the app opens.
  • No BOLT12 on Spark yet.
  • App size. Breez ships as its own dynamic framework, about 9.3 MB for device arm64 uncompressed; it links beside ldk-node and bitkit-core without duplicate symbols.
  • API key and dependency. Mainnet needs a Breez API key, and Lightning goes through a Spark service provider (Lightspark), a dependency like Blocktank was.
  • Testing reach. Spark's regtest is Lightspark's hosted chain with no Lightning, so dev builds cannot test Lightning payments or deposits from Bitkit's regtest; on dev, Savings to Spending sends regtest coins to an address Spark never sees.

Design

N/A — no design available. Figma has no Spark or unlimited-receiving state for the Lightning Connections header, so No limit uses the same style and arrow as the spending figure beside it; @aldertnl, a design for this state is still open.

Preview

Case 1 on a regtest simulator build without channels: the Spending invoice comes from Spark.

ios-receive-spark2x.mp4

Case 10 on a regtest simulator build, staged with a local hook (not in this PR) for the balance and the claimed deposit; the pending deposit is the wallet's real regtest transaction, and its confirmations went from 0/3 to 3/3 as blocks were mined.

Lightning Connections → Spark (10) Spark detail, top and bottom (10)
ios-spark-screens2x.mp4

On a regtest simulator build with a staged 14,703 sat Spark balance and a pending deposit (its transaction id masked): Lightning Connections and the Spark detail with the full-width bar and receiving shown as No limit, and the Spark confirm screen with the claim fee and without the background toggle and Learn More.

Lightning Connections Spark detail Spark confirm

QA Notes

Setup

  • Mainnet build with BREEZ_API_KEY in Secrets.xcconfig (copy Secrets.xcconfig.template), and small amounts.
  • Dev build (regtest) needs no key (Testing and development). Spark's regtest is Lightspark's own chain, separate from Bitkit's staging regtest, and has no Lightning network, so on dev:
    • Spark start-up, Spark invoices, Spark connections and the Savings to Spending screens work.
    • Spark is funded from Lightspark's regtest faucet, sent to the deposit address on the Spark screen (Settings › Advanced › Lightning Connections › Spark); it is credited after 1 confirmation on regtest.
    • Two dev builds with Spark balances pay each other's Lightning invoices as Spark transfers.
    • Savings to Spending broadcasts on Bitkit's staging regtest, which Spark does not see, so the deposit is never claimed; Spending to Savings withdraws on Spark's chain, which Bitkit does not see.
    • Spark's chain exposes no public Electrum server, only an Esplora-compatible REST API at https://regtest-mempool.us-west-2.sparkinfra.net/api (the SDK's own regtest default, sdk_builder.rs). It lacks /fee-estimates, which ldk-node needs to start, so a dev build cannot point its node at Spark's chain as-is.

Journeys

  • J1: new transfer/spark-transfer-to-spending.xml — with Spark ready, the transfer buttons and Funding open the Spark amount and confirm screens.
  • J2: updated transfer/transfer-unavailable-sheet.xml — now needs Spark not running, since a ready Spark replaces the sheet.

Manual Tests

  • 16 to 19 are new for the rebuilt flow on the sunset shape and early claims.
  • 1. Dev, new wallet with no channels → Receive shows Auto and Spending tabs, and the Spending invoice's payee is Spark's node, not the LDK node — Spark's regtest is not in the journey environment.
  • 2. Dev, fund Savings, Transfer to Spending → amount max is the on-chain budget, confirm shows 0 service fee and no Advanced, swipe broadcasts to the Spark deposit address — same.
  • 3. Mainnet, Transfer to Spending with a small amount → after 3 confirmations the Spending balance shows the amount — mainnet funds.
  • 4. Mainnet, no channels, pay a Lightning invoice from another wallet → paid through Spark, activity shows it — mainnet funds.
  • 5. Mainnet, no channels, receive a Lightning payment → received sheet and activity show it — mainnet funds.
  • 6. Mainnet, receive while the app is closed, then open it → the payment is claimed and shown — mainnet funds.
  • 7. Mainnet, Spending to Savings with only a Spark balance → the balance moves on-chain — mainnet funds.
  • 8. Mainnet, restore the wallet on another device → the Spark balance comes back — mainnet funds.
  • 9. Mainnet, user with an existing channel → payments within channel capacity still go over the channel — mainnet channel.
  • 10. Dev or mainnet, Spark with a balance and a deposit in progress → Lightning Connections shows Spark first with its balance and the deposit's confirmations; its detail shows provider, trust note, deposits and Transfer to Savings — Spark state is not in the journey environment.
  • 11. Dev, fund Spark from the regtest faucet to the address on the Spark screen → after 1 confirmation Spending shows the amount — faucet is outside the journey environment.
  • 12. Dev, two devices with Spark balances, pay one's Spending invoice from the other → paid as a Spark transfer, both show the activity — two devices.
  • 14. Mainnet, Spark send of a Lightning invoice → after Spark's next sync the activity shows the fee Spark charged, not 0 — needs mainnet routing.
  • 15. Mainnet, Transfer to Spending, then Transfer to Savings → both show as transfers in Activity, and the Spark screen lists the withdrawal with its fee and an empty bar — needs mainnet.
  • 16. Mainnet, Spark ready, no channels → Funding (Spending card) shows Transfer from Savings and Use Other Wallet above Manual Setup; Transfer from Savings opens the Spark amount screen; Savings → Transfer to Spending opens the same flow — mainnet.
  • 17. Mainnet, Transfer to Spending of a small amount → the deposit screen shows the deposit, then either an early-claim choice with both fees, an automatic early claim, or the standard claim with its fee; on a choice, Use now → the screen says Spark is adding it, and the Spending balance shows it before 3 confirmations — mainnet funds.
  • 18. Mainnet, same as 17 but tap Wait → the deposit is claimed after 3 confirmations at the standard fee — mainnet funds.
  • 19. Build without a Breez API key (Spark off) → Funding and the transfer buttons behave as on master: Manual Setup only and the Transfer Unavailable sheet — any build.
  • 13. Dev, wallet with Spark connected → Backup settings lists Spark exit data as synced; restore the same seed on a fresh install → the log shows Imported Spark exit data before Spark is used, and Spark's balance and deposits match — needs two installs.

Automated Checks

  • added SparkClaimOfferTests.swift — a quote maps to the standard claim, an automatic early claim within the cap, or a choice above the cap or with automatic claiming off, and each claim outcome maps to claimed, waiting, repriced or declined
  • added ChannelFreeRailTests.swift — rail events before the node callback are delivered, Paykit proofs and private Paykit sets read Spark payments, QuickPay reconciles them, and a Spark send honours the routing fee limit
  • added SparkLightningSendTests.swift — a Lightning invoice with no channels opens the payment when Spark can pay, is rejected without Spark, and a Spark send returns before completion
  • added SparkTransferActivityTests.swift — Spark deposits and withdrawals are marked as transfers, failed ones are not, and withdrawals are listed with the fee Spark kept
  • added SparkExitBackupTests.swift — SPARK_EXIT uploads the exported state under its own key, a restored state is staged until Spark connects, and one from another network is skipped

Channel-only audit

Every place that assumed channels, checked for a Spark wallet with no channels and compared with Android:

  • Fixed:
    • AppViewModel scan check: rejected every Lightning invoice without channels before considering Spark; now pays through Spark when its balance covers the amount, and the toast counts Spark's balance.
    • SendSheet insufficient toasts: count Spark's balance.
    • SendSheet channel wait: no longer waits for a reconnecting channel when Spark can pay the amount.
    • SparkManager send: returns as soon as the payment starts, so its completion event reaches the send screen and Paykit settlement; it showed "Payment Pending" before. Same fix on Android.
    • LightningService.emitChannelFreeRailEvent: Spark events that arrive before the node's event callback is set are kept and delivered once it is; they were dropped.
    • PrivatePaykitService+Invoices settled and attempted payment sets: include Spark payments, so a private invoice Spark received isn't reused and a contact invoice Spark paid isn't paid again.
    • PaykitLightningPaymentProofLookup: settles a Paykit proof from Spark's record when its completion event was missed, also before the node lists its payments.
    • QuickPayPaymentCoordinator reconcile: includes Spark payments.
    • SparkManager activity: recorded through the same path as LDK payments, so a Paykit contact and seen state survive Spark syncs.
    • TransferViewModel swap to Savings: also withdraws Spark's balance, which the confirm screen already counted.
    • PaykitAllowanceManager.lightningReady: Spark ready counts as ready.
    • LightningService.send on Spark: enforces the caller's routing fee limit (Paykit auto-pay's 1%) against Spark's fee estimate.
    • LnurlPayAmount: caps and shows the larger rail balance, not the sum of both.
    • AppStatusHelper.channelsStatus: a ready Spark wallet shows the Lightning connection as ready.
    • LNURL withdraw "no capacity", Receive amount liquidity and CJIT, Lightning Connections receiving capacity and counter: fixed earlier in this PR.
  • Channel-only by design:
    • Channel list and detail, close channel, Blocktank orders, node info, LNURL channel, manual channel funding and the multi-channel Savings path: they manage channels.
    • GiftLoading: gift claims open a Blocktank channel, which Blocktank no longer sells.
    • The notification extension: it wakes the LDK node only; Spark receives while closed are claimed on the next open (no push).
    • nodeLifecycleState gates on send and receive: the node runs beside Spark, as on Android.
    • WalletViewModel balance derivation while the node isn't up: keeps the last balances, which include Spark.
  • Already Spark-aware: maxSendLightningSats, receive invoice creation and tabs, Paykit Lightning endpoint publishing, the Spending card transfer button, the LNURL withdraw invoice.
  • Not covered: a regtest Spark-to-Spark transfer (preferSpark) has no Lightning details, so it maps to no event; mainnet sends are Lightning payments.
  • Android has the same gaps in the private Paykit payment sets, the proof lookup, the Spark activity contact, the swap to Savings, the channel wait and App Status; its flows don't hit them in the cases run on device.

Evidence

  • Rebased on master at 92a03765: the mainnet Release build for device, SwiftFormat and the unit suite pass (run). The rebuilt flow and early claims (16 to 19) are not yet driven. Results below ran on the earlier flow before the rebuild; their revisions are kept as run.

Debug simulator build of 4b58c22 and f79c9f5 (before the rebase onto 55b8a47), iOS simulator, Spark's regtest:

  • 1: new wallet without channels; the log shows Connected Spark wallet on 'regtest'. Receive shows Auto and Spending with a Lightning QR whose invoice names an explicit payee and a route hint to 0202f87a…bb76, which an LDK node without channels does not add.

  • The rebased head aed1f9f builds for the simulator (arm64).

  • 10 on 34dfdef (now bb09eeb): Lightning Connections listed Spark first with its balance and the pending deposit with live confirmations; the detail showed provider, trust note, pending and claimed deposits with the claim fee, and Transfer To Savings.

  • 10 and 2 on 5c3b6f7 (now cbc59e9): the Spark row and detail drew a full purple bar with no receiving side, the header read Receiving capacity No limit, and a 20,000 sat Spark transfer confirm showed network fee 458, Claim fee 99, To spending 19,901 and Total 20,458, with no background toggle, Learn More or Advanced.

Gaps

  • 16 to 19: not run yet; they need a mainnet build on a phone.
  • Early claims: the provider decides per deposit whether to offer one, so 17 may show only the standard claim; that is the flow working, not a failure.
  • Exit data backup, the channel-free Lightning send and the audit fixes on a9aa36fd: the unit suite passes except SendConfirmationLifecycleTests.testCustomFeeWalletSwitchSurvivesFeeScreenNavigation, which fails the same way on the base branch at 77b01a4a. Not yet driven on a device.
  • Pending at broadcast on 8f6de109: built for the simulator only, not driven; the twin Android change was driven on an emulator.
  • 2 to 9: not run on iOS; 3 to 9 need mainnet and a Breez API key.
  • 11 and 12: not run; the faucet needs a person to request funds. The regtest deposit address row and Spark transfers for invoices are built but not driven on iOS.
  • A payment received while the app is in the background is recorded as activity, but the received sheet does not show.

Models used

  • Planning/scoping: claude-opus-5-5 (reasoning: low)
  • Implementation: claude-opus-5-5 (reasoning: low)
  • Review: Not performed

@ovitrif ovitrif added this to the 3.1.0 milestone Oct 26, 2026
@ovitrif ovitrif self-assigned this Oct 26, 2026
@ovitrif
ovitrif force-pushed the feat/breez-spark-lightning branch from aed1f9f to 82d6014 Compare October 26, 2026 14:04
@ovitrif
ovitrif force-pushed the feat/breez-spark-lightning branch 2 times, most recently from bb09eeb to bf0e9cd Compare October 26, 2026 17:18
@ovitrif
ovitrif force-pushed the fix/blocktank-sunset-sheet branch from 9d5e276 to 1883357 Compare October 26, 2026 17:25
@ovitrif
ovitrif force-pushed the feat/breez-spark-lightning branch 3 times, most recently from 856799e to 7897f16 Compare October 26, 2026 22:47
@ovitrif ovitrif changed the title feat: keep lightning through breez sdk on spark feat: add spark via breez sdk Oct 26, 2026
@ovitrif
ovitrif force-pushed the feat/breez-spark-lightning branch from 4534525 to a9aa36f Compare October 27, 2026 02:18
@ovitrif ovitrif mentioned this pull request Oct 27, 2026
5 of 7 tasks
@ovitrif

ovitrif commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator Author

QA:
Tested on an iPhone, mainnet, by @ovitrif, 26–27 Oct; amounts are sats. Balances, names, addresses and txids are masked.

🟢 Pay a Lightning invoice from iOS
The iPhone paid a plain Lightning invoice from the Pixel through Spark with no channel, and the Pixel received it at once. Ran on a9aa36f.

🟢 Restore Spark exit data
Exit data backs up as its own category, and after a wipe the iPhone imported 16 leaves of Spark exit data before using Spark; its balance and claimed deposit came back. Ran on a9aa36f.

🟢 Move Spending to Savings
Transfer to Savings withdrew the Spark balance for a 1,470 sat fee and 4,917 sats arrived in Savings; it was listed as a plain received payment, fixed in 93aec43 to show as a transfer. Ran on a9aa36f.

🟢 Claim a deposit
Spark claimed the 7,500 sat deposit after 3 confirmations, keeping 198 sats, and Spending showed 7,302. Ran on an earlier head of this PR, before the 27 Oct rebase.
🟢 Transfer to Spending
Transfer to Spending sent 9,632 sats to Spark and Spending showed it as an incoming transfer. The confirm screen estimated a 99 sat claim fee where claims so far took 198 to 297; 7388559 now shows the most Spark may keep. Ran on f25edfe, a build of #1145 on an earlier head of this PR.

🔴 Pay a Paykit request over Spark
The iPhone paid the Pixel's 204 sat Paykit request over Spark and it arrived at once, but the iPhone stayed on Payment Pending: the payment settled inside the send call, before the send screen started watching for it. Fixed in 735e972 and synonymdev/bitkit-android@024b6bb85, not rerun on a device yet. Ran on 56d7adf, a build of #1145 on 9ddd96b. An earlier attempt kept loading for minutes while Paykit's shared state stayed locked; since a5d94ed the sheet stops at once and says the contact's payment details aren't ready, and the lock itself is a Paykit issue reported separately.

@ovitrif
ovitrif force-pushed the fix/blocktank-sunset-sheet branch from 6104b95 to 23b8b66 Compare October 27, 2026 17:39
@ovitrif ovitrif removed this from the 3.1.0 milestone Oct 28, 2026
@ovitrif

ovitrif commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Removed from the 3.1.0 milestone: this draft is the deliverable of a finished Spark experiment and does not ship in 3.1.0.

@ovitrif
ovitrif changed the base branch from fix/blocktank-sunset-sheet to master October 28, 2026 13:25
@ovitrif

ovitrif commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Retargeted this draft to master before merging its base, #1127, so deleting that branch would not close it.

@ovitrif
ovitrif force-pushed the feat/breez-spark-lightning branch from 735e972 to a77cb76 Compare October 28, 2026 14:42
@ovitrif

ovitrif commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Rebuilt this branch on master after the Blocktank sunset (#1127). Master removed the old Transfer to Spending flow, so Spark now has its own amount, confirm and deposit screens, reached from Funding and the transfer buttons while Spark is ready. The deposit screen offers Breez's early claim at the fee the provider quotes for that deposit.

The history was rewritten into new commits, so the shas under Evidence predate the rebuild. This PR stays a draft.

@ovitrif
ovitrif force-pushed the feat/breez-spark-lightning branch from a77cb76 to c72164c Compare October 29, 2026 11:05
@ovitrif
ovitrif force-pushed the feat/breez-spark-lightning branch from 3808d9d to 92a0376 Compare October 29, 2026 12:03
@ovitrif

ovitrif commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator Author

Cancelled the unit-tests run on 782d2ff (run): that head was replaced by 92a0376, which folds a SwiftFormat fix into the same change, and a new run is going on it (run).

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.

1 participant