@glyphteck/veyl 0.51.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -6499,10 +6499,10 @@ var init_origins = __esm(() => {
6499
6499
  origins = Object.freeze({
6500
6500
  root: `https://${domains.root}`,
6501
6501
  rootDev: `https://${domains.rootDev}`,
6502
- rootDevWeb: `https://${domains.rootDev}:3001`,
6503
6502
  veyl: `https://${domains.veyl}`,
6504
6503
  veylDev: `https://${domains.veylDev}`,
6505
- veylDevWeb: `https://${domains.veylDev}:3000`
6504
+ veylDevWeb: `https://${domains.veylDev}:3000`,
6505
+ veylDevFeatureWeb: `https://${domains.veylDev}:3001`
6506
6506
  });
6507
6507
  appDomains = Object.freeze([
6508
6508
  domains.veyl
@@ -7469,6 +7469,85 @@ var init_settingscloud = __esm(() => {
7469
7469
  "use client";
7470
7470
  });
7471
7471
 
7472
+ // ../../core/utils/number.js
7473
+ function nonNegativeNumber(value, fallback) {
7474
+ const next = Number(value);
7475
+ return Number.isFinite(next) && next >= 0 ? next : fallback;
7476
+ }
7477
+ function positiveNumber(value, fallback) {
7478
+ const next = Number(value);
7479
+ return Number.isFinite(next) && next > 0 ? next : fallback;
7480
+ }
7481
+ function positiveInt(value, fallback) {
7482
+ const next = Math.trunc(Number(value));
7483
+ return Number.isFinite(next) && next > 0 ? next : fallback;
7484
+ }
7485
+ function nonNegativeInt(value, fallback) {
7486
+ const next = Math.trunc(Number(value));
7487
+ return Number.isFinite(next) && next >= 0 ? next : fallback;
7488
+ }
7489
+
7490
+ // ../../core/utils/async.js
7491
+ function sleep(ms) {
7492
+ return new Promise((resolve) => setTimeout(resolve, nonNegativeNumber(ms, 0)));
7493
+ }
7494
+ function createOwnedWaits() {
7495
+ const waits = new Set;
7496
+ let closed = false;
7497
+ const wait = (schedule, cancel) => new Promise((resolve) => {
7498
+ if (closed) {
7499
+ resolve();
7500
+ return;
7501
+ }
7502
+ const pending = { cancel, id: null, resolve };
7503
+ pending.id = schedule(() => {
7504
+ waits.delete(pending);
7505
+ resolve();
7506
+ });
7507
+ waits.add(pending);
7508
+ });
7509
+ return {
7510
+ delay(ms) {
7511
+ return wait((done) => globalThis.setTimeout(done, nonNegativeNumber(ms, 0)), (id) => globalThis.clearTimeout(id));
7512
+ },
7513
+ idle({ timeout = 0, delay = 0 } = {}) {
7514
+ const requestIdle = globalThis.requestIdleCallback?.bind(globalThis);
7515
+ const cancelIdle = globalThis.cancelIdleCallback?.bind(globalThis);
7516
+ if (typeof requestIdle === "function" && typeof cancelIdle === "function") {
7517
+ return wait((done) => requestIdle(done, { timeout: nonNegativeNumber(timeout, 0) }), cancelIdle);
7518
+ }
7519
+ return wait((done) => globalThis.setTimeout(done, nonNegativeNumber(delay, 0)), (id) => globalThis.clearTimeout(id));
7520
+ },
7521
+ close() {
7522
+ if (closed)
7523
+ return;
7524
+ closed = true;
7525
+ for (const pending of waits) {
7526
+ pending.cancel(pending.id);
7527
+ pending.resolve();
7528
+ }
7529
+ waits.clear();
7530
+ }
7531
+ };
7532
+ }
7533
+ async function yieldToUi() {
7534
+ if (typeof requestAnimationFrame === "function") {
7535
+ await new Promise((resolve) => requestAnimationFrame(resolve));
7536
+ }
7537
+ await sleep(0);
7538
+ }
7539
+ function waitForIdle({ timeout = 0, delay = 0 } = {}) {
7540
+ return new Promise((resolve) => {
7541
+ const idle = globalThis.requestIdleCallback?.bind(globalThis);
7542
+ if (typeof idle === "function") {
7543
+ idle(() => resolve(), { timeout: nonNegativeNumber(timeout, 0) });
7544
+ return;
7545
+ }
7546
+ globalThis.setTimeout(resolve, nonNegativeNumber(delay, 0));
7547
+ });
7548
+ }
7549
+ var init_async = () => {};
7550
+
7472
7551
  // ../../core/crypto/sign.js
7473
7552
  function orderKeys(a, b) {
7474
7553
  if (!a || !b) {
@@ -8529,6 +8608,8 @@ async function openVaultAccountSession(vault, password, options = {}) {
8529
8608
  mark(diag, "vault.unlock.decrypt.done", { elapsedMs: Date.now() - decryptStartedAt, source });
8530
8609
  onStage?.("seed-decrypted");
8531
8610
  notifySeedDecrypted(onSeedDecrypted, diag, source);
8611
+ await yieldToUi();
8612
+ requireCurrent(isCurrent);
8532
8613
  onStage?.("deriving");
8533
8614
  const deriveStartedAt = Date.now();
8534
8615
  const registry = await openSecretRegistry(masterSeed, registryEnvelope);
@@ -8674,6 +8755,7 @@ var init_session = __esm(() => {
8674
8755
  init_password();
8675
8756
  init_settings();
8676
8757
  init_settingscloud();
8758
+ init_async();
8677
8759
  init_vault();
8678
8760
  });
8679
8761
 
@@ -8821,10 +8903,7 @@ var init_display = __esm(() => {
8821
8903
 
8822
8904
  // ../../core/profile.js
8823
8905
  function readBotMarker(profile) {
8824
- const bot = profile?.bot;
8825
- if (!bot)
8826
- return null;
8827
- return typeof bot === "string" ? bot : BOT_PROFILE_MARKER;
8906
+ return profile?.bot === BOT_PROFILE_MARKER ? BOT_PROFILE_MARKER : null;
8828
8907
  }
8829
8908
  function hasPeerKeys(profile) {
8830
8909
  return !!(profile?.walletPK || profile?.chatPK);
@@ -8866,7 +8945,7 @@ function formatUserDisplay(user, showAtSymbol = false) {
8866
8945
  }
8867
8946
  return "unknown user";
8868
8947
  }
8869
- var BOT_PROFILE_MARKER = "bot";
8948
+ var BOT_PROFILE_MARKER = "glyphteck";
8870
8949
  var init_profile = __esm(() => {
8871
8950
  init_avatar();
8872
8951
  init_display();
@@ -9921,24 +10000,6 @@ var init_filepayload = __esm(() => {
9921
10000
  SHARED_MEDIA_FILE_PATTERN = new RegExp(`^${SHARED_MEDIA_ROOT}/(${SHARED_MEDIA_ID_PATTERN})$`);
9922
10001
  });
9923
10002
 
9924
- // ../../core/utils/number.js
9925
- function nonNegativeNumber(value, fallback) {
9926
- const next = Number(value);
9927
- return Number.isFinite(next) && next >= 0 ? next : fallback;
9928
- }
9929
- function positiveNumber(value, fallback) {
9930
- const next = Number(value);
9931
- return Number.isFinite(next) && next > 0 ? next : fallback;
9932
- }
9933
- function positiveInt(value, fallback) {
9934
- const next = Math.trunc(Number(value));
9935
- return Number.isFinite(next) && next > 0 ? next : fallback;
9936
- }
9937
- function nonNegativeInt(value, fallback) {
9938
- const next = Math.trunc(Number(value));
9939
- return Number.isFinite(next) && next >= 0 ? next : fallback;
9940
- }
9941
-
9942
10003
  // ../../core/chat/messages/files.js
9943
10004
  function hasLocalFileRef(msg) {
9944
10005
  if (!hasText(msg?.p) || !hasText(msg?.k)) {
@@ -13525,8 +13586,8 @@ function isPendingTransfer(tx) {
13525
13586
  function isWalletTransfer(tx) {
13526
13587
  return hasTransferType(tx, WALLET_TRANSFER_TYPES, WALLET_TRANSFER_TYPE_CODES);
13527
13588
  }
13528
- function isWithdrawalTransfer(tx) {
13529
- return hasTransferType(tx, WITHDRAWAL_TRANSFER_TYPES, WITHDRAWAL_TRANSFER_TYPE_CODES);
13589
+ function isBitcoinPaymentTransfer(tx) {
13590
+ return hasTransferType(tx, BITCOIN_PAYMENT_TRANSFER_TYPES, BITCOIN_PAYMENT_TRANSFER_TYPE_CODES);
13530
13591
  }
13531
13592
  function isFundingTransfer(tx) {
13532
13593
  if (hasTransferType(tx, BITCOIN_DEPOSIT_TYPES, BITCOIN_DEPOSIT_TYPE_CODES)) {
@@ -13542,7 +13603,7 @@ function isVisibleTransferStatus(tx) {
13542
13603
  return !status || !HIDDEN_TRANSFER_STATUSES.has(status);
13543
13604
  }
13544
13605
  function isVisibleTransfer(tx) {
13545
- return isVisibleTransferStatus(tx) && (isWalletTransfer(tx) || isFundingTransfer(tx) || isWithdrawalTransfer(tx));
13606
+ return isVisibleTransferStatus(tx) && (isWalletTransfer(tx) || isFundingTransfer(tx) || isBitcoinPaymentTransfer(tx));
13546
13607
  }
13547
13608
  function isClaimablePendingTransfer(tx, types2 = null) {
13548
13609
  if (Array.isArray(types2) && types2.length && !types2.includes(tx?.type)) {
@@ -13553,7 +13614,7 @@ function isClaimablePendingTransfer(tx, types2 = null) {
13553
13614
  function transferBelongsToWallet(tx, walletPK) {
13554
13615
  return !!walletPK && (sameText(tx?.senderIdentityPublicKey, walletPK) || sameText(tx?.receiverIdentityPublicKey, walletPK));
13555
13616
  }
13556
- var TRANSFER_STATUS_COMPLETED = "TRANSFER_STATUS_COMPLETED", TRANSFER_TYPE_BITCOIN_DEPOSIT = "BITCOIN_DEPOSIT", TRANSFER_TYPE_COOPERATIVE_EXIT = "COOPERATIVE_EXIT", TRANSFER_TYPE_TRANSFER = "TRANSFER", TRANSFER_TYPE_UTXO_SWAP = "UTXO_SWAP", CLAIMABLE_TRANSFER_STATUS_CODES, CLAIMABLE_TRANSFER_STATUSES, TRANSFER_TYPE_COOPERATIVE_EXIT_CODE = 1, TRANSFER_TYPE_TRANSFER_CODE = 2, TRANSFER_TYPE_UTXO_SWAP_CODE = 3, FINAL_TRANSFER_STATUS_CODES, FINAL_TRANSFER_STATUSES, HIDDEN_TRANSFER_STATUS_CODES, HIDDEN_TRANSFER_STATUSES, LIGHTNING_RECEIVE_DONE_STATUSES, WALLET_TRANSFER_TYPE_CODES, WALLET_TRANSFER_TYPES, WITHDRAWAL_TRANSFER_TYPE_CODES, WITHDRAWAL_TRANSFER_TYPES, BITCOIN_DEPOSIT_TYPE_CODES, BITCOIN_DEPOSIT_TYPES, FUNDING_TRANSFER_TYPE_CODES, FUNDING_TRANSFER_TYPES;
13617
+ var TRANSFER_STATUS_COMPLETED = "TRANSFER_STATUS_COMPLETED", TRANSFER_TYPE_BITCOIN_DEPOSIT = "BITCOIN_DEPOSIT", TRANSFER_TYPE_COOPERATIVE_EXIT = "COOPERATIVE_EXIT", TRANSFER_TYPE_TRANSFER = "TRANSFER", TRANSFER_TYPE_UTXO_SWAP = "UTXO_SWAP", CLAIMABLE_TRANSFER_STATUS_CODES, CLAIMABLE_TRANSFER_STATUSES, TRANSFER_TYPE_COOPERATIVE_EXIT_CODE = 1, TRANSFER_TYPE_TRANSFER_CODE = 2, TRANSFER_TYPE_UTXO_SWAP_CODE = 3, FINAL_TRANSFER_STATUS_CODES, FINAL_TRANSFER_STATUSES, HIDDEN_TRANSFER_STATUS_CODES, HIDDEN_TRANSFER_STATUSES, LIGHTNING_RECEIVE_DONE_STATUSES, WALLET_TRANSFER_TYPE_CODES, WALLET_TRANSFER_TYPES, BITCOIN_PAYMENT_TRANSFER_TYPE_CODES, BITCOIN_PAYMENT_TRANSFER_TYPES, BITCOIN_DEPOSIT_TYPE_CODES, BITCOIN_DEPOSIT_TYPES, FUNDING_TRANSFER_TYPE_CODES, FUNDING_TRANSFER_TYPES;
13557
13618
  var init_tx = __esm(() => {
13558
13619
  init_time();
13559
13620
  CLAIMABLE_TRANSFER_STATUS_CODES = new Set([2, 3, 4, 9, 10]);
@@ -13571,8 +13632,8 @@ var init_tx = __esm(() => {
13571
13632
  LIGHTNING_RECEIVE_DONE_STATUSES = new Set(["transfer_completed", "lightning_payment_received", "payment_preimage_recovered", "completed"]);
13572
13633
  WALLET_TRANSFER_TYPE_CODES = new Set([TRANSFER_TYPE_TRANSFER_CODE]);
13573
13634
  WALLET_TRANSFER_TYPES = new Set([TRANSFER_TYPE_TRANSFER]);
13574
- WITHDRAWAL_TRANSFER_TYPE_CODES = new Set([TRANSFER_TYPE_COOPERATIVE_EXIT_CODE]);
13575
- WITHDRAWAL_TRANSFER_TYPES = new Set([TRANSFER_TYPE_COOPERATIVE_EXIT]);
13635
+ BITCOIN_PAYMENT_TRANSFER_TYPE_CODES = new Set([TRANSFER_TYPE_COOPERATIVE_EXIT_CODE]);
13636
+ BITCOIN_PAYMENT_TRANSFER_TYPES = new Set([TRANSFER_TYPE_COOPERATIVE_EXIT]);
13576
13637
  BITCOIN_DEPOSIT_TYPE_CODES = new Set;
13577
13638
  BITCOIN_DEPOSIT_TYPES = new Set([TRANSFER_TYPE_BITCOIN_DEPOSIT]);
13578
13639
  FUNDING_TRANSFER_TYPE_CODES = new Set([TRANSFER_TYPE_UTXO_SWAP_CODE]);
@@ -17636,67 +17697,6 @@ var init_equal = __esm(() => {
17636
17697
  init_core();
17637
17698
  });
17638
17699
 
17639
- // ../../core/utils/async.js
17640
- function sleep(ms) {
17641
- return new Promise((resolve) => setTimeout(resolve, nonNegativeNumber(ms, 0)));
17642
- }
17643
- function createOwnedWaits() {
17644
- const waits = new Set;
17645
- let closed = false;
17646
- const wait = (schedule, cancel) => new Promise((resolve) => {
17647
- if (closed) {
17648
- resolve();
17649
- return;
17650
- }
17651
- const pending = { cancel, id: null, resolve };
17652
- pending.id = schedule(() => {
17653
- waits.delete(pending);
17654
- resolve();
17655
- });
17656
- waits.add(pending);
17657
- });
17658
- return {
17659
- delay(ms) {
17660
- return wait((done) => globalThis.setTimeout(done, nonNegativeNumber(ms, 0)), (id) => globalThis.clearTimeout(id));
17661
- },
17662
- idle({ timeout = 0, delay = 0 } = {}) {
17663
- const requestIdle = globalThis.requestIdleCallback?.bind(globalThis);
17664
- const cancelIdle = globalThis.cancelIdleCallback?.bind(globalThis);
17665
- if (typeof requestIdle === "function" && typeof cancelIdle === "function") {
17666
- return wait((done) => requestIdle(done, { timeout: nonNegativeNumber(timeout, 0) }), cancelIdle);
17667
- }
17668
- return wait((done) => globalThis.setTimeout(done, nonNegativeNumber(delay, 0)), (id) => globalThis.clearTimeout(id));
17669
- },
17670
- close() {
17671
- if (closed)
17672
- return;
17673
- closed = true;
17674
- for (const pending of waits) {
17675
- pending.cancel(pending.id);
17676
- pending.resolve();
17677
- }
17678
- waits.clear();
17679
- }
17680
- };
17681
- }
17682
- async function yieldToUi() {
17683
- if (typeof requestAnimationFrame === "function") {
17684
- await new Promise((resolve) => requestAnimationFrame(resolve));
17685
- }
17686
- await sleep(0);
17687
- }
17688
- function waitForIdle({ timeout = 0, delay = 0 } = {}) {
17689
- return new Promise((resolve) => {
17690
- const idle = globalThis.requestIdleCallback?.bind(globalThis);
17691
- if (typeof idle === "function") {
17692
- idle(() => resolve(), { timeout: nonNegativeNumber(timeout, 0) });
17693
- return;
17694
- }
17695
- globalThis.setTimeout(resolve, nonNegativeNumber(delay, 0));
17696
- });
17697
- }
17698
- var init_async = () => {};
17699
-
17700
17700
  // ../../core/chat/messages/payloadlog.js
17701
17701
  function messagePayloadKind(message) {
17702
17702
  if (!message || typeof message !== "object") {
@@ -23020,12 +23020,12 @@ function getCurrencyAmountSats(amount) {
23020
23020
  }
23021
23021
  return value;
23022
23022
  }
23023
- function getWithdrawalFeeBreakdown(feeQuote, exitSpeed = DEFAULT_EXIT_SPEED) {
23023
+ function getBitcoinPaymentFeeBreakdown(feeQuote, exitSpeed = DEFAULT_EXIT_SPEED) {
23024
23024
  if (!feeQuote) {
23025
23025
  return null;
23026
23026
  }
23027
23027
  const speed = getExitSpeed(exitSpeed);
23028
- const fields = WITHDRAWAL_FEE_FIELDS[speed];
23028
+ const fields = BITCOIN_PAYMENT_FEE_FIELDS[speed];
23029
23029
  const userFeeSats = getCurrencyAmountSats(feeQuote[fields.user]);
23030
23030
  const l1BroadcastFeeSats = getCurrencyAmountSats(feeQuote[fields.l1]);
23031
23031
  return {
@@ -23037,16 +23037,16 @@ function getWithdrawalFeeBreakdown(feeQuote, exitSpeed = DEFAULT_EXIT_SPEED) {
23037
23037
  expiresAt: feeQuote.expiresAt ?? null
23038
23038
  };
23039
23039
  }
23040
- function getWithdrawalFeeAmountSats(feeQuote, exitSpeed = DEFAULT_EXIT_SPEED) {
23041
- return getWithdrawalFeeBreakdown(feeQuote, exitSpeed)?.feeAmountSats ?? null;
23040
+ function getBitcoinPaymentFeeAmountSats(feeQuote, exitSpeed = DEFAULT_EXIT_SPEED) {
23041
+ return getBitcoinPaymentFeeBreakdown(feeQuote, exitSpeed)?.feeAmountSats ?? null;
23042
23042
  }
23043
- function normalizeWithdrawalFeeQuote(feeQuote) {
23043
+ function normalizeBitcoinPaymentFeeQuote(feeQuote) {
23044
23044
  if (!feeQuote) {
23045
23045
  return null;
23046
23046
  }
23047
23047
  const speeds = {};
23048
23048
  for (const speed of EXIT_SPEEDS) {
23049
- speeds[speed] = getWithdrawalFeeBreakdown(feeQuote, speed);
23049
+ speeds[speed] = getBitcoinPaymentFeeBreakdown(feeQuote, speed);
23050
23050
  }
23051
23051
  return {
23052
23052
  id: feeQuote.id ?? null,
@@ -23156,7 +23156,7 @@ function normalizeLightningPaymentResult(result) {
23156
23156
  raw: result
23157
23157
  };
23158
23158
  }
23159
- var DEFAULT_EXIT_SPEED = "MEDIUM", EXIT_SPEEDS, UNILATERAL_EXIT_PARENT_TX_FALLBACK_VBYTES = 191, UNILATERAL_EXIT_FEE_BUMP_TX_VBYTES = 151, UNILATERAL_EXIT_PACKAGES_PER_LEAF = 2, UNILATERAL_EXIT_PREVIEW_VBYTES, DEFAULT_FEE_RATE_SPEED = "medium", FEE_RATE_FALLBACKS, WITHDRAWAL_FEE_FIELDS;
23159
+ var DEFAULT_EXIT_SPEED = "MEDIUM", EXIT_SPEEDS, UNILATERAL_EXIT_PARENT_TX_FALLBACK_VBYTES = 191, UNILATERAL_EXIT_FEE_BUMP_TX_VBYTES = 151, UNILATERAL_EXIT_PACKAGES_PER_LEAF = 2, UNILATERAL_EXIT_PREVIEW_VBYTES, DEFAULT_FEE_RATE_SPEED = "medium", FEE_RATE_FALLBACKS, BITCOIN_PAYMENT_FEE_FIELDS;
23160
23160
  var init_fees = __esm(() => {
23161
23161
  EXIT_SPEEDS = Object.freeze(["SLOW", "MEDIUM", "FAST"]);
23162
23162
  UNILATERAL_EXIT_PREVIEW_VBYTES = UNILATERAL_EXIT_PACKAGES_PER_LEAF * (UNILATERAL_EXIT_PARENT_TX_FALLBACK_VBYTES + UNILATERAL_EXIT_FEE_BUMP_TX_VBYTES);
@@ -23173,7 +23173,7 @@ var init_fees = __esm(() => {
23173
23173
  noPriority: Object.freeze(["low", "medium", "high"]),
23174
23174
  average: Object.freeze(["medium", "low", "high"])
23175
23175
  });
23176
- WITHDRAWAL_FEE_FIELDS = Object.freeze({
23176
+ BITCOIN_PAYMENT_FEE_FIELDS = Object.freeze({
23177
23177
  FAST: Object.freeze({ user: "userFeeFast", l1: "l1BroadcastFeeFast" }),
23178
23178
  MEDIUM: Object.freeze({ user: "userFeeMedium", l1: "l1BroadcastFeeMedium" }),
23179
23179
  SLOW: Object.freeze({ user: "userFeeSlow", l1: "l1BroadcastFeeSlow" })
@@ -25769,59 +25769,6 @@ async function createLightningInvoice(wallet, { amountSats = 0, memo, expirySeco
25769
25769
  return { success: false, error };
25770
25770
  }
25771
25771
  }
25772
- async function quoteLightningFees(wallet, { invoice, amountSats } = {}) {
25773
- if (!wallet) {
25774
- return { success: false, error: new Error("wallet not ready") };
25775
- }
25776
- const encodedInvoice = cleanText(invoice);
25777
- if (!encodedInvoice) {
25778
- return { success: false, error: new Error("lightning invoice required") };
25779
- }
25780
- try {
25781
- const params = { encodedInvoice };
25782
- if (amountSats != null) {
25783
- params.amountSats = toSafeSats(amountSats);
25784
- }
25785
- const feeAmountSats = await wallet.getLightningSendFeeEstimate(params);
25786
- return {
25787
- success: true,
25788
- feeAmountSats,
25789
- fees: normalizeLightningFeeEstimate(feeAmountSats)
25790
- };
25791
- } catch (error) {
25792
- return { success: false, error };
25793
- }
25794
- }
25795
- async function sendLightningPayment(wallet, { invoice, maxFeeSats, preferSpark = false, amountSatsToSend, idempotencyKey } = {}) {
25796
- if (!wallet) {
25797
- return { success: false, error: new Error("wallet not ready") };
25798
- }
25799
- const encodedInvoice = cleanText(invoice);
25800
- if (!encodedInvoice) {
25801
- return { success: false, error: new Error("lightning invoice required") };
25802
- }
25803
- try {
25804
- const params = {
25805
- invoice: encodedInvoice,
25806
- maxFeeSats: toSafeNonNegativeSats(maxFeeSats, "maxFeeSats"),
25807
- preferSpark: !!preferSpark
25808
- };
25809
- if (amountSatsToSend != null) {
25810
- params.amountSatsToSend = toSafeSats(amountSatsToSend, "amountSatsToSend");
25811
- }
25812
- if (idempotencyKey) {
25813
- params.idempotencyKey = idempotencyKey;
25814
- }
25815
- const payment = await wallet.payLightningInvoice(params);
25816
- return {
25817
- success: true,
25818
- payment,
25819
- result: normalizeLightningPaymentResult(payment)
25820
- };
25821
- } catch (error) {
25822
- return { success: false, error };
25823
- }
25824
- }
25825
25772
  async function getLightningReceiveRequest(wallet, id) {
25826
25773
  if (!wallet) {
25827
25774
  return { success: false, error: new Error("wallet not ready") };
@@ -25865,17 +25812,9 @@ var init_lightningops = __esm(() => {
25865
25812
  });
25866
25813
 
25867
25814
  // ../../core/wallet/lightning.js
25868
- function createLightning({ wallet, updateWalletData }) {
25815
+ function createLightning({ wallet }) {
25869
25816
  return {
25870
25817
  createLightningInvoice: (params) => createLightningInvoice(wallet, params),
25871
- quoteLightningFees: (params) => quoteLightningFees(wallet, params),
25872
- async sendLightningPayment(params) {
25873
- const result = await sendLightningPayment(wallet, params);
25874
- if (result.success) {
25875
- await updateWalletData({ reason: "lightning-send" });
25876
- }
25877
- return result;
25878
- },
25879
25818
  getLightningReceiveRequest: (id) => getLightningReceiveRequest(wallet, id),
25880
25819
  getLightningSendRequest: (id) => getLightningSendRequest(wallet, id)
25881
25820
  };
@@ -26382,61 +26321,6 @@ var init_lifecycle = __esm(() => {
26382
26321
  });
26383
26322
  });
26384
26323
 
26385
- // ../../core/wallet/privacy.js
26386
- function createWalletPrivacy({ wallet, ghostWallet, diag }) {
26387
- let desiredPrivacy = ghostWallet === true;
26388
- let revision = 0;
26389
- let closed = false;
26390
- let privacySync = Promise.resolve();
26391
- const waits = createOwnedWaits();
26392
- const setGhostWallet = (nextGhostWallet) => {
26393
- const nextDesiredPrivacy = nextGhostWallet === true;
26394
- if (revision > 0 && desiredPrivacy === nextDesiredPrivacy) {
26395
- return privacySync;
26396
- }
26397
- desiredPrivacy = nextDesiredPrivacy;
26398
- const requestRevision = ++revision;
26399
- if (!wallet || typeof wallet.setPrivacyEnabled !== "function" || closed) {
26400
- return privacySync;
26401
- }
26402
- privacySync = privacySync.catch(() => {}).then(async () => {
26403
- await waits.delay(PRIVACY_SYNC_DELAY_MS);
26404
- if (closed || requestRevision !== revision) {
26405
- return;
26406
- }
26407
- await waits.idle({ timeout: PRIVACY_SYNC_DELAY_MS, delay: PRIVACY_SYNC_DELAY_MS });
26408
- if (closed || requestRevision !== revision) {
26409
- return;
26410
- }
26411
- const startedAt = Date.now();
26412
- const desired = desiredPrivacy;
26413
- markDiag(diag, "wallet.privacy.start", { ghostWallet: desired });
26414
- await wallet.setPrivacyEnabled(desired);
26415
- markDone(diag, "wallet.privacy", startedAt, { changed: true });
26416
- }).catch((error) => {
26417
- markDiag(diag, "wallet.privacy.error", { code: error?.code || "", message: error?.message || String(error) });
26418
- });
26419
- return privacySync;
26420
- };
26421
- setGhostWallet(ghostWallet);
26422
- return {
26423
- setGhostWallet,
26424
- close() {
26425
- if (closed)
26426
- return;
26427
- closed = true;
26428
- revision += 1;
26429
- waits.close();
26430
- }
26431
- };
26432
- }
26433
- var PRIVACY_SYNC_DELAY_MS;
26434
- var init_privacy = __esm(() => {
26435
- init_config();
26436
- init_async();
26437
- PRIVACY_SYNC_DELAY_MS = WALLET_BOOT_CACHED_REFRESH_DELAY_MS * 2;
26438
- });
26439
-
26440
26324
  // ../../node_modules/.bun/bech32@2.0.0/node_modules/bech32/dist/index.js
26441
26325
  var require_dist = __commonJS((exports) => {
26442
26326
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -26647,7 +26531,43 @@ var init_spark = __esm(() => {
26647
26531
  });
26648
26532
  });
26649
26533
 
26650
- // ../../core/wallet/send.js
26534
+ // ../../core/wallet/payment.js
26535
+ function paymentKind(value) {
26536
+ const kind = cleanText(value).toLowerCase();
26537
+ if (!PAYMENT_KINDS.has(kind)) {
26538
+ throw new Error("unsupported payment kind");
26539
+ }
26540
+ return kind;
26541
+ }
26542
+ function paymentDestination(value) {
26543
+ const destination = cleanText(value);
26544
+ if (!destination) {
26545
+ throw new Error("payment destination required");
26546
+ }
26547
+ return destination;
26548
+ }
26549
+ function optionalPaymentAmount(value) {
26550
+ return value == null ? null : toSafeSats(value);
26551
+ }
26552
+ function normalizeIntent(intent = {}) {
26553
+ const kind = paymentKind(intent.kind);
26554
+ const destination = paymentDestination(intent.destination);
26555
+ const amountSats = optionalPaymentAmount(intent.amountSats);
26556
+ if ((kind === PAYMENT_KIND_BITCOIN || kind === PAYMENT_KIND_SPARK) && amountSats == null) {
26557
+ throw new Error("payment amount required");
26558
+ }
26559
+ return {
26560
+ kind,
26561
+ destination,
26562
+ amountSats,
26563
+ variableAmount: intent.variableAmount === true,
26564
+ preferSpark: intent.preferSpark === true,
26565
+ idempotencyKey: cleanText(intent.idempotencyKey) || null,
26566
+ maxFeeSats: intent.maxFeeSats == null ? null : toSafeNonNegativeSats(intent.maxFeeSats, "maxFeeSats"),
26567
+ exitSpeed: getExitSpeed(intent.exitSpeed),
26568
+ deductFeeFromAmount: intent.deductFeeFromAmount !== false
26569
+ };
26570
+ }
26651
26571
  function firstSparkInvoiceError(result) {
26652
26572
  return result?.invalidInvoices?.[0]?.error || result?.satsTransactionErrors?.[0]?.error || result?.tokenTransactionErrors?.[0]?.error || null;
26653
26573
  }
@@ -26663,139 +26583,360 @@ function publicSparkInvoiceResult(transfer) {
26663
26583
  amountSats: Number.isSafeInteger(transfer?.totalValue) ? transfer.totalValue : null
26664
26584
  };
26665
26585
  }
26666
- function createWalletSend({ wallet, network, updateWalletData, refreshBalance = null, rememberTransfer, refreshPendingTransfers = null, sentTransferRefreshDelayMs = null, beginSdkActivity = null, diag }) {
26667
- const refreshTimers = new Set;
26668
- let closed = false;
26669
- const sendMoneyWithSpark = async (receiverWalletPK, amountSats) => {
26670
- if (!wallet || closed) {
26671
- throw new Error("wallet not ready");
26586
+ function getBitcoinPaymentMinimumReceiveSats(addressInput) {
26587
+ const address = cleanText(addressInput).toLowerCase();
26588
+ if (address.startsWith("1"))
26589
+ return P2PKH_DUST_SATS;
26590
+ if (address.startsWith("3"))
26591
+ return P2SH_DUST_SATS;
26592
+ const p2wpkhLength = address.startsWith("bcrt1q") ? 44 : 42;
26593
+ if ((address.startsWith("bc1q") || address.startsWith("bcrt1q")) && address.length === p2wpkhLength) {
26594
+ return P2WPKH_DUST_SATS;
26595
+ }
26596
+ return SEGWIT_SCRIPT_DUST_SATS;
26597
+ }
26598
+ function getBitcoinPaymentAmounts(payment) {
26599
+ const amountSats = toSafeSats(payment?.amountSats);
26600
+ const feeAmountSats = toSafeNonNegativeSats(payment?.feeAmountSats ?? 0, "feeAmountSats");
26601
+ const deductFeeFromAmount = payment?.deductFeeFromAmount !== false;
26602
+ const receiveAmountSats = deductFeeFromAmount ? Math.max(0, amountSats - feeAmountSats) : amountSats;
26603
+ const sendAmountSats = deductFeeFromAmount ? amountSats : amountSats + feeAmountSats;
26604
+ return {
26605
+ sendAmountSats,
26606
+ receiveAmountSats,
26607
+ feeAmountSats
26608
+ };
26609
+ }
26610
+ function assertBitcoinPaymentReceivesFunds(payment) {
26611
+ const { receiveAmountSats } = getBitcoinPaymentAmounts(payment);
26612
+ const minimumReceiveAmountSats = getBitcoinPaymentMinimumReceiveSats(payment?.destination);
26613
+ if (receiveAmountSats < minimumReceiveAmountSats) {
26614
+ throw new Error(`bitcoin payment would create a dust output below ${minimumReceiveAmountSats} sats`);
26615
+ }
26616
+ }
26617
+ function bitcoinPaymentReview(intent, feeQuote) {
26618
+ const feeQuoteId = feeQuote?.id ?? null;
26619
+ const feeAmountSats = getBitcoinPaymentFeeAmountSats(feeQuote, intent.exitSpeed);
26620
+ if (!feeQuoteId || feeAmountSats == null) {
26621
+ throw new Error("bitcoin payment fee quote unavailable");
26622
+ }
26623
+ const sparkFees = normalizeBitcoinPaymentFeeQuote(feeQuote);
26624
+ const payment = {
26625
+ ...intent,
26626
+ state: PAYMENT_STATE_PREPARED,
26627
+ feeQuote,
26628
+ feeQuoteId,
26629
+ feeAmountSats,
26630
+ fees: { spark: sparkFees },
26631
+ expiresAt: sparkFees?.expiresAt ?? feeQuote.expiresAt ?? null
26632
+ };
26633
+ assertBitcoinPaymentReceivesFunds(payment);
26634
+ return Object.freeze(payment);
26635
+ }
26636
+ function preparedPayment(intent, extra = {}) {
26637
+ return Object.freeze({
26638
+ ...intent,
26639
+ state: PAYMENT_STATE_PREPARED,
26640
+ fees: null,
26641
+ expiresAt: null,
26642
+ ...extra
26643
+ });
26644
+ }
26645
+ async function prepare(wallet, network, paymentInput) {
26646
+ if (!wallet) {
26647
+ throw new Error("wallet not ready");
26648
+ }
26649
+ const intent = normalizeIntent(paymentInput);
26650
+ if (intent.kind === PAYMENT_KIND_BITCOIN) {
26651
+ if (!isAddressOnNetwork(intent.destination, network)) {
26652
+ throw new Error(`refusing to pay - address is not a ${network} address`);
26672
26653
  }
26673
- const startedAt = Date.now();
26674
- markDiag(diag, "wallet.send.start", {});
26675
- const endSdkActivity = typeof beginSdkActivity === "function" ? beginSdkActivity("send") : null;
26676
- try {
26677
- const receiverSparkAddress = walletPKtoSparkAddress(receiverWalletPK, network);
26678
- const tx = await wallet.transfer({
26679
- receiverSparkAddress,
26680
- amountSats: toSafeSats(amountSats)
26681
- });
26682
- endSdkActivity?.();
26683
- markDone(diag, "wallet.send.sdk", startedAt, { hasTransfer: !!tx?.id });
26684
- const rememberStartedAt = Date.now();
26685
- await rememberTransfer?.(tx, { pending: true });
26686
- markDone(diag, "wallet.send.remember", rememberStartedAt, { hasTransfer: !!tx?.id });
26687
- await refreshBalance?.();
26688
- const refreshDelayMs = Number(sentTransferRefreshDelayMs);
26689
- if (!closed && tx?.id && typeof refreshPendingTransfers === "function" && Number.isFinite(refreshDelayMs) && refreshDelayMs >= 0) {
26690
- markDiag(diag, "wallet.send.refresh.schedule", { delayMs: refreshDelayMs });
26691
- const timer = setTimeout(() => {
26692
- refreshTimers.delete(timer);
26693
- if (closed)
26694
- return;
26695
- markDiag(diag, "wallet.send.refresh.start", {});
26696
- refreshPendingTransfers([tx.id]);
26697
- }, refreshDelayMs);
26698
- refreshTimers.add(timer);
26654
+ const feeQuote = await wallet.getWithdrawalFeeQuote({
26655
+ amountSats: intent.amountSats,
26656
+ withdrawalAddress: intent.destination
26657
+ });
26658
+ return bitcoinPaymentReview(intent, feeQuote);
26659
+ }
26660
+ if (intent.kind === PAYMENT_KIND_LIGHTNING) {
26661
+ let maxFeeSats = intent.maxFeeSats;
26662
+ let fees = maxFeeSats == null ? null : normalizeLightningFeeEstimate(maxFeeSats);
26663
+ if (maxFeeSats == null) {
26664
+ const estimateParams = { encodedInvoice: intent.destination };
26665
+ if (intent.variableAmount && intent.amountSats != null) {
26666
+ estimateParams.amountSats = intent.amountSats;
26699
26667
  }
26700
- markDone(diag, "wallet.send", startedAt, { hasTransfer: !!tx?.id });
26701
- return tx?.id;
26702
- } catch (error) {
26703
- endSdkActivity?.();
26704
- markError(diag, "wallet.send", startedAt, error);
26705
- const message = error instanceof Error ? error.message : String(error);
26706
- throw new Error(`failed to send money: ${message}`, { cause: error });
26668
+ maxFeeSats = await wallet.getLightningSendFeeEstimate(estimateParams);
26669
+ fees = normalizeLightningFeeEstimate(maxFeeSats);
26707
26670
  }
26671
+ return preparedPayment(intent, { maxFeeSats, fees });
26672
+ }
26673
+ return preparedPayment(intent);
26674
+ }
26675
+ function normalizePreparedPayment(paymentInput, network) {
26676
+ const intent = normalizeIntent(paymentInput);
26677
+ if (paymentInput?.state !== PAYMENT_STATE_PREPARED) {
26678
+ throw new Error("prepared payment required");
26679
+ }
26680
+ if (intent.kind !== PAYMENT_KIND_BITCOIN) {
26681
+ return preparedPayment(intent, {
26682
+ fees: paymentInput.fees || null,
26683
+ expiresAt: paymentInput.expiresAt ?? null
26684
+ });
26685
+ }
26686
+ if (!isAddressOnNetwork(intent.destination, network)) {
26687
+ throw new Error(`refusing to pay - address is not a ${network} address`);
26688
+ }
26689
+ const feeQuoteId = cleanText(paymentInput.feeQuoteId);
26690
+ if (!feeQuoteId) {
26691
+ throw new Error("bitcoin payment fee quote missing");
26692
+ }
26693
+ const payment = {
26694
+ ...intent,
26695
+ state: PAYMENT_STATE_PREPARED,
26696
+ feeQuote: paymentInput.feeQuote || null,
26697
+ feeQuoteId,
26698
+ feeAmountSats: toSafeNonNegativeSats(paymentInput.feeAmountSats, "feeAmountSats"),
26699
+ fees: paymentInput.fees || null,
26700
+ expiresAt: paymentInput.expiresAt ?? null
26701
+ };
26702
+ assertBitcoinPaymentReceivesFunds(payment);
26703
+ return Object.freeze(payment);
26704
+ }
26705
+ async function sendBitcoin(wallet, walletPK, network, payment, rememberTransfer) {
26706
+ if (!isAddressOnNetwork(payment.destination, network)) {
26707
+ throw new Error(`refusing to pay - address is not a ${network} address`);
26708
+ }
26709
+ if (!payment.feeQuoteId || payment.feeAmountSats == null) {
26710
+ throw new Error("bitcoin payment review missing");
26711
+ }
26712
+ assertBitcoinPaymentReceivesFunds(payment);
26713
+ const tx = await wallet.withdraw({
26714
+ onchainAddress: payment.destination,
26715
+ amountSats: payment.amountSats,
26716
+ exitSpeed: payment.exitSpeed,
26717
+ feeQuoteId: payment.feeQuoteId,
26718
+ feeAmountSats: payment.feeAmountSats,
26719
+ deductFeeFromWithdrawalAmount: payment.deductFeeFromAmount
26720
+ });
26721
+ const transferId = tx?.transfer?.sparkId || tx?.transfer?.id || null;
26722
+ if (transferId) {
26723
+ const createdTime = tx?.createdAt || new Date().toISOString();
26724
+ await rememberTransfer?.({
26725
+ id: transferId,
26726
+ senderIdentityPublicKey: walletPK,
26727
+ receiverIdentityPublicKey: "",
26728
+ status: "TRANSFER_STATUS_SENDER_INITIATED",
26729
+ totalValue: payment.amountSats,
26730
+ createdTime,
26731
+ updatedTime: tx?.updatedAt || createdTime,
26732
+ type: "COOPERATIVE_EXIT",
26733
+ transferDirection: "OUTGOING"
26734
+ }, {
26735
+ pending: true,
26736
+ bitcoinAddress: payment.destination,
26737
+ bitcoinTxid: tx?.coopExitTxid || null
26738
+ });
26739
+ }
26740
+ return {
26741
+ id: transferId || tx?.id || tx?.coopExitTxid || null,
26742
+ result: tx
26708
26743
  };
26709
- const payExternalInvoice = async ({ type, invoice, amountSats, variableAmount = false } = {}) => {
26744
+ }
26745
+ function createPayment({
26746
+ wallet,
26747
+ walletPK,
26748
+ network,
26749
+ updateWalletData,
26750
+ refreshBalance = null,
26751
+ rememberTransfer,
26752
+ refreshPendingTransfers = null,
26753
+ sentTransferRefreshDelayMs = null,
26754
+ beginSdkActivity = null,
26755
+ diag = null
26756
+ }) {
26757
+ const refreshTimers = new Set;
26758
+ let closed = false;
26759
+ const assertReady = () => {
26710
26760
  if (!wallet || closed) {
26711
26761
  throw new Error("wallet not ready");
26712
26762
  }
26713
- const value = cleanText(invoice);
26714
- if (!value) {
26715
- throw new Error("invoice required");
26763
+ };
26764
+ const preparePayment = async (intent) => {
26765
+ assertReady();
26766
+ return prepare(wallet, network, intent);
26767
+ };
26768
+ const scheduleTransferRefresh = (id) => {
26769
+ const refreshDelayMs = Number(sentTransferRefreshDelayMs);
26770
+ if (closed || !id || typeof refreshPendingTransfers !== "function" || !Number.isFinite(refreshDelayMs) || refreshDelayMs < 0) {
26771
+ return;
26716
26772
  }
26773
+ markDiag(diag, "wallet.send.refresh.schedule", { delayMs: refreshDelayMs });
26774
+ const timer = setTimeout(() => {
26775
+ refreshTimers.delete(timer);
26776
+ if (closed)
26777
+ return;
26778
+ markDiag(diag, "wallet.send.refresh.start", {});
26779
+ refreshPendingTransfers([id]);
26780
+ }, refreshDelayMs);
26781
+ refreshTimers.add(timer);
26782
+ };
26783
+ const sendPayment = async (paymentInput) => {
26784
+ assertReady();
26785
+ if (paymentInput?.kind === PAYMENT_KIND_BITCOIN && paymentInput?.state !== PAYMENT_STATE_PREPARED) {
26786
+ throw new Error("bitcoin payment must be reviewed before sending");
26787
+ }
26788
+ const payment = paymentInput?.state === PAYMENT_STATE_PREPARED ? normalizePreparedPayment(paymentInput, network) : await preparePayment(paymentInput);
26717
26789
  const startedAt = Date.now();
26718
- markDiag(diag, "wallet.externalPay.start", { type });
26719
- if (type === "lightning") {
26720
- try {
26721
- const sendAmountSats = variableAmount ? toSafeSats(amountSats, "amountSatsToSend") : null;
26722
- const estimateParams = {
26723
- encodedInvoice: value,
26724
- ...sendAmountSats != null ? { amountSats: sendAmountSats } : {}
26725
- };
26726
- const feeAmountSats = await wallet.getLightningSendFeeEstimate(estimateParams);
26727
- const fees = normalizeLightningFeeEstimate(feeAmountSats);
26728
- const payment = await wallet.payLightningInvoice({
26729
- invoice: value,
26730
- maxFeeSats: fees.feeAmountSats,
26731
- preferSpark: true,
26732
- ...sendAmountSats != null ? { amountSatsToSend: sendAmountSats } : {}
26790
+ const diagKind = payment.kind;
26791
+ markDiag(diag, "wallet.payment.start", { kind: diagKind });
26792
+ const endSdkActivity = typeof beginSdkActivity === "function" ? beginSdkActivity("payment") : null;
26793
+ try {
26794
+ let outcome;
26795
+ if (payment.kind === PAYMENT_KIND_SPARK) {
26796
+ if (sameText(payment.destination, walletPK)) {
26797
+ throw new Error("cannot send money to the same wallet");
26798
+ }
26799
+ const tx = await wallet.transfer({
26800
+ receiverSparkAddress: walletPKtoSparkAddress(payment.destination, network),
26801
+ amountSats: payment.amountSats
26802
+ });
26803
+ await rememberTransfer?.(tx, { pending: true });
26804
+ await refreshBalance?.();
26805
+ scheduleTransferRefresh(tx?.id);
26806
+ outcome = { id: tx?.id || null, result: tx };
26807
+ } else if (payment.kind === PAYMENT_KIND_LIGHTNING) {
26808
+ const sent = await wallet.payLightningInvoice({
26809
+ invoice: payment.destination,
26810
+ maxFeeSats: payment.maxFeeSats,
26811
+ preferSpark: payment.preferSpark,
26812
+ ...payment.variableAmount && payment.amountSats != null ? { amountSatsToSend: payment.amountSats } : {},
26813
+ ...payment.idempotencyKey ? { idempotencyKey: payment.idempotencyKey } : {}
26733
26814
  });
26734
- const result = normalizeLightningPaymentResult(payment);
26815
+ const result = normalizeLightningPaymentResult(sent);
26735
26816
  if (result?.kind === "spark" && result?.transfer) {
26736
26817
  await rememberTransfer?.(result.transfer, { pending: true });
26737
26818
  } else {
26738
- await rememberTransfer?.(result?.id || payment?.id);
26819
+ await rememberTransfer?.(result?.id || sent?.id);
26739
26820
  await updateWalletData({ reason: "external-lightning-send" });
26740
26821
  }
26741
- markDone(diag, "wallet.externalPay", startedAt, { type, hasTransfer: !!result?.transfer });
26742
- return {
26743
- id: result?.id || payment?.id || null,
26744
- payment,
26745
- result,
26746
- fees
26747
- };
26748
- } catch (error) {
26749
- markError(diag, "wallet.externalPay", startedAt, error, { type });
26750
- throw error;
26751
- }
26752
- }
26753
- if (type === "spark") {
26754
- try {
26755
- const safeAmountSats = amountSats != null ? toSafeSats(amountSats, "amountSats") : null;
26822
+ outcome = { id: result?.id || sent?.id || null, result, raw: sent };
26823
+ } else if (payment.kind === PAYMENT_KIND_SPARK_INVOICE) {
26756
26824
  const result = await wallet.fulfillSparkInvoice([
26757
26825
  {
26758
- invoice: value,
26759
- ...safeAmountSats != null ? { amount: BigInt(safeAmountSats) } : {}
26826
+ invoice: payment.destination,
26827
+ ...payment.amountSats != null ? { amount: BigInt(payment.amountSats) } : {}
26760
26828
  }
26761
26829
  ]);
26762
26830
  const error = firstSparkInvoiceError(result);
26763
- if (error) {
26831
+ if (error)
26764
26832
  throw error;
26765
- }
26766
26833
  const success = firstSparkInvoiceSuccess(result);
26767
- if (!success) {
26834
+ if (!success)
26768
26835
  throw new Error("failed to pay spark invoice");
26769
- }
26770
26836
  const id = success.id || success.txid || null;
26771
26837
  await rememberTransfer?.(success.id ? success : id, { pending: true });
26772
- markDone(diag, "wallet.externalPay", startedAt, { type, hasTransfer: !!id });
26773
- return {
26774
- id,
26775
- result: publicSparkInvoiceResult(success)
26776
- };
26777
- } catch (error) {
26778
- markError(diag, "wallet.externalPay", startedAt, error, { type });
26779
- throw error;
26838
+ outcome = { id, result: publicSparkInvoiceResult(success), raw: result };
26839
+ } else if (payment.kind === PAYMENT_KIND_BITCOIN) {
26840
+ outcome = await sendBitcoin(wallet, walletPK, network, payment, rememberTransfer);
26841
+ await updateWalletData({ reason: "bitcoin-payment" });
26842
+ } else {
26843
+ throw new Error("unsupported payment kind");
26780
26844
  }
26845
+ endSdkActivity?.();
26846
+ markDone(diag, "wallet.payment", startedAt, { kind: diagKind, hasTransfer: !!outcome?.id });
26847
+ return Object.freeze({
26848
+ kind: payment.kind,
26849
+ destination: payment.destination,
26850
+ amountSats: payment.amountSats,
26851
+ id: outcome?.id || null,
26852
+ fees: payment.fees || null,
26853
+ result: outcome?.result || null,
26854
+ raw: outcome?.raw || null
26855
+ });
26856
+ } catch (error) {
26857
+ endSdkActivity?.();
26858
+ markError(diag, "wallet.payment", startedAt, error, { kind: diagKind });
26859
+ const message = error instanceof Error ? error.message : String(error);
26860
+ throw new Error(`failed to send payment: ${message}`, { cause: error });
26781
26861
  }
26782
- throw new Error("unsupported invoice type");
26783
26862
  };
26784
26863
  return {
26785
- sendMoneyWithSpark,
26786
- payExternalInvoice,
26864
+ preparePayment,
26865
+ sendPayment,
26787
26866
  close() {
26788
26867
  closed = true;
26789
- for (const timer of refreshTimers) {
26868
+ for (const timer of refreshTimers)
26790
26869
  clearTimeout(timer);
26791
- }
26792
26870
  refreshTimers.clear();
26793
26871
  }
26794
26872
  };
26795
26873
  }
26796
- var init_send2 = __esm(() => {
26874
+ var PAYMENT_KIND_BITCOIN = "bitcoin", PAYMENT_KIND_LIGHTNING = "lightning", PAYMENT_KIND_SPARK = "spark", PAYMENT_KIND_SPARK_INVOICE = "spark_invoice", PAYMENT_STATE_PREPARED = "prepared", PAYMENT_KINDS, P2PKH_DUST_SATS = 546, P2SH_DUST_SATS = 540, P2WPKH_DUST_SATS = 294, SEGWIT_SCRIPT_DUST_SATS = 330;
26875
+ var init_payment = __esm(() => {
26876
+ init_network();
26797
26877
  init_fees();
26798
26878
  init_spark();
26879
+ PAYMENT_KINDS = new Set([
26880
+ PAYMENT_KIND_BITCOIN,
26881
+ PAYMENT_KIND_LIGHTNING,
26882
+ PAYMENT_KIND_SPARK,
26883
+ PAYMENT_KIND_SPARK_INVOICE
26884
+ ]);
26885
+ });
26886
+
26887
+ // ../../core/wallet/privacy.js
26888
+ function createWalletPrivacy({ wallet, ghostWallet, diag }) {
26889
+ let desiredPrivacy = ghostWallet === true;
26890
+ let revision = 0;
26891
+ let closed = false;
26892
+ let privacySync = Promise.resolve();
26893
+ const waits = createOwnedWaits();
26894
+ const setGhostWallet = (nextGhostWallet) => {
26895
+ const nextDesiredPrivacy = nextGhostWallet === true;
26896
+ if (revision > 0 && desiredPrivacy === nextDesiredPrivacy) {
26897
+ return privacySync;
26898
+ }
26899
+ desiredPrivacy = nextDesiredPrivacy;
26900
+ const requestRevision = ++revision;
26901
+ if (!wallet || typeof wallet.setPrivacyEnabled !== "function" || closed) {
26902
+ return privacySync;
26903
+ }
26904
+ privacySync = privacySync.catch(() => {}).then(async () => {
26905
+ await waits.delay(PRIVACY_SYNC_DELAY_MS);
26906
+ if (closed || requestRevision !== revision) {
26907
+ return;
26908
+ }
26909
+ await waits.idle({ timeout: PRIVACY_SYNC_DELAY_MS, delay: PRIVACY_SYNC_DELAY_MS });
26910
+ if (closed || requestRevision !== revision) {
26911
+ return;
26912
+ }
26913
+ const startedAt = Date.now();
26914
+ const desired = desiredPrivacy;
26915
+ markDiag(diag, "wallet.privacy.start", { ghostWallet: desired });
26916
+ await wallet.setPrivacyEnabled(desired);
26917
+ markDone(diag, "wallet.privacy", startedAt, { changed: true });
26918
+ }).catch((error) => {
26919
+ markDiag(diag, "wallet.privacy.error", { code: error?.code || "", message: error?.message || String(error) });
26920
+ });
26921
+ return privacySync;
26922
+ };
26923
+ setGhostWallet(ghostWallet);
26924
+ return {
26925
+ setGhostWallet,
26926
+ close() {
26927
+ if (closed)
26928
+ return;
26929
+ closed = true;
26930
+ revision += 1;
26931
+ waits.close();
26932
+ }
26933
+ };
26934
+ }
26935
+ var PRIVACY_SYNC_DELAY_MS;
26936
+ var init_privacy = __esm(() => {
26937
+ init_config();
26938
+ init_async();
26939
+ PRIVACY_SYNC_DELAY_MS = WALLET_BOOT_CACHED_REFRESH_DELAY_MS * 2;
26799
26940
  });
26800
26941
 
26801
26942
  // ../../core/wallet/history.js
@@ -26819,7 +26960,7 @@ function compareRecentTransfer(a, b) {
26819
26960
  return String(b?.id || "").localeCompare(String(a?.id || ""));
26820
26961
  }
26821
26962
  function sameTransfer(left, right) {
26822
- return left?.id === right?.id && left?.status === right?.status && txCreatedMs(left) === txCreatedMs(right) && txUpdatedMs(left) === txUpdatedMs(right) && left?.totalValue === right?.totalValue && left?.type === right?.type && left?.transferDirection === right?.transferDirection && left?.senderIdentityPublicKey === right?.senderIdentityPublicKey && left?.receiverIdentityPublicKey === right?.receiverIdentityPublicKey;
26963
+ return left?.id === right?.id && left?.status === right?.status && txCreatedMs(left) === txCreatedMs(right) && txUpdatedMs(left) === txUpdatedMs(right) && left?.totalValue === right?.totalValue && left?.type === right?.type && left?.transferDirection === right?.transferDirection && left?.senderIdentityPublicKey === right?.senderIdentityPublicKey && left?.receiverIdentityPublicKey === right?.receiverIdentityPublicKey && left?.bitcoinAddress === right?.bitcoinAddress && left?.bitcoinTxid === right?.bitcoinTxid;
26823
26964
  }
26824
26965
  function sameTransfers(a = [], b = []) {
26825
26966
  if (a === b) {
@@ -26861,10 +27002,13 @@ function satValue(value) {
26861
27002
  const amount = Number(value);
26862
27003
  return Number.isFinite(amount) ? amount : 0;
26863
27004
  }
26864
- function compactTransfer(tx, { incoming = false } = {}) {
27005
+ function compactTransfer(tx, { incoming = false, bitcoinAddress = null, bitcoinTxid = null } = {}) {
26865
27006
  if (!tx?.id) {
26866
27007
  return null;
26867
27008
  }
27009
+ const isBitcoinPayment = enumName(tx.type, TRANSFER_TYPE_BY_CODE) === "COOPERATIVE_EXIT";
27010
+ const storedBitcoinAddress = String(bitcoinAddress || tx.bitcoinAddress || "").trim() || null;
27011
+ const storedBitcoinTxid = String(bitcoinTxid || tx.bitcoinTxid || (isBitcoinPayment ? tx.userRequest?.coopExitTxid : "") || "").trim() || null;
26868
27012
  return {
26869
27013
  id: tx.id,
26870
27014
  senderIdentityPublicKey: hexKey(tx.senderIdentityPublicKey),
@@ -26874,11 +27018,13 @@ function compactTransfer(tx, { incoming = false } = {}) {
26874
27018
  createdTime: tx.createdTime,
26875
27019
  updatedTime: tx.updatedTime,
26876
27020
  type: enumName(tx.type, TRANSFER_TYPE_BY_CODE),
26877
- transferDirection: tx.transferDirection || (incoming ? "INCOMING" : undefined)
27021
+ transferDirection: tx.transferDirection || (incoming ? "INCOMING" : undefined),
27022
+ ...isBitcoinPayment && storedBitcoinAddress ? { bitcoinAddress: storedBitcoinAddress } : {},
27023
+ ...isBitcoinPayment && storedBitcoinTxid ? { bitcoinTxid: storedBitcoinTxid } : {}
26878
27024
  };
26879
27025
  }
26880
27026
  function compactRememberedTransfer(tx, options = {}) {
26881
- const compact2 = compactTransfer(tx, { incoming: options?.incoming === true });
27027
+ const compact2 = compactTransfer(tx, options);
26882
27028
  if (!compact2) {
26883
27029
  return null;
26884
27030
  }
@@ -26952,12 +27098,30 @@ function getOldestAnyTransferMs(transfers = []) {
26952
27098
  function shouldReplaceTransfer(current, next) {
26953
27099
  return isPendingTransfer(current) && (!isPendingTransfer(next) || current?.status !== next?.status || txUpdatedMs(next) > txUpdatedMs(current));
26954
27100
  }
27101
+ function mergeTransferDetails(current, next) {
27102
+ if (!current)
27103
+ return next;
27104
+ const base = shouldReplaceTransfer(current, next) ? next : current;
27105
+ const bitcoinAddress = next?.bitcoinAddress || current.bitcoinAddress || null;
27106
+ const bitcoinTxid = next?.bitcoinTxid || current.bitcoinTxid || null;
27107
+ if (base === current && bitcoinAddress === current?.bitcoinAddress && bitcoinTxid === current?.bitcoinTxid) {
27108
+ return current;
27109
+ }
27110
+ if (base === next && bitcoinAddress === next?.bitcoinAddress && bitcoinTxid === next?.bitcoinTxid) {
27111
+ return next;
27112
+ }
27113
+ return {
27114
+ ...base,
27115
+ ...bitcoinAddress ? { bitcoinAddress } : {},
27116
+ ...bitcoinTxid ? { bitcoinTxid } : {}
27117
+ };
27118
+ }
26955
27119
  function indexTransfersById(transfers = []) {
26956
27120
  const byId = new Map;
26957
27121
  for (const tx of Array.isArray(transfers) ? transfers : []) {
26958
27122
  const id = String(tx?.id || "");
26959
27123
  if (id) {
26960
- byId.set(id, tx);
27124
+ byId.set(id, mergeTransferDetails(byId.get(id), tx));
26961
27125
  }
26962
27126
  }
26963
27127
  return byId;
@@ -26969,7 +27133,7 @@ function hasMergeableTransferChanges(transfers = [], transferById = new Map) {
26969
27133
  continue;
26970
27134
  }
26971
27135
  const current = transferById.get(id);
26972
- if (!current || shouldReplaceTransfer(current, tx)) {
27136
+ if (!current || mergeTransferDetails(current, tx) !== current) {
26973
27137
  return true;
26974
27138
  }
26975
27139
  }
@@ -26986,8 +27150,9 @@ function dedupeSortedTransfers(transfers = []) {
26986
27150
  continue;
26987
27151
  }
26988
27152
  const current = byId.get(id);
26989
- if (!current || shouldReplaceTransfer(current, tx)) {
26990
- byId.set(id, tx);
27153
+ const merged = mergeTransferDetails(current, tx);
27154
+ if (!current || merged !== current) {
27155
+ byId.set(id, merged);
26991
27156
  }
26992
27157
  }
26993
27158
  return sortRecentTransfers([...byId.values()]);
@@ -27055,11 +27220,14 @@ function mergeCompactedTransferPage(current = [], pageTransfers = [], position =
27055
27220
  const updatedCurrent = replacements.size ? current.map((tx) => {
27056
27221
  const id = String(tx?.id || "");
27057
27222
  const replacement = id ? replacements.get(id) : null;
27058
- if (!replacement || !shouldReplaceTransfer(tx, replacement)) {
27223
+ if (!replacement) {
27059
27224
  return tx;
27060
27225
  }
27226
+ const merged = mergeTransferDetails(tx, replacement);
27227
+ if (merged === tx)
27228
+ return tx;
27061
27229
  changed = true;
27062
- return replacement;
27230
+ return merged;
27063
27231
  }) : current;
27064
27232
  if (!newItems.length) {
27065
27233
  return changed ? updatedCurrent : current;
@@ -27082,7 +27250,8 @@ function mergeTransferPageForWallet(currentTransfers = [], pageTransfers = [], w
27082
27250
  return mergeCompactedTransferPage(current, page, position);
27083
27251
  }
27084
27252
  function mergeRecentSnapshotForWallet(currentTransfers = [], latestTransfers = [], walletPK) {
27085
- const latest = mergeTransferPageForWallet([], latestTransfers, walletPK, "append");
27253
+ const currentById = new Map(currentTransfers.map((tx) => [String(tx?.id || ""), tx]));
27254
+ const latest = mergeTransferPageForWallet([], latestTransfers, walletPK, "append").map((tx) => mergeTransferDetails(currentById.get(String(tx?.id || "")), tx));
27086
27255
  if (!latest.length) {
27087
27256
  return filterTransfersForWallet(currentTransfers, walletPK);
27088
27257
  }
@@ -27211,7 +27380,7 @@ function pendingReconcileAgeMs(tx, now = Date.now(), firstSeenAt = null) {
27211
27380
  return baseMs ? Math.max(0, now - baseMs) : null;
27212
27381
  }
27213
27382
  function getPendingTransferRetryMs(tx, ageMs, unresolvedCount = 0) {
27214
- if (isWithdrawalTransfer(tx)) {
27383
+ if (isBitcoinPaymentTransfer(tx)) {
27215
27384
  if (!Number.isFinite(ageMs) || ageMs <= PENDING_TRANSFER_WARM_AGE_MS) {
27216
27385
  return PENDING_TRANSFER_WARM_RETRY_MS;
27217
27386
  }
@@ -29244,210 +29413,6 @@ var init_transfers2 = __esm(() => {
29244
29413
  ]);
29245
29414
  });
29246
29415
 
29247
- // ../../core/wallet/withdrawops.js
29248
- function getWithdrawalMinimumReceiveSats(onchainAddress) {
29249
- const address = cleanText(onchainAddress).toLowerCase();
29250
- if (address.startsWith("1"))
29251
- return P2PKH_DUST_SATS;
29252
- if (address.startsWith("3"))
29253
- return P2SH_DUST_SATS;
29254
- const p2wpkhLength = address.startsWith("bcrt1q") ? 44 : 42;
29255
- if ((address.startsWith("bc1q") || address.startsWith("bcrt1q")) && address.length === p2wpkhLength) {
29256
- return P2WPKH_DUST_SATS;
29257
- }
29258
- return SEGWIT_SCRIPT_DUST_SATS;
29259
- }
29260
- function getWithdrawalReviewAmounts(withdrawal) {
29261
- const amountSats = toSafeSats(withdrawal?.amountSats);
29262
- const feeAmountSats = toSafeNonNegativeSats(withdrawal?.feeAmountSats ?? 0, "feeAmountSats");
29263
- const deductFeeFromWithdrawalAmount = withdrawal?.deductFeeFromWithdrawalAmount !== false;
29264
- const receiveAmountSats = deductFeeFromWithdrawalAmount ? Math.max(0, amountSats - feeAmountSats) : amountSats;
29265
- const sendAmountSats = deductFeeFromWithdrawalAmount ? amountSats : amountSats + feeAmountSats;
29266
- return {
29267
- sendAmountSats,
29268
- receiveAmountSats,
29269
- feeAmountSats
29270
- };
29271
- }
29272
- function assertWithdrawalReceivesFunds(withdrawal) {
29273
- const { receiveAmountSats } = getWithdrawalReviewAmounts(withdrawal);
29274
- const minimumReceiveAmountSats = getWithdrawalMinimumReceiveSats(withdrawal?.onchainAddress);
29275
- if (receiveAmountSats < minimumReceiveAmountSats) {
29276
- throw new Error(`withdrawal would create a dust output below ${minimumReceiveAmountSats} sats`);
29277
- }
29278
- }
29279
- function getWithdrawalReview({ feeQuote, exitSpeed, amountSats, onchainAddress, deductFeeFromWithdrawalAmount = true }) {
29280
- const safeExitSpeed = getExitSpeed(exitSpeed);
29281
- const feeQuoteId = feeQuote?.id ?? null;
29282
- const feeAmountSats = getWithdrawalFeeAmountSats(feeQuote, safeExitSpeed);
29283
- if (!feeQuoteId || feeAmountSats == null) {
29284
- throw new Error("withdrawal fee quote unavailable");
29285
- }
29286
- const sparkFees = normalizeWithdrawalFeeQuote(feeQuote);
29287
- const withdrawal = {
29288
- kind: "cooperative_exit",
29289
- onchainAddress,
29290
- amountSats,
29291
- exitSpeed: safeExitSpeed,
29292
- deductFeeFromWithdrawalAmount,
29293
- feeQuote,
29294
- feeQuoteId,
29295
- feeAmountSats,
29296
- fees: {
29297
- spark: sparkFees
29298
- },
29299
- sparkFees,
29300
- expiresAt: sparkFees?.expiresAt ?? feeQuote.expiresAt ?? null
29301
- };
29302
- assertWithdrawalReceivesFunds(withdrawal);
29303
- return withdrawal;
29304
- }
29305
- async function quoteWithdrawalFees(wallet, network, { onchainAddress, amountSats } = {}) {
29306
- if (!wallet) {
29307
- return { success: false, error: new Error("wallet not ready") };
29308
- }
29309
- const address = cleanText(onchainAddress);
29310
- if (!isAddressOnNetwork(address, network)) {
29311
- return { success: false, error: new Error(`refusing to withdraw - address is not a ${network} address`) };
29312
- }
29313
- try {
29314
- const safeAmountSats = toSafeSats(amountSats);
29315
- const feeQuote = await wallet.getWithdrawalFeeQuote({
29316
- amountSats: safeAmountSats,
29317
- withdrawalAddress: address
29318
- });
29319
- if (!feeQuote?.id) {
29320
- throw new Error("withdrawal fee quote unavailable");
29321
- }
29322
- const sparkFees = normalizeWithdrawalFeeQuote(feeQuote);
29323
- return {
29324
- success: true,
29325
- feeQuote,
29326
- fees: {
29327
- spark: sparkFees
29328
- },
29329
- sparkFees,
29330
- amountSats: safeAmountSats,
29331
- onchainAddress: address
29332
- };
29333
- } catch (error) {
29334
- return { success: false, error };
29335
- }
29336
- }
29337
- async function prepareWithdrawal(wallet, network, { onchainAddress, amountSats, exitSpeed = DEFAULT_EXIT_SPEED, deductFeeFromWithdrawalAmount = true } = {}) {
29338
- const quoted = await quoteWithdrawalFees(wallet, network, { onchainAddress, amountSats });
29339
- if (!quoted.success) {
29340
- return quoted;
29341
- }
29342
- try {
29343
- const withdrawal = getWithdrawalReview({
29344
- feeQuote: quoted.feeQuote,
29345
- exitSpeed,
29346
- amountSats: quoted.amountSats,
29347
- onchainAddress: quoted.onchainAddress,
29348
- deductFeeFromWithdrawalAmount
29349
- });
29350
- return {
29351
- success: true,
29352
- withdrawal,
29353
- ...withdrawal
29354
- };
29355
- } catch (error) {
29356
- return { success: false, error };
29357
- }
29358
- }
29359
- async function withdrawFunds(wallet, network, { onchainAddress, amountSats, exitSpeed = DEFAULT_EXIT_SPEED, feeQuote = null, feeQuoteId = null, feeAmountSats = null, deductFeeFromWithdrawalAmount = true } = {}) {
29360
- if (!wallet) {
29361
- return { success: false, error: new Error("wallet not ready") };
29362
- }
29363
- const address = cleanText(onchainAddress);
29364
- if (!isAddressOnNetwork(address, network)) {
29365
- return { success: false, error: new Error(`refusing to withdraw - address is not a ${network} address`) };
29366
- }
29367
- try {
29368
- const safeAmountSats = toSafeSats(amountSats);
29369
- const safeExitSpeed = getExitSpeed(exitSpeed);
29370
- let readyFeeQuote = feeQuote;
29371
- if (!readyFeeQuote && (!feeQuoteId || feeAmountSats == null)) {
29372
- const quoted = await quoteWithdrawalFees(wallet, network, {
29373
- onchainAddress: address,
29374
- amountSats: safeAmountSats
29375
- });
29376
- if (!quoted.success) {
29377
- return quoted;
29378
- }
29379
- readyFeeQuote = quoted.feeQuote;
29380
- }
29381
- const readyFeeQuoteId = feeQuoteId || readyFeeQuote?.id;
29382
- const readyFeeAmountSats = feeAmountSats == null ? getWithdrawalFeeAmountSats(readyFeeQuote, safeExitSpeed) : toSafeNonNegativeSats(feeAmountSats, "feeAmountSats");
29383
- if (!readyFeeQuoteId || readyFeeAmountSats == null) {
29384
- throw new Error("withdrawal fee quote unavailable");
29385
- }
29386
- assertWithdrawalReceivesFunds({
29387
- onchainAddress: address,
29388
- amountSats: safeAmountSats,
29389
- feeAmountSats: readyFeeAmountSats,
29390
- deductFeeFromWithdrawalAmount
29391
- });
29392
- const tx = await wallet.withdraw({
29393
- onchainAddress: address,
29394
- amountSats: safeAmountSats,
29395
- exitSpeed: safeExitSpeed,
29396
- feeQuoteId: readyFeeQuoteId,
29397
- feeAmountSats: readyFeeAmountSats,
29398
- deductFeeFromWithdrawalAmount
29399
- });
29400
- return {
29401
- success: true,
29402
- tx,
29403
- feeQuote: readyFeeQuote,
29404
- fees: readyFeeQuote ? {
29405
- spark: normalizeWithdrawalFeeQuote(readyFeeQuote)
29406
- } : null,
29407
- feeAmountSats: readyFeeAmountSats
29408
- };
29409
- } catch (error) {
29410
- return { success: false, error };
29411
- }
29412
- }
29413
- async function confirmWithdrawal(wallet, network, withdrawal) {
29414
- if (!withdrawal) {
29415
- return { success: false, error: new Error("withdrawal review missing") };
29416
- }
29417
- return withdrawFunds(wallet, network, {
29418
- onchainAddress: withdrawal.onchainAddress,
29419
- amountSats: withdrawal.amountSats,
29420
- exitSpeed: withdrawal.exitSpeed,
29421
- feeQuoteId: withdrawal.feeQuoteId,
29422
- feeAmountSats: withdrawal.feeAmountSats,
29423
- deductFeeFromWithdrawalAmount: withdrawal.deductFeeFromWithdrawalAmount
29424
- });
29425
- }
29426
- var P2PKH_DUST_SATS = 546, P2SH_DUST_SATS = 540, P2WPKH_DUST_SATS = 294, SEGWIT_SCRIPT_DUST_SATS = 330;
29427
- var init_withdrawops = __esm(() => {
29428
- init_network();
29429
- init_fees();
29430
- });
29431
-
29432
- // ../../core/wallet/withdraw.js
29433
- function createWithdrawal({ wallet, network, updateWalletData }) {
29434
- const refreshOnSuccess = async (result) => {
29435
- if (result.success) {
29436
- await updateWalletData({ reason: "withdraw" });
29437
- }
29438
- return result;
29439
- };
29440
- return {
29441
- quoteWithdrawalFees: (params) => quoteWithdrawalFees(wallet, network, params),
29442
- prepareWithdrawal: (params) => prepareWithdrawal(wallet, network, params),
29443
- confirmWithdrawal: async (withdrawal) => refreshOnSuccess(await confirmWithdrawal(wallet, network, withdrawal)),
29444
- withdrawFunds: async (params) => refreshOnSuccess(await withdrawFunds(wallet, network, params))
29445
- };
29446
- }
29447
- var init_withdraw = __esm(() => {
29448
- init_withdrawops();
29449
- });
29450
-
29451
29416
  // ../../core/wallet/session.js
29452
29417
  function sameShallowObject(left, right) {
29453
29418
  if (left === right)
@@ -29499,18 +29464,12 @@ function createEmptyWalletSessionSnapshot(network, transferSnapshot = null, cach
29499
29464
  requestTransferDiscoveryHotWindow: NOOP5,
29500
29465
  claimDeposits: ASYNC_FALSE,
29501
29466
  getFundingAddress: ASYNC_NOOP,
29502
- sendMoneyWithSpark: WALLET_NOT_READY,
29503
- payExternalInvoice: WALLET_NOT_READY,
29467
+ preparePayment: WALLET_NOT_READY,
29468
+ sendPayment: WALLET_NOT_READY,
29504
29469
  createLightningInvoice: WALLET_NOT_READY,
29505
- quoteLightningFees: WALLET_NOT_READY,
29506
- sendLightningPayment: WALLET_NOT_READY,
29507
29470
  getLightningReceiveRequest: WALLET_NOT_READY,
29508
29471
  getLightningSendRequest: WALLET_NOT_READY,
29509
- quoteWithdrawalFees: WALLET_NOT_READY,
29510
- prepareWithdrawal: WALLET_NOT_READY,
29511
- confirmWithdrawal: WALLET_NOT_READY,
29512
- withdrawFunds: WALLET_NOT_READY,
29513
- runWalletMutation: WALLET_NOT_READY
29472
+ runPayment: WALLET_NOT_READY
29514
29473
  },
29515
29474
  txValue: {
29516
29475
  oldestTxMs: null,
@@ -29641,8 +29600,9 @@ function createWalletSession({
29641
29600
  diag
29642
29601
  });
29643
29602
  const transferState = getTransferState();
29644
- const send = createWalletSend({
29603
+ const payment = createPayment({
29645
29604
  wallet,
29605
+ walletPK,
29646
29606
  network,
29647
29607
  updateWalletData,
29648
29608
  refreshBalance: balance.getBalance,
@@ -29652,28 +29612,15 @@ function createWalletSession({
29652
29612
  beginSdkActivity: transferState.beginSdkActivity,
29653
29613
  diag
29654
29614
  });
29655
- const lightning = createLightning({ wallet, updateWalletData });
29656
- const withdrawal = createWithdrawal({ wallet, network, updateWalletData });
29615
+ const lightning = createLightning({ wallet });
29657
29616
  const privacy = createWalletPrivacy({ wallet, ghostWallet, diag });
29658
29617
  const mutations = createWalletMutationQueue();
29659
- const sendMoneyWithSpark = (receiverWalletPK, ...args) => {
29660
- if (sameText(receiverWalletPK, walletPK)) {
29661
- throw new Error("cannot send money to the same wallet");
29662
- }
29663
- return send.sendMoneyWithSpark(receiverWalletPK, ...args);
29664
- };
29665
29618
  const mutationActions = {
29666
- sendMoneyWithSpark: (...args) => mutations.run(() => sendMoneyWithSpark(...args)),
29667
- payExternalInvoice: (...args) => mutations.run(() => send.payExternalInvoice(...args)),
29668
- sendLightningPayment: (...args) => mutations.run(() => lightning.sendLightningPayment(...args)),
29669
- confirmWithdrawal: (...args) => mutations.run(() => withdrawal.confirmWithdrawal(...args)),
29670
- withdrawFunds: (...args) => mutations.run(() => withdrawal.withdrawFunds(...args)),
29671
- runWalletMutation: (task) => mutations.run(() => task({
29672
- sendMoneyWithSpark,
29673
- payExternalInvoice: send.payExternalInvoice,
29674
- sendLightningPayment: lightning.sendLightningPayment,
29675
- confirmWithdrawal: withdrawal.confirmWithdrawal,
29676
- withdrawFunds: withdrawal.withdrawFunds
29619
+ preparePayment: (...args) => mutations.run(() => payment.preparePayment(...args)),
29620
+ sendPayment: (...args) => mutations.run(() => payment.sendPayment(...args)),
29621
+ runPayment: (task) => mutations.run(() => task({
29622
+ preparePayment: payment.preparePayment,
29623
+ sendPayment: payment.sendPayment
29677
29624
  }))
29678
29625
  };
29679
29626
  function buildSnapshot() {
@@ -29695,18 +29642,12 @@ function createWalletSession({
29695
29642
  requestTransferDiscoveryHotWindow: polling.requestTransferDiscoveryHotWindow,
29696
29643
  claimDeposits: claims.claimDeposits,
29697
29644
  getFundingAddress: funding.getFundingAddress,
29698
- sendMoneyWithSpark: mutationActions.sendMoneyWithSpark,
29699
- payExternalInvoice: mutationActions.payExternalInvoice,
29645
+ preparePayment: mutationActions.preparePayment,
29646
+ sendPayment: mutationActions.sendPayment,
29700
29647
  createLightningInvoice: lightning.createLightningInvoice,
29701
- quoteLightningFees: lightning.quoteLightningFees,
29702
- sendLightningPayment: mutationActions.sendLightningPayment,
29703
29648
  getLightningReceiveRequest: lightning.getLightningReceiveRequest,
29704
29649
  getLightningSendRequest: lightning.getLightningSendRequest,
29705
- quoteWithdrawalFees: withdrawal.quoteWithdrawalFees,
29706
- prepareWithdrawal: withdrawal.prepareWithdrawal,
29707
- confirmWithdrawal: mutationActions.confirmWithdrawal,
29708
- withdrawFunds: mutationActions.withdrawFunds,
29709
- runWalletMutation: mutationActions.runWalletMutation
29650
+ runPayment: mutationActions.runPayment
29710
29651
  };
29711
29652
  const txValue = {
29712
29653
  oldestTxMs: currentTransferState.oldestLoadedMs,
@@ -29769,7 +29710,7 @@ function createWalletSession({
29769
29710
  polling.close();
29770
29711
  privacy.close();
29771
29712
  mutations.close();
29772
- send.close();
29713
+ payment.close();
29773
29714
  claims.close();
29774
29715
  funding.close();
29775
29716
  updateWalletData.close();
@@ -29790,10 +29731,9 @@ var init_session5 = __esm(() => {
29790
29731
  init_funding();
29791
29732
  init_lightning();
29792
29733
  init_lifecycle();
29734
+ init_payment();
29793
29735
  init_privacy();
29794
- init_send2();
29795
29736
  init_transfers2();
29796
- init_withdraw();
29797
29737
  init_localdata();
29798
29738
  });
29799
29739
 
@@ -30144,7 +30084,9 @@ function txSearchFields(tx) {
30144
30084
  tx?.amount == null ? "" : String(tx.amount),
30145
30085
  tx?.incoming ? "incoming received inflow" : "outgoing sent outflow",
30146
30086
  tx?.funding ? "funded fund deposit" : "",
30147
- tx?.withdrawal ? "withdrawn withdraw" : "",
30087
+ tx?.bitcoin ? "bitcoin payment onchain on-chain l1" : "",
30088
+ tx?.bitcoinAddress,
30089
+ tx?.bitcoinTxid,
30148
30090
  tx?.pending ? "pending" : "completed"
30149
30091
  ];
30150
30092
  }
@@ -30360,7 +30302,7 @@ function getRecentWalletPeers(transfers, walletPK) {
30360
30302
  continue;
30361
30303
  }
30362
30304
  const tx = enrichTx(raw);
30363
- if (!isVisibleTransfer(tx) || tx.funding || tx.withdrawal || !tx.peerPK || tx.peerPK === walletPK) {
30305
+ if (!isVisibleTransfer(tx) || tx.funding || tx.bitcoin || !tx.peerPK || tx.peerPK === walletPK) {
30364
30306
  continue;
30365
30307
  }
30366
30308
  const txMs = tx.createdMs || 0;
@@ -30399,7 +30341,7 @@ function getPeerDataFromTransfers(transfers, walletPK, peerPK) {
30399
30341
  if (rawPeerPK !== peerPK)
30400
30342
  continue;
30401
30343
  const tx = enrichTx(raw);
30402
- if (tx.funding || tx.withdrawal) {
30344
+ if (tx.funding || tx.bitcoin) {
30403
30345
  continue;
30404
30346
  }
30405
30347
  txs.push(tx);
@@ -30763,7 +30705,7 @@ var byRecentTx = (a, b) => {
30763
30705
  return String(b?.id || "").localeCompare(String(a?.id || ""));
30764
30706
  }, TX_TIME_RANGES, enrichTx = (tx) => {
30765
30707
  const incoming = tx.transferDirection === "INCOMING";
30766
- const isWithdrawal = isWithdrawalTransfer(tx);
30708
+ const isBitcoinPayment = isBitcoinPaymentTransfer(tx);
30767
30709
  const isFunding = isFundingTransfer(tx);
30768
30710
  const pending = !isCompletedTransfer(tx);
30769
30711
  const peerPK = incoming ? tx.senderIdentityPublicKey : tx.receiverIdentityPublicKey;
@@ -30775,10 +30717,10 @@ var byRecentTx = (a, b) => {
30775
30717
  totalValue: tx.totalValue,
30776
30718
  amount: incoming ? tx.totalValue : -tx.totalValue,
30777
30719
  funding: isFunding,
30778
- withdrawal: isWithdrawal,
30720
+ bitcoin: isBitcoinPayment,
30779
30721
  pending,
30780
30722
  pendingCredit: pending && (incoming || isFunding),
30781
- summaryPending: pending && (incoming || isFunding || isWithdrawal)
30723
+ summaryPending: pending && (incoming || isFunding || isBitcoinPayment)
30782
30724
  };
30783
30725
  }, aggregateTxs = (transfers, userPK) => {
30784
30726
  const dayMap = new Map;
@@ -30810,7 +30752,7 @@ var byRecentTx = (a, b) => {
30810
30752
  }
30811
30753
  if (!firstDate || txDate < firstDate)
30812
30754
  firstDate = txDate;
30813
- if (tx.peerPK && tx.peerPK !== userPK && !tx.funding && !tx.withdrawal) {
30755
+ if (tx.peerPK && tx.peerPK !== userPK && !tx.funding && !tx.bitcoin) {
30814
30756
  const txMs = txDate.getTime();
30815
30757
  if (!peerMap.has(tx.peerPK)) {
30816
30758
  peerMap.set(tx.peerPK, {
@@ -31713,16 +31655,16 @@ var PASSKEY_ENVIRONMENT_MISMATCH = "passkey-environment-mismatch", PASSKEY_PROVI
31713
31655
  var init_passkey = () => {};
31714
31656
 
31715
31657
  // ../../product/links.js
31716
- var links, localHosts, allowedPasskeyOrigins, storageCorsOrigins, webApps;
31658
+ var links, localHosts, prodPasskeyOrigins, devPasskeyOrigins, allowedPasskeyOrigins, storageCorsOrigins, devStorageCorsOrigins, webApps;
31717
31659
  var init_links = __esm(() => {
31718
31660
  init_origins();
31719
31661
  links = Object.freeze({
31720
31662
  root: origins.root,
31721
31663
  rootDev: origins.rootDev,
31722
- rootDevWeb: origins.rootDevWeb,
31723
31664
  veyl: origins.veyl,
31724
31665
  veylDev: origins.veylDev,
31725
31666
  veylDevWeb: origins.veylDevWeb,
31667
+ veylDevFeatureWeb: origins.veylDevFeatureWeb,
31726
31668
  terms: `${origins.veyl}/legal#terms`,
31727
31669
  communityRules: `${origins.veyl}/community-rules`,
31728
31670
  contact: `mailto:contact@${ROOT_DOMAIN}`,
@@ -31732,19 +31674,26 @@ var init_links = __esm(() => {
31732
31674
  domains.rootDev,
31733
31675
  domains.veylDev
31734
31676
  ]);
31735
- allowedPasskeyOrigins = Object.freeze([
31677
+ prodPasskeyOrigins = Object.freeze([
31736
31678
  origins.root,
31737
- origins.rootDev,
31738
- origins.rootDevWeb,
31679
+ origins.veyl
31680
+ ]);
31681
+ devPasskeyOrigins = Object.freeze([
31739
31682
  origins.veylDev,
31740
31683
  origins.veylDevWeb,
31741
- origins.veyl
31684
+ origins.veylDevFeatureWeb
31685
+ ]);
31686
+ allowedPasskeyOrigins = Object.freeze([
31687
+ ...prodPasskeyOrigins,
31688
+ ...devPasskeyOrigins
31742
31689
  ]);
31743
31690
  storageCorsOrigins = Object.freeze([
31744
- origins.rootDevWeb,
31691
+ origins.veyl
31692
+ ]);
31693
+ devStorageCorsOrigins = Object.freeze([
31745
31694
  origins.veylDev,
31746
31695
  origins.veylDevWeb,
31747
- origins.veyl
31696
+ origins.veylDevFeatureWeb
31748
31697
  ]);
31749
31698
  webApps = Object.freeze({
31750
31699
  veyl: Object.freeze({
@@ -33066,8 +33015,8 @@ function makeInvite(value = {}) {
33066
33015
  const cleanedKind = cleanKind(kind);
33067
33016
  const rawTo = value.to ?? value.recipient;
33068
33017
  const toIsUsername = !!cleanUsername2(rawTo);
33069
- const paymentKind = cleanedKind === invite.send || cleanedKind === invite.request;
33070
- const receiver = value.r ?? value.walletPK ?? value.receiver ?? (paymentKind && !toIsUsername ? rawTo : null);
33018
+ const paymentKind2 = cleanedKind === invite.send || cleanedKind === invite.request;
33019
+ const receiver = value.r ?? value.walletPK ?? value.receiver ?? (paymentKind2 && !toIsUsername ? rawTo : null);
33071
33020
  const data = readParams({
33072
33021
  kind,
33073
33022
  from: value.from ?? value.sender,
@@ -33368,8 +33317,8 @@ function createRuntimeProductActions({
33368
33317
  await getUser();
33369
33318
  return supportOwner.feedback(message, {
33370
33319
  type: options.type,
33371
- platform: "headless",
33372
- route: cleanText(options.route) || "cli",
33320
+ platform: "sdk",
33321
+ route: cleanText(options.route) || "sdk",
33373
33322
  appVersion: version || "",
33374
33323
  context: options.context
33375
33324
  });
@@ -33377,8 +33326,8 @@ function createRuntimeProductActions({
33377
33326
  async bug(message, options = {}) {
33378
33327
  await getUser();
33379
33328
  return supportOwner.bug(message, {
33380
- platform: "headless",
33381
- route: cleanText(options.route) || "cli",
33329
+ platform: "sdk",
33330
+ route: cleanText(options.route) || "sdk",
33382
33331
  appVersion: version || ""
33383
33332
  });
33384
33333
  },
@@ -40812,21 +40761,21 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
40812
40761
  transfer
40813
40762
  };
40814
40763
  }
40815
- function cleanWithdrawal(withdrawal, options = {}) {
40816
- if (!withdrawal)
40764
+ function cleanBitcoinPayment(payment, options = {}) {
40765
+ if (!payment)
40817
40766
  return null;
40818
40767
  return {
40819
- kind: withdrawal.kind,
40820
- onchainAddress: withdrawal.onchainAddress,
40821
- amountSats: withdrawal.amountSats,
40822
- exitSpeed: withdrawal.exitSpeed,
40823
- deductFeeFromWithdrawalAmount: withdrawal.deductFeeFromWithdrawalAmount,
40824
- feeQuoteId: withdrawal.feeQuoteId,
40825
- feeAmountSats: withdrawal.feeAmountSats,
40826
- fees: stripFees(withdrawal.fees, options),
40827
- amounts: getWithdrawalReviewAmounts(withdrawal),
40828
- expiresAt: withdrawal.expiresAt,
40829
- raw: options.raw ? jsonSafe(withdrawal.feeQuote) : undefined
40768
+ kind: payment.kind,
40769
+ onchainAddress: payment.destination,
40770
+ amountSats: payment.amountSats,
40771
+ exitSpeed: payment.exitSpeed,
40772
+ deductFeeFromWithdrawalAmount: payment.deductFeeFromAmount,
40773
+ feeQuoteId: payment.feeQuoteId,
40774
+ feeAmountSats: payment.feeAmountSats,
40775
+ fees: stripFees(payment.fees, options),
40776
+ amounts: getBitcoinPaymentAmounts(payment),
40777
+ expiresAt: payment.expiresAt,
40778
+ raw: options.raw ? jsonSafe(payment.feeQuote) : undefined
40830
40779
  };
40831
40780
  }
40832
40781
  async function uncertainMutation(operation, operationId, retryable, run) {
@@ -40872,20 +40821,25 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
40872
40821
  await snapshot2.value.refresh();
40873
40822
  return { claimed: depositsClaimed === true || transferIds2.length > 0, depositsClaimed, transferIds: transferIds2 };
40874
40823
  }
40875
- async function sendWith(peer, sats, options = {}, sendMoneyWithSpark = null) {
40824
+ async function sendWith(peer, sats, options = {}, paymentSender = null) {
40876
40825
  const { snapshot: snapshot2 } = await readyWallet();
40877
40826
  const amountSats = cleanPositiveSats(sats);
40878
40827
  const profile = await resolvePeer(peer);
40879
40828
  if (!profile.walletPK)
40880
40829
  throw new Error("peer wallet key missing");
40881
- const sendMoney = sendMoneyWithSpark || snapshot2.value.sendMoneyWithSpark;
40882
- const txId = await uncertainMutation("wallet.send", options.operationId, false, () => sendMoney(profile.walletPK, amountSats));
40830
+ const sendPayment = paymentSender || snapshot2.value.sendPayment;
40831
+ const receipt = await uncertainMutation("wallet.send", options.operationId, false, () => sendPayment({
40832
+ kind: PAYMENT_KIND_SPARK,
40833
+ destination: profile.walletPK,
40834
+ amountSats
40835
+ }));
40836
+ const txId = receipt?.id || null;
40883
40837
  return {
40884
- txId: txId || null,
40838
+ txId,
40885
40839
  operationId: options.operationId || txId || null,
40886
40840
  amountSats,
40887
40841
  peer: profile.username ? `@${profile.username}` : profile.uid,
40888
- raw: options.raw ? { id: txId || null } : undefined
40842
+ raw: options.raw ? jsonSafe(receipt) : undefined
40889
40843
  };
40890
40844
  }
40891
40845
  const send = (peer, sats, options = {}) => sendWith(peer, sats, options);
@@ -40904,37 +40858,34 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
40904
40858
  }
40905
40859
  async function lightningQuote(encodedInvoice, options = {}) {
40906
40860
  const { snapshot: snapshot2 } = await readyWallet();
40907
- const result = throwIfFailed(await snapshot2.value.quoteLightningFees({
40908
- invoice: encodedInvoice,
40909
- amountSats: options.amountSats
40910
- }), "could not quote lightning fees");
40911
- return { feeAmountSats: result.feeAmountSats, fees: result.fees };
40861
+ const payment = await snapshot2.value.preparePayment({
40862
+ kind: PAYMENT_KIND_LIGHTNING,
40863
+ destination: encodedInvoice,
40864
+ amountSats: options.amountSats,
40865
+ variableAmount: options.amountSats != null
40866
+ });
40867
+ return { feeAmountSats: payment.maxFeeSats, fees: payment.fees };
40912
40868
  }
40913
40869
  async function lightningPay(encodedInvoice, options = {}) {
40914
40870
  const { snapshot: snapshot2 } = await readyWallet();
40915
40871
  const amountSatsToSend = options.amountSatsToSend ?? options.amountSats;
40916
- let maxFeeSats = options.maxFeeSats;
40917
- let fees = null;
40918
- if (maxFeeSats == null) {
40919
- const quote = throwIfFailed(await snapshot2.value.quoteLightningFees({ invoice: encodedInvoice, amountSats: amountSatsToSend }), "could not quote lightning fees");
40920
- maxFeeSats = quote.feeAmountSats;
40921
- fees = quote.fees;
40922
- }
40923
40872
  const operationId = cleanText(options.idempotencyKey || options.operationId);
40924
- const result = await uncertainMutation("lightning.pay", operationId, !!options.idempotencyKey, async () => throwIfFailed(await snapshot2.value.sendLightningPayment({
40925
- invoice: encodedInvoice,
40926
- maxFeeSats,
40873
+ const receipt = await uncertainMutation("lightning.pay", operationId, !!options.idempotencyKey, () => snapshot2.value.sendPayment({
40874
+ kind: PAYMENT_KIND_LIGHTNING,
40875
+ destination: encodedInvoice,
40876
+ amountSats: amountSatsToSend,
40877
+ variableAmount: amountSatsToSend != null,
40878
+ maxFeeSats: options.maxFeeSats,
40927
40879
  preferSpark: options.preferSpark === true,
40928
- amountSatsToSend,
40929
40880
  idempotencyKey: options.idempotencyKey
40930
- }), "could not pay lightning invoice"));
40931
- const resultId = result.result?.id || result.payment?.id || null;
40881
+ }));
40882
+ const resultId = receipt?.id || null;
40932
40883
  return {
40933
40884
  id: resultId,
40934
40885
  operationId: operationId || resultId,
40935
- fees,
40936
- result: summarizePaymentResult(result.result),
40937
- raw: options.raw ? jsonSafe(result) : undefined
40886
+ fees: receipt?.fees || null,
40887
+ result: summarizePaymentResult(receipt?.result),
40888
+ raw: options.raw ? jsonSafe(receipt) : undefined
40938
40889
  };
40939
40890
  }
40940
40891
  async function lightningReceive(id, options = {}) {
@@ -40960,44 +40911,53 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
40960
40911
  throw new Error("invoice must be a direct lightning or spark invoice string");
40961
40912
  }
40962
40913
  const { snapshot: snapshot2 } = await readyWallet();
40963
- const result = await uncertainMutation("wallet.pay-invoice", options.operationId, false, () => snapshot2.value.payExternalInvoice({
40964
- type,
40965
- invoice: parsed.invoice,
40914
+ const receipt = await uncertainMutation("wallet.pay-invoice", options.operationId, false, () => snapshot2.value.sendPayment({
40915
+ kind: type === "lightning" ? PAYMENT_KIND_LIGHTNING : PAYMENT_KIND_SPARK_INVOICE,
40916
+ destination: parsed.invoice,
40966
40917
  amountSats: options.amountSats,
40967
- variableAmount: options.amountSats != null
40918
+ variableAmount: options.amountSats != null,
40919
+ preferSpark: type === "lightning"
40968
40920
  }));
40969
- const resultId = result?.id || result?.result?.id || null;
40921
+ const resultId = receipt?.id || null;
40970
40922
  return {
40971
40923
  type,
40972
40924
  id: resultId,
40973
40925
  operationId: options.operationId || resultId || null,
40974
- fees: result?.fees || null,
40975
- result: summarizePaymentResult(result?.result),
40976
- raw: options.raw ? jsonSafe(result) : undefined
40926
+ fees: receipt?.fees || null,
40927
+ result: summarizePaymentResult(receipt?.result),
40928
+ raw: options.raw ? jsonSafe(receipt) : undefined
40977
40929
  };
40978
40930
  }
40979
- async function withdrawQuote(onchainAddress, sats, options = {}) {
40931
+ async function quoteBitcoinPayment(onchainAddress, sats, options = {}) {
40980
40932
  const { snapshot: snapshot2 } = await readyWallet();
40981
- const result = throwIfFailed(await snapshot2.value.quoteWithdrawalFees({ onchainAddress, amountSats: sats }), "could not quote withdrawal");
40933
+ const payment = await snapshot2.value.preparePayment({
40934
+ kind: PAYMENT_KIND_BITCOIN,
40935
+ destination: onchainAddress,
40936
+ amountSats: sats,
40937
+ exitSpeed: options.exitSpeed || options.speed,
40938
+ deductFeeFromAmount: options.deductFeeFromWithdrawalAmount !== false
40939
+ });
40982
40940
  return {
40983
- amountSats: result.amountSats,
40984
- onchainAddress: result.onchainAddress,
40985
- feeQuoteId: result.feeQuote?.id || null,
40986
- fees: stripFees(result.fees, options),
40987
- raw: options.raw ? jsonSafe(result.feeQuote) : undefined
40941
+ amountSats: payment.amountSats,
40942
+ onchainAddress: payment.destination,
40943
+ feeQuoteId: payment.feeQuoteId,
40944
+ feeAmountSats: payment.feeAmountSats,
40945
+ fees: stripFees(payment.fees, options),
40946
+ raw: options.raw ? jsonSafe(payment.feeQuote) : undefined
40988
40947
  };
40989
40948
  }
40990
- async function withdrawPrepare(onchainAddress, sats, options = {}) {
40949
+ async function prepareBitcoinPayment(onchainAddress, sats, options = {}) {
40991
40950
  const { snapshot: snapshot2 } = await readyWallet();
40992
- const result = throwIfFailed(await snapshot2.value.prepareWithdrawal({
40993
- onchainAddress,
40951
+ const payment = await snapshot2.value.preparePayment({
40952
+ kind: PAYMENT_KIND_BITCOIN,
40953
+ destination: onchainAddress,
40994
40954
  amountSats: sats,
40995
40955
  exitSpeed: options.exitSpeed || options.speed,
40996
- deductFeeFromWithdrawalAmount: options.deductFeeFromWithdrawalAmount !== false
40997
- }), "could not prepare withdrawal");
40998
- return cleanWithdrawal(result.withdrawal, options);
40956
+ deductFeeFromAmount: options.deductFeeFromWithdrawalAmount !== false
40957
+ });
40958
+ return cleanBitcoinPayment(payment, options);
40999
40959
  }
41000
- async function withdraw(onchainAddress, sats, options = {}) {
40960
+ async function sendBitcoinPayment(onchainAddress, sats, options = {}) {
41001
40961
  const hasFeeQuoteId = !!cleanText(options.feeQuoteId);
41002
40962
  const hasFeeAmountSats = options.feeAmountSats != null;
41003
40963
  if (hasFeeQuoteId !== hasFeeAmountSats) {
@@ -41005,22 +40965,28 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
41005
40965
  }
41006
40966
  const { snapshot: snapshot2 } = await readyWallet();
41007
40967
  const operationId = cleanText(options.operationId || options.feeQuoteId);
41008
- const result = await uncertainMutation("withdrawal.confirm", operationId, false, async () => throwIfFailed(await snapshot2.value.withdrawFunds({
41009
- onchainAddress,
40968
+ const intent = {
40969
+ kind: PAYMENT_KIND_BITCOIN,
40970
+ destination: onchainAddress,
41010
40971
  amountSats: sats,
41011
40972
  exitSpeed: options.exitSpeed || options.speed,
41012
- feeQuote: options.feeQuote,
40973
+ deductFeeFromAmount: options.deductFeeFromWithdrawalAmount !== false
40974
+ };
40975
+ const payment = hasFeeQuoteId ? {
40976
+ ...intent,
40977
+ state: PAYMENT_STATE_PREPARED,
40978
+ feeQuote: options.feeQuote || null,
41013
40979
  feeQuoteId: options.feeQuoteId,
41014
- feeAmountSats: options.feeAmountSats,
41015
- deductFeeFromWithdrawalAmount: options.deductFeeFromWithdrawalAmount !== false
41016
- }), "could not withdraw funds"));
41017
- const txId = result.tx?.id || result.tx?.txid || null;
40980
+ feeAmountSats: options.feeAmountSats
40981
+ } : await snapshot2.value.preparePayment(intent);
40982
+ const receipt = await uncertainMutation("withdrawal.confirm", operationId, false, () => snapshot2.value.sendPayment(payment));
40983
+ const txId = receipt?.result?.coopExitTxid || receipt?.result?.id || receipt?.id || null;
41018
40984
  return {
41019
40985
  txId,
41020
40986
  operationId: operationId || txId || null,
41021
- feeAmountSats: result.feeAmountSats,
41022
- fees: stripFees(result.fees, options),
41023
- tx: options.raw ? jsonSafe(result.tx) : undefined
40987
+ feeAmountSats: payment.feeAmountSats,
40988
+ fees: stripFees(payment.fees, options),
40989
+ tx: options.raw ? jsonSafe(receipt?.result) : undefined
41024
40990
  };
41025
40991
  }
41026
40992
  async function request2(peer, sats, options = {}) {
@@ -41043,7 +41009,7 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
41043
41009
  const peer = profile.username ? `@${profile.username}` : peerChatPK;
41044
41010
  let mutationStarted = false;
41045
41011
  try {
41046
- return await snapshot2.value.runWalletMutation(async ({ sendMoneyWithSpark }) => {
41012
+ return await snapshot2.value.runPayment(async ({ sendPayment }) => {
41047
41013
  const target = await chat.messageForPeer(peer, messageId, { count: 100 });
41048
41014
  const message = target.message;
41049
41015
  if (!message || message.t !== "req")
@@ -41055,9 +41021,9 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
41055
41021
  if (!isRequestOnNetwork(message, target.session.network)) {
41056
41022
  throw new Error(`switch wallet network to ${requestNetwork(message)?.toLowerCase() || "the request network"} before paying`);
41057
41023
  }
41058
- const paid = await sendWith(peer, cleanPositiveSats(message.a), options, (...args) => {
41024
+ const paid = await sendWith(peer, cleanPositiveSats(message.a), options, (intent) => {
41059
41025
  mutationStarted = true;
41060
- return sendMoneyWithSpark(...args);
41026
+ return sendPayment(intent);
41061
41027
  });
41062
41028
  const updated = { ...setReqTx(message, paid.txId), cid: message.cid };
41063
41029
  await runtime.chat.getSnapshot().updateMessage(chatId, message.id, updated, peerChatPK);
@@ -41133,9 +41099,9 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
41133
41099
  transactions,
41134
41100
  searchTransactions,
41135
41101
  transaction,
41136
- withdrawQuote,
41137
- withdrawPrepare,
41138
- withdraw
41102
+ quoteBitcoinPayment,
41103
+ prepareBitcoinPayment,
41104
+ sendBitcoinPayment
41139
41105
  };
41140
41106
  }
41141
41107
  var DEFAULT_TIMEOUT_MS4 = 15000, HISTORY_LOAD_ATTEMPTS = 4, messageWindowSequence = 0;
@@ -41147,7 +41113,7 @@ var init_runtime_actions = __esm(() => {
41147
41113
  init_values();
41148
41114
  init_fees();
41149
41115
  init_claiming();
41150
- init_withdrawops();
41116
+ init_payment();
41151
41117
  init_tx();
41152
41118
  init_invoice();
41153
41119
  init_messages3();
@@ -41160,9 +41126,9 @@ var package_default;
41160
41126
  var init_package = __esm(() => {
41161
41127
  package_default = {
41162
41128
  name: "veyl",
41163
- version: "0.51.0",
41129
+ version: "0.55.0",
41164
41130
  private: true,
41165
- license: "Apache-2.0",
41131
+ license: "UNLICENSED",
41166
41132
  workspaces: {
41167
41133
  packages: [
41168
41134
  "clients/*",
@@ -41214,7 +41180,8 @@ var init_package = __esm(() => {
41214
41180
  "install:clean": "bun scripts/deps.mjs clean-install",
41215
41181
  update: "bun scripts/deps.mjs update",
41216
41182
  "sync:frameworks": "bun scripts/sync-frameworks.mjs",
41217
- "check:frameworks": "bun scripts/sync-frameworks.mjs --check"
41183
+ "check:frameworks": "bun scripts/sync-frameworks.mjs --check",
41184
+ "test:repo": "bun scripts/test.mjs"
41218
41185
  },
41219
41186
  dependencies: {
41220
41187
  "@buildonspark/spark-sdk": "^0.9.0",
@@ -41514,9 +41481,9 @@ class AccountRuntime {
41514
41481
  send: (id, payload) => this.lightningSend(id, payload)
41515
41482
  };
41516
41483
  this.withdrawal = {
41517
- quote: (address, sats, payload) => this.withdrawQuote(address, sats, payload),
41518
- prepare: (address, sats, payload) => this.withdrawPrepare(address, sats, payload),
41519
- confirm: (address, sats, payload) => this.withdraw(address, sats, payload)
41484
+ quote: (address, sats, payload) => this.quoteBitcoinPayment(address, sats, payload),
41485
+ prepare: (address, sats, payload) => this.prepareBitcoinPayment(address, sats, payload),
41486
+ confirm: (address, sats, payload) => this.sendBitcoinPayment(address, sats, payload)
41520
41487
  };
41521
41488
  this.profile = this.runtimeProduct.profile;
41522
41489
  this.settings = this.runtimeProduct.settings;
@@ -41566,7 +41533,7 @@ class AccountRuntime {
41566
41533
  chatPK: profile.chatPK || null,
41567
41534
  notificationPK: profile.notificationPK || null,
41568
41535
  auth: profile.auth || "machine",
41569
- bot: profile.bot || null,
41536
+ bot: profile.bot === BOT_PROFILE_MARKER ? BOT_PROFILE_MARKER : null,
41570
41537
  signedIn: this.auth?.currentUser?.uid === profile.uid,
41571
41538
  unlocked: !!this.session
41572
41539
  };
@@ -41617,7 +41584,7 @@ class AccountRuntime {
41617
41584
  publicKeyPem: machine.publicKeyPem,
41618
41585
  privateKeyPem: options.saveCredential === false ? null : machine.privateKeyPem,
41619
41586
  auth: "machine",
41620
- bot: finish.bot || "bot",
41587
+ bot: finish.bot === BOT_PROFILE_MARKER ? BOT_PROFILE_MARKER : null,
41621
41588
  createdAt: Date.now(),
41622
41589
  hasVault: false
41623
41590
  });
@@ -41636,7 +41603,17 @@ class AccountRuntime {
41636
41603
  if (!credentialId || !privateKeyPem) {
41637
41604
  throw new Error("machine credential required");
41638
41605
  }
41639
- const start = await this.callAccountEndpoint("/account/login/start", { credentialId });
41606
+ const namespaceKeyPath = options.namespaceKeyPath || this.options.namespaceKeyPath;
41607
+ const namespaceClaim = options.namespaceClaim || (namespaceKeyPath ? await this.ports.signNamespaceClaim({
41608
+ path: namespaceKeyPath,
41609
+ optional: options.namespaceKeyOptional === true || this.options.namespaceKeyOptional === true,
41610
+ username: profile.username || username,
41611
+ credentialId
41612
+ }) : null);
41613
+ const start = await this.callAccountEndpoint("/account/login/start", {
41614
+ credentialId,
41615
+ ...namespaceClaim ? { namespaceClaim } : {}
41616
+ });
41640
41617
  const finish = await this.callAccountEndpoint("/account/login/finish", {
41641
41618
  challengeId: start.challengeId,
41642
41619
  signature: this.ports.signChallenge(privateKeyPem, start.challenge)
@@ -41648,7 +41625,7 @@ class AccountRuntime {
41648
41625
  uid: finish.uid || profile.uid,
41649
41626
  username: finish.username || profile.username,
41650
41627
  credentialId,
41651
- bot: finish.bot || profile.bot || null,
41628
+ bot: finish.bot === BOT_PROFILE_MARKER ? BOT_PROFILE_MARKER : null,
41652
41629
  lastLoginAt: Date.now()
41653
41630
  });
41654
41631
  return this.accountSummary(next);
@@ -41730,6 +41707,7 @@ class AccountRuntime {
41730
41707
  publicKeyPem: machine?.publicKeyPem || stored?.publicKeyPem || null,
41731
41708
  privateKeyPem: options.saveCredential === false ? stored?.privateKeyPem || null : machine?.privateKeyPem || stored?.privateKeyPem || null,
41732
41709
  auth: "passkey",
41710
+ bot: null,
41733
41711
  lastLoginAt: Date.now()
41734
41712
  });
41735
41713
  return {
@@ -42144,14 +42122,14 @@ class AccountRuntime {
42144
42122
  async transaction(id, options = {}) {
42145
42123
  return this.runtimeMoney.transaction(id, options);
42146
42124
  }
42147
- async withdrawQuote(address, sats, options = {}) {
42148
- return this.runtimeMoney.withdrawQuote(address, sats, options);
42125
+ async quoteBitcoinPayment(address, sats, options = {}) {
42126
+ return this.runtimeMoney.quoteBitcoinPayment(address, sats, options);
42149
42127
  }
42150
- async withdrawPrepare(address, sats, options = {}) {
42151
- return this.runtimeMoney.withdrawPrepare(address, sats, options);
42128
+ async prepareBitcoinPayment(address, sats, options = {}) {
42129
+ return this.runtimeMoney.prepareBitcoinPayment(address, sats, options);
42152
42130
  }
42153
- async withdraw(address, sats, options = {}) {
42154
- return this.runtimeMoney.withdraw(address, sats, options);
42131
+ async sendBitcoinPayment(address, sats, options = {}) {
42132
+ return this.runtimeMoney.sendBitcoinPayment(address, sats, options);
42155
42133
  }
42156
42134
  async listenEvents(options = {}) {
42157
42135
  return listenAccount(this, options);
@@ -42187,6 +42165,7 @@ var init_client = __esm(() => {
42187
42165
  init_core();
42188
42166
  init_agreement();
42189
42167
  init_network();
42168
+ init_profile();
42190
42169
  init_username();
42191
42170
  init_time();
42192
42171
  init_vault();
@@ -88807,7 +88786,7 @@ var OutP2A, OutPK, OutPKH, OutSH, OutWSH, OutWPKH, OutMS, OutTR, OutTRNS, OutTRM
88807
88786
  hash
88808
88787
  };
88809
88788
  }, TAP_LEAF_VERSION = 192, tapLeafHash = (script, version = TAP_LEAF_VERSION) => tagSchnorr("TapLeaf", new Uint8Array([version]), VarBytes.encode(script)), base58check;
88810
- var init_payment = __esm(() => {
88789
+ var init_payment2 = __esm(() => {
88811
88790
  init_esm();
88812
88791
  init_esm2();
88813
88792
  init_psbt();
@@ -89970,7 +89949,7 @@ var EMPTY32, EMPTY_OUTPUT, toVsize = (weight) => Math.ceil(weight / 4), PRECISIO
89970
89949
  var init_transaction = __esm(() => {
89971
89950
  init_esm();
89972
89951
  init_esm2();
89973
- init_payment();
89952
+ init_payment2();
89974
89953
  init_psbt();
89975
89954
  init_script();
89976
89955
  init_utils6();
@@ -90003,11 +89982,11 @@ var init_transaction = __esm(() => {
90003
89982
 
90004
89983
  // ../../node_modules/.bun/@scure+btc-signer@1.8.1/node_modules/@scure/btc-signer/esm/index.js
90005
89984
  var init_esm3 = __esm(() => {
90006
- init_payment();
89985
+ init_payment2();
90007
89986
  init_script();
90008
89987
  init_transaction();
90009
89988
  init_utils6();
90010
- init_payment();
89989
+ init_payment2();
90011
89990
  init_transaction();
90012
89991
  /*! scure-btc-signer - MIT License (c) 2022 Paul Miller (paulmillr.com) */
90013
89992
  });
@@ -104366,7 +104345,7 @@ var init_spark_wallet_CwB3Fuv1 = __esm(() => {
104366
104345
  init_esm3();
104367
104346
  init_utils6();
104368
104347
  init_psbt();
104369
- init_payment();
104348
+ init_payment2();
104370
104349
  init_hmac2();
104371
104350
  init_esm4();
104372
104351
  init_esm5();
@@ -175978,7 +175957,7 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
175978
175957
  return [];
175979
175958
  let roleQuery = null;
175980
175959
  if (role.id === "bots") {
175981
- roleQuery = query(collection(db, "profiles"), where("bot", "!=", false), limit(SEARCH_ROLE_LIMIT));
175960
+ roleQuery = query(collection(db, "profiles"), where("bot", "==", BOT_PROFILE_MARKER), limit(SEARCH_ROLE_LIMIT));
175982
175961
  } else if (role.id === "active") {
175983
175962
  roleQuery = query(collection(db, "profiles"), where("active", "==", true), limit(SEARCH_ROLE_LIMIT));
175984
175963
  }
@@ -176898,6 +176877,7 @@ var init_cloud = __esm(() => {
176898
176877
  init_dist5();
176899
176878
  init_dist6();
176900
176879
  init_avatar();
176880
+ init_profile();
176901
176881
  init_filepayload();
176902
176882
  init_protocol();
176903
176883
  init_config();
@@ -176921,7 +176901,7 @@ function sdkFunctionBaseUrl(config = firebaseConfig, region = DEFAULT_FUNCTION_R
176921
176901
  if (!projectId) {
176922
176902
  throw new Error("firebase project id required");
176923
176903
  }
176924
- return `https://${region}-${projectId}.cloudfunctions.net/headless`;
176904
+ return `https://${region}-${projectId}.cloudfunctions.net/machineAuth`;
176925
176905
  }
176926
176906
  function createCloudRuntime(options2 = {}) {
176927
176907
  const config = options2.firebaseConfig || firebaseConfig;
@@ -177596,7 +177576,7 @@ async function runPasskeyBrowserFlow(options2 = {}) {
177596
177576
  throw error;
177597
177577
  }
177598
177578
  const callback = `http://127.0.0.1:${address.port}${CALLBACK_PATH}`;
177599
- const target = appendSearch(new URL("/cli/passkey", cleanWebUrl(options2.webUrl)), {
177579
+ const target = appendSearch(new URL("/sdk/passkey", cleanWebUrl(options2.webUrl)), {
177600
177580
  mode,
177601
177581
  state,
177602
177582
  callback,
@@ -179146,6 +179126,7 @@ class FleetOwner {
179146
179126
  activate: false,
179147
179127
  credential: material.credential,
179148
179128
  vaultSecret: material.vaultSecret,
179129
+ namespaceKeyPath: this.options.namespaceKeyPath,
179149
179130
  getVaultMasterSeed: () => {
179150
179131
  const derived = deriveFleetAccount(this.seed, accountIndex);
179151
179132
  try {
@@ -179331,7 +179312,6 @@ class FleetOwner {
179331
179312
  publicKeyPem: material.credential.publicKeyPem,
179332
179313
  privateKeyPem: null,
179333
179314
  auth: "machine",
179334
- bot: "bot",
179335
179315
  hasVault: false,
179336
179316
  createdAt: Date.now()
179337
179317
  });