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