@qntx/spark 0.3.0 → 0.5.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/README.md CHANGED
@@ -68,6 +68,13 @@ those inputs once. Retrying without it would select different outputs and pay tw
68
68
  Offline receive: once a transfer commits, the sender cannot cancel it and its expiry does not
69
69
  return it — `transfers.claim(transferId)`/`claimPending` can pick it up at any later time.
70
70
 
71
+ Transaction history: `transfers.history({ limit?, offset? })` pages transfers newest-first
72
+ (`TRANSFER`, `PREIMAGE_SWAP`, `COOPERATIVE_EXIT`, `UTXO_SWAP`), folding each entry with its SSP
73
+ `user_request` when the counterparty is the SSP — lightning invoices, payment hashes and
74
+ preimages, coop-exit fees and payout txids, static-deposit credits. Entries surface as
75
+ `SparkPayment` (`send`/`receive`, `pending`/`completed`/`failed`, `spark`/`lightning`/`deposit`/
76
+ `withdraw`); `nextOffset` is `undefined` at the end.
77
+
71
78
  Unilateral exit: each pre-signed transaction carries a hard deadline — once its parent confirms
72
79
  and its relative timelock passes, it must confirm within 50 blocks; otherwise the operators'
73
80
  watchtower may publish a self-fee variant instead. For intermediate nodes this strands
@@ -1,5 +1,5 @@
1
1
  import { i as SparkOperatorConfig, n as SparkNetwork, o as Signature, r as SparkNetworkConfig } from "./lightning-address-CRULmi9v.mjs";
2
- import { v as SparkSigner } from "./transactions-DjTZU8ev.mjs";
2
+ import { v as SparkSigner } from "./transactions-p89sj_IQ.mjs";
3
3
  import "@bufbuild/protobuf/codegenv2";
4
4
  import "@bufbuild/protobuf/wkt";
5
5
  import { Message, UnknownEnum } from "@bufbuild/protobuf";
@@ -332,6 +332,43 @@ type SparkTransfer = {
332
332
  readonly leaves: ReadonlyArray<SparkTransferLeaf>;
333
333
  };
334
334
  //#endregion
335
+ //#region src/transfer/payment.d.ts
336
+ /**
337
+ * One entry of `client.transfers.history`: a transfer folded with its SSP `user_request` into the
338
+ * wallet-facing payment shape. Mapping follows the Breez adaptor semantics; every field a consumer
339
+ * displays comes from authenticated SO data or the SSP record — never from host input.
340
+ */
341
+ type SparkPayment = {
342
+ readonly id: string;
343
+ readonly direction: "send" | "receive";
344
+ readonly status: "pending" | "completed" | "failed";
345
+ readonly method: "spark" | "lightning" | "deposit" | "withdraw";
346
+ /** Sats excluding fees — the total minus the fee for outbound sends and exits. */
347
+ readonly amountSats: number;
348
+ readonly feeSats: number;
349
+ /** Milliseconds since the epoch; absent when the SO reports none. */
350
+ readonly createdAt: number | undefined;
351
+ readonly details: {
352
+ readonly kind: "spark";
353
+ readonly invoice?: string;
354
+ } | {
355
+ readonly kind: "lightning";
356
+ readonly invoice: string;
357
+ /** Payment hash, hex. */
358
+ readonly paymentHash: string;
359
+ /** Payment preimage, hex. */
360
+ readonly preimage?: string;
361
+ readonly description?: string;
362
+ } | {
363
+ readonly kind: "withdraw";
364
+ readonly txid?: string;
365
+ } | {
366
+ readonly kind: "deposit";
367
+ readonly txid: string;
368
+ readonly vout: number;
369
+ } | undefined;
370
+ };
371
+ //#endregion
335
372
  //#region src/core/bitcoin/cpfp.d.ts
336
373
  type FundingInput = {
337
374
  /** Display-order hex txid of the confirmed funding output. */
@@ -430,6 +467,19 @@ type SparkClient = {
430
467
  readonly limit?: number;
431
468
  readonly offset?: number;
432
469
  }) => Promise<ReadonlyArray<SparkTransfer>>;
470
+ /**
471
+ * Transfer history as wallet-facing payments: TRANSFER, PREIMAGE_SWAP, COOPERATIVE_EXIT and
472
+ * UTXO_SWAP records (newest first) folded with their SSP user requests when the counterparty is
473
+ * the SSP — one batched SSP call per page. `limit` is 1–100 (default 20); `nextOffset` is the
474
+ * offset of the next page, `undefined` at the end.
475
+ */
476
+ readonly history: (options?: {
477
+ readonly limit?: number;
478
+ readonly offset?: number;
479
+ }) => Promise<{
480
+ readonly payments: ReadonlyArray<SparkPayment>;
481
+ readonly nextOffset: number | undefined;
482
+ }>;
433
483
  /**
434
484
  * Sends exactly `amountSats` to `receiver` (a `spark1…`/`sparkrt1…` address string or a 33-byte
435
485
  * identity public key) via `start_transfer_v2` — selecting exact leaves, or swapping with the
@@ -823,4 +873,4 @@ type SparkClientOptions = {
823
873
  */
824
874
  declare function createSparkClient(options: SparkClientOptions): SparkClient;
825
875
  //#endregion
826
- export { CooperativeExitStatus as A, exitTransactions as C, CooperativeExitQuote as D, createMemorySparkStore as E, UnusedDepositAddress as F, SparkLeaf as I, SparkEvent as L, StaticDepositClaim as M, StaticDepositRefund as N, CooperativeExitResult as O, StaticDepositUtxo as P, ExitTransaction as S, SparkStore as T, LightningSendStatus as _, createSparkClient as a, LightningInvoice as b, buildCpfpChild as c, SparkTokenBalance as d, SparkTokenOutput as f, LightningSendOutcome as g, LightningReceiveStatus as h, SparkInvoiceStatus as i, MIN_STATIC_REFUND_FEE_SATS as j, CooperativeExitSpeed as k, SparkTransfer as l, SparkWalletSettings as m, SparkClient as n, StaticDepositClaimResult as o, SparkTokenOutputStatus as p, SparkClientOptions as r, FundingInput as s, ClaimPendingResult as t, SparkTransferLeaf as u, LightningSendStatusRequest as v, SparkExitChain as w, WatchtowerExitedLeaf as x, LightningPayment as y };
876
+ export { CooperativeExitSpeed as A, ExitTransaction as C, createMemorySparkStore as D, SparkStore as E, StaticDepositUtxo as F, UnusedDepositAddress as I, SparkLeaf as L, MIN_STATIC_REFUND_FEE_SATS as M, StaticDepositClaim as N, CooperativeExitQuote as O, StaticDepositRefund as P, SparkEvent as R, WatchtowerExitedLeaf as S, SparkExitChain as T, LightningSendOutcome as _, createSparkClient as a, LightningPayment as b, buildCpfpChild as c, SparkTransferLeaf as d, SparkTokenBalance as f, LightningReceiveStatus as g, SparkWalletSettings as h, SparkInvoiceStatus as i, CooperativeExitStatus as j, CooperativeExitResult as k, SparkPayment as l, SparkTokenOutputStatus as m, SparkClient as n, StaticDepositClaimResult as o, SparkTokenOutput as p, SparkClientOptions as r, FundingInput as s, ClaimPendingResult as t, SparkTransfer as u, LightningSendStatus as v, exitTransactions as w, LightningInvoice as x, LightningSendStatusRequest as y };
package/dist/index.d.mts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { a as SparkTokenBroadcastError, i as SparkRequestError, n as SparkError, r as SparkInputError, t as SparkCryptoError } from "./index-D1fBaHTa.mjs";
2
2
  import { a as sparkNetworkConfig, i as SparkOperatorConfig, n as SparkNetwork, r as SparkNetworkConfig } from "./lightning-address-CRULmi9v.mjs";
3
3
  import { i as isExpired, n as Bolt11Network, r as decodeBolt11, t as Bolt11Invoice } from "./bolt11-DsNTTS_O.mjs";
4
- import { A as CooperativeExitStatus, C as exitTransactions, D as CooperativeExitQuote, E as createMemorySparkStore, F as UnusedDepositAddress, I as SparkLeaf, L as SparkEvent, M as StaticDepositClaim, N as StaticDepositRefund, O as CooperativeExitResult, P as StaticDepositUtxo, S as ExitTransaction, T as SparkStore, _ as LightningSendStatus, a as createSparkClient, b as LightningInvoice, c as buildCpfpChild, d as SparkTokenBalance, f as SparkTokenOutput, g as LightningSendOutcome, h as LightningReceiveStatus, i as SparkInvoiceStatus, j as MIN_STATIC_REFUND_FEE_SATS, k as CooperativeExitSpeed, l as SparkTransfer, m as SparkWalletSettings, n as SparkClient, o as StaticDepositClaimResult, p as SparkTokenOutputStatus, r as SparkClientOptions, s as FundingInput, t as ClaimPendingResult, u as SparkTransferLeaf, v as LightningSendStatusRequest, w as SparkExitChain, x as WatchtowerExitedLeaf, y as LightningPayment } from "./index-rHuqmVV3.mjs";
5
- import { n as EPHEMERAL_ANCHOR_SCRIPT, t as addressToScript, v as SparkSigner } from "./transactions-DjTZU8ev.mjs";
4
+ import { A as CooperativeExitSpeed, C as ExitTransaction, D as createMemorySparkStore, E as SparkStore, F as StaticDepositUtxo, I as UnusedDepositAddress, L as SparkLeaf, M as MIN_STATIC_REFUND_FEE_SATS, N as StaticDepositClaim, O as CooperativeExitQuote, P as StaticDepositRefund, R as SparkEvent, S as WatchtowerExitedLeaf, T as SparkExitChain, _ as LightningSendOutcome, a as createSparkClient, b as LightningPayment, c as buildCpfpChild, d as SparkTransferLeaf, f as SparkTokenBalance, g as LightningReceiveStatus, h as SparkWalletSettings, i as SparkInvoiceStatus, j as CooperativeExitStatus, k as CooperativeExitResult, l as SparkPayment, m as SparkTokenOutputStatus, n as SparkClient, o as StaticDepositClaimResult, p as SparkTokenOutput, r as SparkClientOptions, s as FundingInput, t as ClaimPendingResult, u as SparkTransfer, v as LightningSendStatus, w as exitTransactions, x as LightningInvoice, y as LightningSendStatusRequest } from "./index-CsGON46O.mjs";
5
+ import { n as EPHEMERAL_ANCHOR_SCRIPT, t as bitcoinAddressScript, v as SparkSigner } from "./transactions-p89sj_IQ.mjs";
6
6
  //#region src/core/invoice.d.ts
7
7
  /** Payment carried by a Spark invoice: satoshis or BTKN tokens. */
8
- type SparkPayment = {
8
+ type SparkInvoicePayment = {
9
9
  readonly type: "sats";
10
10
  readonly amount?: number | undefined;
11
11
  } | {
@@ -20,7 +20,7 @@ type SparkInvoiceFields = {
20
20
  readonly version: number;
21
21
  /** UUID identifying the invoice (canonical lowercase form). */
22
22
  readonly id: string;
23
- readonly payment?: SparkPayment | undefined;
23
+ readonly payment?: SparkInvoicePayment | undefined;
24
24
  /** At most 120 UTF-8 bytes. */
25
25
  readonly memo?: string | undefined;
26
26
  /** 33-byte compressed secp256k1 public key. */
@@ -120,4 +120,4 @@ export declare function parseSparkInvoice(text: string, options: {
120
120
  readonly now: number;
121
121
  }): ParsedSparkInvoice;
122
122
  //#endregion
123
- export { type Bolt11Invoice, type Bolt11Network, type ClaimPendingResult, type CooperativeExitQuote, type CooperativeExitResult, type CooperativeExitSpeed, type CooperativeExitStatus, EPHEMERAL_ANCHOR_SCRIPT, type ExitTransaction, type FundingInput, type LightningInvoice, type LightningPayment, type LightningReceiveStatus, type LightningSendOutcome, type LightningSendStatus, type LightningSendStatusRequest, MIN_STATIC_REFUND_FEE_SATS, type ParsedSparkInvoice, type SparkAddress, type SparkClient, type SparkClientOptions, SparkCryptoError, SparkError, type SparkEvent, type SparkExitChain, SparkInputError, type SparkInvoiceFields, type SparkInvoiceStatus, type SparkLeaf, type SparkNetwork, type SparkNetworkConfig, type SparkOperatorConfig, type SparkPayment, SparkRequestError, type SparkStore, type SparkTokenBalance, SparkTokenBroadcastError, type SparkTokenIdentifierData, type SparkTokenOutput, type SparkTokenOutputStatus, type SparkTransfer, type SparkTransferLeaf, type SparkWalletSettings, type StaticDepositClaim, type StaticDepositClaimResult, type StaticDepositRefund, type StaticDepositUtxo, type UnusedDepositAddress, type WatchtowerExitedLeaf, addressToScript, buildCpfpChild, createMemorySparkStore, createSparkClient, decodeBolt11, exitTransactions, isExpired, sparkNetworkConfig };
123
+ export { type Bolt11Invoice, type Bolt11Network, type ClaimPendingResult, type CooperativeExitQuote, type CooperativeExitResult, type CooperativeExitSpeed, type CooperativeExitStatus, EPHEMERAL_ANCHOR_SCRIPT, type ExitTransaction, type FundingInput, type LightningInvoice, type LightningPayment, type LightningReceiveStatus, type LightningSendOutcome, type LightningSendStatus, type LightningSendStatusRequest, MIN_STATIC_REFUND_FEE_SATS, type ParsedSparkInvoice, type SparkAddress, type SparkClient, type SparkClientOptions, SparkCryptoError, SparkError, type SparkEvent, type SparkExitChain, SparkInputError, type SparkInvoiceFields, type SparkInvoicePayment, type SparkInvoiceStatus, type SparkLeaf, type SparkNetwork, type SparkNetworkConfig, type SparkOperatorConfig, type SparkPayment, SparkRequestError, type SparkStore, type SparkTokenBalance, SparkTokenBroadcastError, type SparkTokenIdentifierData, type SparkTokenOutput, type SparkTokenOutputStatus, type SparkTransfer, type SparkTransferLeaf, type SparkWalletSettings, type StaticDepositClaim, type StaticDepositClaimResult, type StaticDepositRefund, type StaticDepositUtxo, type UnusedDepositAddress, type WatchtowerExitedLeaf, bitcoinAddressScript, buildCpfpChild, createMemorySparkStore, createSparkClient, decodeBolt11, exitTransactions, isExpired, sparkNetworkConfig };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as SparkTokenBroadcastError, i as SparkRequestError, n as SparkError, r as SparkInputError, t as SparkCryptoError } from "./errors-5xLkExNL.mjs";
2
- import { $ as SparkAuthnService, A as EPHEMERAL_ANCHOR_SCRIPT, B as parseTransaction, Bt as TransferReceiverStatus, C as createInitialTimelockRefundTxs, Ct as InitiatePreimageSwapRequest_Reason, D as txId, Dt as RenewNodeTimelockSigningJobSchema, E as estimateVbytes, Et as Order, Ft as SparkAddressSchema, G as PartialTokenOutputSchema, Gt as SignatureScheme, Ht as TransferType, I as doesTxnNeedRenewed, It as SparkInvoiceFieldsSchema, J as SparkTokenService, K as PartialTokenTransactionSchema, L as getNextHTLCTransactionSequence, Lt as SparkService, M as computeTaprootKeyNoScript, N as p2trScriptFromPublicKey, Nt as SenderTransferPackageSchema, O as txIdInputBytes, Ot as RenewNodeZeroTimelockSigningJobSchema, P as xOnlyPublicKey, Pt as SigningJobSchema, Q as ChallengeSchema, R as getTimelockFromSequence, Rt as StartTransferRequestSchema, S as createInitialTimelockNodeTx, St as HashVariant, T as createZeroTimelockNodeTx, Tt as InvoiceStatus, U as CommitStatus, Ut as TreeNodeStatus, V as taprootKeySpendSighash, Vt as TransferStatus, W as InvoiceAttachmentSchema, Wt as UserSignedTxSigningJobSchema, X as TokenTransactionMetadataSchema, Y as TokenOutputStatus, Z as TokenTransactionStatus, _ as addressToScript, _t as AdaptorPublicKeyPackageSchema, a as proofOfPossessionDigest, at as uuidToBytes, b as createDecrementedTimelockNodeTx, bt as ClaimPackageSchema, d as LIGHTNING_HTLC_SEQUENCE, dt as assertU32, et as hashSparkInvoice, f as constructHtlcSenderSpend, ft as requireLength, g as lightningHtlcOutputScript, gt as sparkNetworkProto, h as finalizeHtlcSpend, ht as sparkNetworkFromProto, it as uuidFromBytes, j as btcNetwork, k as verifyFinalizedTaprootSignature, kt as RenewRefundTimelockSigningJobSchema, lt as assertCompressedKey, mt as sparkNetworkConfig, nt as protoInvoiceToPlain, o as sendLeafSigningDigest, ot as uuidv7, p as createRefundTxsForLightning, pt as u64ToSats, q as SignatureWithIndexSchema, rt as validateInvoiceFields, st as compareBytes, t as hashFinalTokenTransaction, tt as encodeInvoiceFields, ut as assertSats, v as createConnectorRefundTxs, w as createMultiInputRootTx, wt as InputSigningDataSchema, x as createDecrementedTimelockRefundTxs, xt as Direction, y as createCurrentTimelockRefundTxs, z as isZeroTimelock, zt as TransferPackageSchema } from "./token-DmojVTWi.mjs";
2
+ import { $ as SparkAuthnService, A as EPHEMERAL_ANCHOR_SCRIPT, B as parseTransaction, Bt as TransferReceiverStatus, C as createInitialTimelockRefundTxs, Ct as InitiatePreimageSwapRequest_Reason, D as txId, Dt as RenewNodeTimelockSigningJobSchema, E as estimateVbytes, Et as Order, Ft as SparkAddressSchema, G as PartialTokenOutputSchema, Gt as SignatureScheme, Ht as TransferType, I as doesTxnNeedRenewed, It as SparkInvoiceFieldsSchema, J as SparkTokenService, K as PartialTokenTransactionSchema, L as getNextHTLCTransactionSequence, Lt as SparkService, M as computeTaprootKeyNoScript, N as p2trScriptFromPublicKey, Nt as SenderTransferPackageSchema, O as txIdInputBytes, Ot as RenewNodeZeroTimelockSigningJobSchema, P as xOnlyPublicKey, Pt as SigningJobSchema, Q as ChallengeSchema, R as getTimelockFromSequence, Rt as StartTransferRequestSchema, S as createInitialTimelockNodeTx, St as HashVariant, T as createZeroTimelockNodeTx, Tt as InvoiceStatus, U as CommitStatus, Ut as TreeNodeStatus, V as taprootKeySpendSighash, Vt as TransferStatus, W as InvoiceAttachmentSchema, Wt as UserSignedTxSigningJobSchema, X as TokenTransactionMetadataSchema, Y as TokenOutputStatus, Z as TokenTransactionStatus, _ as bitcoinAddressScript, _t as AdaptorPublicKeyPackageSchema, a as proofOfPossessionDigest, at as uuidToBytes, b as createDecrementedTimelockNodeTx, bt as ClaimPackageSchema, d as LIGHTNING_HTLC_SEQUENCE, dt as assertU32, et as hashSparkInvoice, f as constructHtlcSenderSpend, ft as requireLength, g as lightningHtlcOutputScript, gt as sparkNetworkProto, h as finalizeHtlcSpend, ht as sparkNetworkFromProto, it as uuidFromBytes, j as btcNetwork, k as verifyFinalizedTaprootSignature, kt as RenewRefundTimelockSigningJobSchema, lt as assertCompressedKey, mt as sparkNetworkConfig, nt as protoInvoiceToPlain, o as sendLeafSigningDigest, ot as uuidv7, p as createRefundTxsForLightning, pt as u64ToSats, q as SignatureWithIndexSchema, rt as validateInvoiceFields, st as compareBytes, t as hashFinalTokenTransaction, tt as encodeInvoiceFields, ut as assertSats, v as createConnectorRefundTxs, w as createMultiInputRootTx, wt as InputSigningDataSchema, x as createDecrementedTimelockRefundTxs, xt as Direction, y as createCurrentTimelockRefundTxs, z as isZeroTimelock, zt as TransferPackageSchema } from "./token-C3vqRH-k.mjs";
3
3
  import { n as isExpired, t as decodeBolt11 } from "./bolt11-rfxnyLcb.mjs";
4
4
  import { t as serverErrorText } from "./text-CDhN7qo4.mjs";
5
5
  import { bytesToHex, hexToBytes, utf8ToBytes } from "@noble/hashes/utils.js";
@@ -11,7 +11,7 @@ import { base64, bech32m } from "@scure/base";
11
11
  import { sha256 } from "@noble/hashes/sha2.js";
12
12
  import { Code, ConnectError, createClient } from "@connectrpc/connect";
13
13
  import { createGrpcWebTransport } from "@connectrpc/connect-web";
14
- import { bytesToNumberBE, equalBytes, hexToBytes as hexToBytes$1, numberToBytesBE, numberToVarBytesBE } from "@noble/curves/utils.js";
14
+ import { bytesToHex as bytesToHex$1, bytesToNumberBE, equalBytes, hexToBytes as hexToBytes$1, numberToBytesBE, numberToVarBytesBE } from "@noble/curves/utils.js";
15
15
  import { Address, OutScript, Transaction } from "@scure/btc-signer";
16
16
  //#region src/core/address.ts
17
17
  const BECH32M_LIMIT$1 = 1024;
@@ -1229,6 +1229,94 @@ fragment UserRequestFragment on UserRequest {
1229
1229
  lightning_send_request_payment_preimage: payment_preimage
1230
1230
  }
1231
1231
  }`;
1232
+ const TRANSFERS = `
1233
+ query Transfers($transfer_spark_ids: [UUID!]!) {
1234
+ transfers(transfer_spark_ids: $transfer_spark_ids) {
1235
+ ...TransferFragment
1236
+ transfer_user_request: user_request {
1237
+ ...UserRequestFragment
1238
+ }
1239
+ }
1240
+ }
1241
+
1242
+ fragment TransferFragment on Transfer {
1243
+ __typename
1244
+ transfer_spark_id: spark_id
1245
+ }
1246
+
1247
+ fragment CurrencyAmountFragment on CurrencyAmount {
1248
+ __typename
1249
+ currency_amount_original_value: original_value
1250
+ currency_amount_original_unit: original_unit
1251
+ }
1252
+
1253
+ fragment TransferSparkIdFragment on Transfer {
1254
+ __typename
1255
+ transfer_spark_id: spark_id
1256
+ }
1257
+
1258
+ fragment UserRequestFragment on UserRequest {
1259
+ __typename
1260
+ ... on ClaimStaticDeposit {
1261
+ claim_static_deposit_id: id
1262
+ claim_static_deposit_deposit_amount: deposit_amount {
1263
+ ...CurrencyAmountFragment
1264
+ }
1265
+ claim_static_deposit_credit_amount: credit_amount {
1266
+ ...CurrencyAmountFragment
1267
+ }
1268
+ claim_static_deposit_max_fee: max_fee {
1269
+ ...CurrencyAmountFragment
1270
+ }
1271
+ claim_static_deposit_status: status
1272
+ claim_static_deposit_transaction_id: transaction_id
1273
+ claim_static_deposit_output_index: output_index
1274
+ claim_static_deposit_transfer_spark_id: transfer_spark_id
1275
+ }
1276
+ ... on CoopExitRequest {
1277
+ coop_exit_request_id: id
1278
+ coop_exit_request_fee: fee {
1279
+ ...CurrencyAmountFragment
1280
+ }
1281
+ coop_exit_request_l1_broadcast_fee: l1_broadcast_fee {
1282
+ ...CurrencyAmountFragment
1283
+ }
1284
+ coop_exit_request_status: status
1285
+ coop_exit_request_coop_exit_txid: coop_exit_txid
1286
+ coop_exit_request_transfer: transfer {
1287
+ ...TransferSparkIdFragment
1288
+ }
1289
+ }
1290
+ ... on LeavesSwapRequest {
1291
+ leaves_swap_request_id: id
1292
+ leaves_swap_request_status: status
1293
+ }
1294
+ ... on LightningReceiveRequest {
1295
+ lightning_receive_request_id: id
1296
+ lightning_receive_request_invoice: invoice {
1297
+ __typename
1298
+ invoice_encoded_invoice: encoded_invoice
1299
+ invoice_payment_hash: payment_hash
1300
+ }
1301
+ lightning_receive_request_status: status
1302
+ lightning_receive_request_transfer: transfer {
1303
+ ...TransferSparkIdFragment
1304
+ }
1305
+ lightning_receive_request_payment_preimage: payment_preimage
1306
+ }
1307
+ ... on LightningSendRequest {
1308
+ lightning_send_request_id: id
1309
+ lightning_send_request_encoded_invoice: encoded_invoice
1310
+ lightning_send_request_fee: fee {
1311
+ ...CurrencyAmountFragment
1312
+ }
1313
+ lightning_send_request_status: status
1314
+ lightning_send_request_transfer: transfer {
1315
+ ...TransferSparkIdFragment
1316
+ }
1317
+ lightning_send_request_payment_preimage: payment_preimage
1318
+ }
1319
+ }`;
1232
1320
  //#endregion
1233
1321
  //#region src/ssp/parse.ts
1234
1322
  /** A malformed SSP response is a server fault, not caller input. */
@@ -1251,6 +1339,11 @@ function asSats(value, field) {
1251
1339
  if (n === void 0 || !Number.isSafeInteger(n) || n < 0) throw unexpectedResponse(field, "is not a non-negative integer");
1252
1340
  return n;
1253
1341
  }
1342
+ /** A GraphQL Int field used as an array/output index — a number, not a decimal string. */
1343
+ function asIndex(value, field) {
1344
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw unexpectedResponse(field, "is not a non-negative integer");
1345
+ return value;
1346
+ }
1254
1347
  /** CurrencyAmount in SATOSHI → sats; any other unit is an unexpected response. */
1255
1348
  function currencyAmountSats(value, field) {
1256
1349
  const amount = asObject(value, field);
@@ -1371,6 +1464,75 @@ function parseCoopExitResult(request, field) {
1371
1464
  rawConnectorTransaction: asHexBytes(request["coop_exit_request_raw_connector_transaction"], `${field}.coop_exit_request_raw_connector_transaction`)
1372
1465
  };
1373
1466
  }
1467
+ function optionalTxidHex(value, field) {
1468
+ if (value === void 0 || value === null) return;
1469
+ return asTxidHex(value, field);
1470
+ }
1471
+ /** The `transfers` query's per-item parse: id plus its user_request union member (or none). */
1472
+ function parseTransfersResponse(data) {
1473
+ const items = data["transfers"];
1474
+ if (!Array.isArray(items)) throw unexpectedResponse("transfers", "is not an array");
1475
+ return items.map((item, index) => {
1476
+ const field = `transfers[${index}]`;
1477
+ const entry = asObject(item, field);
1478
+ const request = entry["transfer_user_request"];
1479
+ return {
1480
+ transferId: asString(entry["transfer_spark_id"], `${field}.transfer_spark_id`),
1481
+ request: request === void 0 || request === null ? void 0 : parseUserRequest(asObject(request, `${field}.transfer_user_request`), `${field}.transfer_user_request`)
1482
+ };
1483
+ });
1484
+ }
1485
+ /**
1486
+ * Discriminated `user_request` parse. An unknown `__typename` is a variant we do not model, not a
1487
+ * malformed response.
1488
+ */
1489
+ function parseUserRequest(request, field) {
1490
+ switch (request["__typename"]) {
1491
+ case "LightningSendRequest": {
1492
+ const send = parseLightningSend(request, field);
1493
+ return {
1494
+ kind: "lightning-send",
1495
+ status: send.status,
1496
+ invoice: send.encodedInvoice,
1497
+ feeSats: send.feeSats,
1498
+ ...send.paymentPreimage === void 0 ? {} : { preimage: send.paymentPreimage }
1499
+ };
1500
+ }
1501
+ case "LightningReceiveRequest": {
1502
+ const receive = parseLightningReceive(request, field);
1503
+ return {
1504
+ kind: "lightning-receive",
1505
+ status: receive.status,
1506
+ invoice: receive.invoice,
1507
+ ...receive.paymentPreimage === void 0 ? {} : { preimage: receive.paymentPreimage }
1508
+ };
1509
+ }
1510
+ case "CoopExitRequest": return parseCoopExitRequest(request, field);
1511
+ case "ClaimStaticDeposit": return parseStaticDepositRequest(request, field);
1512
+ case "LeavesSwapRequest": return { kind: "leaves-swap" };
1513
+ default: return;
1514
+ }
1515
+ }
1516
+ /** `coop_exit` for history: fee = `fee` + `l1_broadcast_fee`, status and payout txid. */
1517
+ function parseCoopExitRequest(request, field) {
1518
+ const txid = optionalTxidHex(request["coop_exit_request_coop_exit_txid"], `${field}.coop_exit_request_coop_exit_txid`);
1519
+ return {
1520
+ kind: "coop-exit",
1521
+ status: asString(request["coop_exit_request_status"], `${field}.coop_exit_request_status`),
1522
+ feeSats: currencyAmountSats(request["coop_exit_request_fee"], `${field}.coop_exit_request_fee`) + currencyAmountSats(request["coop_exit_request_l1_broadcast_fee"], `${field}.coop_exit_request_l1_broadcast_fee`),
1523
+ ...txid === void 0 ? {} : { txid }
1524
+ };
1525
+ }
1526
+ /** `claim_static_deposit` for history: the claim's txid, vout and credited amount. */
1527
+ function parseStaticDepositRequest(request, field) {
1528
+ return {
1529
+ kind: "static-deposit",
1530
+ txid: asTxidHex(request["claim_static_deposit_transaction_id"], `${field}.claim_static_deposit_transaction_id`),
1531
+ vout: asIndex(request["claim_static_deposit_output_index"], `${field}.claim_static_deposit_output_index`),
1532
+ depositAmountSats: currencyAmountSats(request["claim_static_deposit_deposit_amount"], `${field}.claim_static_deposit_deposit_amount`),
1533
+ creditAmountSats: currencyAmountSats(request["claim_static_deposit_credit_amount"], `${field}.claim_static_deposit_credit_amount`)
1534
+ };
1535
+ }
1374
1536
  //#endregion
1375
1537
  //#region src/ssp/index.ts
1376
1538
  /**
@@ -1501,6 +1663,11 @@ function createSspClient(options) {
1501
1663
  }
1502
1664
  }
1503
1665
  return {
1666
+ async transfers(transferIds) {
1667
+ if (transferIds.length === 0) return [];
1668
+ if (transferIds.length > 100) throw new SparkInputError("transfers: at most 100 ids per call");
1669
+ return parseTransfersResponse(asObject(await readPost("Transfers", TRANSFERS, { transfer_spark_ids: [...transferIds] }), "transfers"));
1670
+ },
1504
1671
  async swapFeeEstimate(amountSats) {
1505
1672
  if (!Number.isSafeInteger(amountSats) || amountSats <= 0) throw new SparkInputError("amount sats must be a positive integer");
1506
1673
  return currencyAmountSats(asObject((await readPost("LeavesSwapFeeEstimate", LEAVES_SWAP_FEE_ESTIMATE, { total_amount_sats: amountSats }))["leaves_swap_fee_estimate"], "leaves_swap_fee_estimate")["leaves_swap_fee_estimate_output_fee_estimate"], "leaves_swap_fee_estimate_output_fee_estimate");
@@ -2209,7 +2376,7 @@ function validateCoopExitPayoutTransaction(params) {
2209
2376
  }
2210
2377
  function p2trAddressScript(address, network) {
2211
2378
  try {
2212
- return OutScript.encode(Address(btcNetwork(network)).decode(address));
2379
+ return bitcoinAddressScript(address, network);
2213
2380
  } catch (error) {
2214
2381
  throw new SparkInputError("expectedPayoutAddress: could not decode the withdrawal address", { cause: error });
2215
2382
  }
@@ -3025,7 +3192,7 @@ function depositScript(verifyingKey, network) {
3025
3192
  /** Output script of a coordinator-supplied address, decoded under our network only. */
3026
3193
  function depositAddressScript(address, network) {
3027
3194
  try {
3028
- return OutScript.encode(Address(btcNetwork(network)).decode(address));
3195
+ return bitcoinAddressScript(address, network);
3029
3196
  } catch (error) {
3030
3197
  throw new SparkError("deposit: address does not decode under our network", { cause: error });
3031
3198
  }
@@ -3706,17 +3873,27 @@ async function queryTransfersByIds(options) {
3706
3873
  network: sparkNetworkProto(options.network)
3707
3874
  }, options.call)).transfers;
3708
3875
  }
3709
- /** `query_all_transfers` — transfers where the identity is sender or receiver. */
3876
+ /**
3877
+ * `query_all_transfers` — transfers where the identity is sender or receiver. `types` filters on
3878
+ * the server side (empty means all). `nextOffset` is the offset of the following page — `undefined`
3879
+ * when the SO reports `-1` (a short page ends the listing).
3880
+ */
3710
3881
  async function queryAllTransfers(options) {
3711
- return (await options.spark.query_all_transfers({
3882
+ const response = await options.spark.query_all_transfers({
3712
3883
  participant: {
3713
3884
  case: "senderOrReceiverIdentityPublicKey",
3714
3885
  value: options.identityPublicKey
3715
3886
  },
3716
3887
  network: sparkNetworkProto(options.network),
3717
3888
  limit: BigInt(options.limit ?? 100),
3718
- offset: BigInt(options.offset ?? 0)
3719
- }, options.call)).transfers.map(mapTransfer);
3889
+ offset: BigInt(options.offset ?? 0),
3890
+ types: [...options.types ?? []]
3891
+ }, options.call);
3892
+ const nextOffset = Number(response.offset);
3893
+ return {
3894
+ transfers: response.transfers.map(mapTransfer),
3895
+ nextOffset: nextOffset < 0 ? void 0 : nextOffset
3896
+ };
3720
3897
  }
3721
3898
  /**
3722
3899
  * Whether `transfer` is exactly the one we signed for: our id, same type, our sender key, and the
@@ -4262,6 +4439,111 @@ async function claimByTransferId(options) {
4262
4439
  }
4263
4440
  }
4264
4441
  //#endregion
4442
+ //#region src/transfer/payment.ts
4443
+ /**
4444
+ * CoopExitRequest statuses, bucketed per Breez's `SparkCoopExitRequestStatus::acceptance`: accepted
4445
+ * means the SSP took the exit over — the SO-side transfer status keeps telling completion; terminal
4446
+ * failures are failed; anything else (incl. unknown values) is pending.
4447
+ */
4448
+ const COOP_EXIT_ACCEPTED$1 = /* @__PURE__ */ new Set([
4449
+ "INBOUND_TRANSFER_CHECKED",
4450
+ "TX_SIGNED",
4451
+ "TX_BROADCASTED",
4452
+ "WAITING_ON_TX_CONFIRMATIONS",
4453
+ "COMPLETE_REQUEST_RECEIVED",
4454
+ "ON_CHAIN_TX_CONFIRMED",
4455
+ "SUCCEEDED"
4456
+ ]);
4457
+ const COOP_EXIT_FAILED$1 = /* @__PURE__ */ new Set([
4458
+ "EXPIRED",
4459
+ "FAILED",
4460
+ "INBOUND_TRANSFER_CLAIMING_FAILED",
4461
+ "EXPIRING_FAILED",
4462
+ "FAILING_FAILED"
4463
+ ]);
4464
+ /**
4465
+ * Whether the transfer's counterparty is the SSP: the receiver on sends (any edge of a
4466
+ * multi-receiver), the sender on receives. Shared by the history batch-fetch and the mapper.
4467
+ */
4468
+ function sspCounterparty(transfer, identityPublicKey, sspIdentityPublicKey) {
4469
+ return equalBytes(transfer.senderIdentityPublicKey, identityPublicKey) ? equalBytes(transfer.receiverIdentityPublicKey, sspIdentityPublicKey) || transfer.receivers.some((receiver) => equalBytes(receiver.identityPublicKey, sspIdentityPublicKey)) : equalBytes(transfer.senderIdentityPublicKey, sspIdentityPublicKey);
4470
+ }
4471
+ function toSparkPayment(options) {
4472
+ const { transfer, request } = options;
4473
+ const direction = equalBytes(transfer.senderIdentityPublicKey, options.identityPublicKey) ? "send" : "receive";
4474
+ const isSsp = sspCounterparty(transfer, options.identityPublicKey, options.sspIdentityPublicKey);
4475
+ const method = transfer.type === "COOPERATIVE_EXIT" ? "withdraw" : transfer.type === "UTXO_SWAP" ? "deposit" : transfer.type === "PREIMAGE_SWAP" ? isSsp ? "lightning" : "spark" : "spark";
4476
+ let status;
4477
+ if (transfer.status === "COMPLETED") status = "completed";
4478
+ else if (direction === "send" && transfer.status === "SENDER_KEY_TWEAKED") status = "completed";
4479
+ else if (transfer.status === "EXPIRED" || transfer.status === "RETURNED") status = "failed";
4480
+ else status = "pending";
4481
+ let feeSats = 0;
4482
+ let amountSats = transfer.totalValueSats;
4483
+ let details;
4484
+ switch (method) {
4485
+ case "lightning":
4486
+ if (request?.kind === "lightning-send") {
4487
+ if (request.preimage !== void 0) status = "completed";
4488
+ ({feeSats} = request);
4489
+ amountSats = Math.max(0, transfer.totalValueSats - feeSats);
4490
+ details = lightningDetails(request.invoice, request.preimage);
4491
+ } else if (request?.kind === "lightning-receive") details = lightningDetails(request.invoice, request.preimage);
4492
+ break;
4493
+ case "withdraw":
4494
+ if (request?.kind === "coop-exit") {
4495
+ ({feeSats} = request);
4496
+ amountSats = Math.max(0, transfer.totalValueSats - feeSats);
4497
+ if (COOP_EXIT_FAILED$1.has(request.status)) status = "failed";
4498
+ else if (!COOP_EXIT_ACCEPTED$1.has(request.status)) status = "pending";
4499
+ details = {
4500
+ kind: "withdraw",
4501
+ ...request.txid === void 0 ? {} : { txid: request.txid }
4502
+ };
4503
+ }
4504
+ break;
4505
+ case "deposit":
4506
+ if (request?.kind === "static-deposit") {
4507
+ feeSats = Math.max(0, request.depositAmountSats - request.creditAmountSats);
4508
+ details = {
4509
+ kind: "deposit",
4510
+ txid: request.txid,
4511
+ vout: request.vout
4512
+ };
4513
+ }
4514
+ break;
4515
+ case "spark": details = {
4516
+ kind: "spark",
4517
+ ...transfer.sparkInvoice === void 0 ? {} : { invoice: transfer.sparkInvoice }
4518
+ };
4519
+ }
4520
+ if (method !== "spark" && details === void 0) status = "pending";
4521
+ return {
4522
+ id: transfer.id,
4523
+ direction,
4524
+ status,
4525
+ method,
4526
+ amountSats,
4527
+ feeSats,
4528
+ createdAt: transfer.createdTimeMs,
4529
+ details
4530
+ };
4531
+ }
4532
+ function lightningDetails(invoice, preimage) {
4533
+ try {
4534
+ const decoded = decodeBolt11(invoice);
4535
+ return {
4536
+ kind: "lightning",
4537
+ invoice,
4538
+ paymentHash: bytesToHex$1(decoded.paymentHash),
4539
+ ...decoded.description === void 0 ? {} : { description: decoded.description },
4540
+ ...preimage === void 0 ? {} : { preimage: bytesToHex$1(preimage) }
4541
+ };
4542
+ } catch {
4543
+ return;
4544
+ }
4545
+ }
4546
+ //#endregion
4265
4547
  //#region src/transfer/send.ts
4266
4548
  /**
4267
4549
  * The signed `TransferPackage` for a send-style transfer: every leaf gets a fresh recipient key
@@ -5892,13 +6174,49 @@ function createTransfers(context) {
5892
6174
  network
5893
6175
  })).transfers;
5894
6176
  },
5895
- list: async (listOptions) => queryAllTransfers({
5896
- spark,
5897
- identityPublicKey: await signer.identityPublicKey(),
5898
- network,
5899
- ...listOptions?.limit === void 0 ? {} : { limit: listOptions.limit },
5900
- ...listOptions?.offset === void 0 ? {} : { offset: listOptions.offset }
5901
- }),
6177
+ history: async (historyOptions) => {
6178
+ const limit = historyOptions?.limit ?? 20;
6179
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100) throw new SparkInputError("history: limit must be an integer in 1–100");
6180
+ const offset = historyOptions?.offset ?? 0;
6181
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new SparkInputError("history: offset must be a non-negative integer");
6182
+ const identityPublicKey = await signer.identityPublicKey();
6183
+ const sspIdentityPublicKey = context.config.ssp.identityPublicKey;
6184
+ const { transfers, nextOffset } = await queryAllTransfers({
6185
+ spark,
6186
+ identityPublicKey,
6187
+ network,
6188
+ limit,
6189
+ offset,
6190
+ types: [
6191
+ TransferType.TRANSFER,
6192
+ TransferType.PREIMAGE_SWAP,
6193
+ TransferType.COOPERATIVE_EXIT,
6194
+ TransferType.UTXO_SWAP
6195
+ ]
6196
+ });
6197
+ const sspIds = transfers.filter((transfer) => sspCounterparty(transfer, identityPublicKey, sspIdentityPublicKey)).map((transfer) => transfer.id);
6198
+ const requests = /* @__PURE__ */ new Map();
6199
+ for (const result of await context.sspClient.transfers(sspIds)) if (result.request !== void 0) requests.set(result.transferId, result.request);
6200
+ return {
6201
+ payments: transfers.map((transfer) => toSparkPayment({
6202
+ transfer,
6203
+ request: requests.get(transfer.id),
6204
+ identityPublicKey,
6205
+ sspIdentityPublicKey
6206
+ })),
6207
+ nextOffset
6208
+ };
6209
+ },
6210
+ list: async (listOptions) => {
6211
+ const { transfers } = await queryAllTransfers({
6212
+ spark,
6213
+ identityPublicKey: await signer.identityPublicKey(),
6214
+ network,
6215
+ ...listOptions?.limit === void 0 ? {} : { limit: listOptions.limit },
6216
+ ...listOptions?.offset === void 0 ? {} : { offset: listOptions.offset }
6217
+ });
6218
+ return transfers;
6219
+ },
5902
6220
  send: async (sendOptions) => sendSats(context, {
5903
6221
  receivers: [{
5904
6222
  receiverIdentityPublicKey: context.receiverIdentityKey(sendOptions.receiver),
@@ -6348,7 +6666,7 @@ async function payLightningInvoice(deps, options) {
6348
6666
  */
6349
6667
  async function sweepHtlcTimeout(deps, options) {
6350
6668
  if (!Number.isFinite(options.feeRateSatPerVbyte) || options.feeRateSatPerVbyte <= 0) throw new SparkInputError("feeRateSatPerVbyte: must be a positive finite number");
6351
- const destinationScript = addressToScript(options.destinationAddress);
6669
+ const destinationScript = bitcoinAddressScript(options.destinationAddress, deps.network);
6352
6670
  const htlc = parseTransaction(options.htlcTx);
6353
6671
  if (!Number.isSafeInteger(options.vout) || options.vout < 0 || options.vout >= htlc.outputsLength) throw new SparkInputError("vout: out of range for the HTLC transaction's outputs");
6354
6672
  const output = htlc.getOutput(options.vout);
@@ -6459,7 +6777,8 @@ function createLightning(context) {
6459
6777
  receiveStatus: async (request) => lightningReceiveStatus(context.sspClient, request),
6460
6778
  sweepHtlcTimeout: async (options) => sweepHtlcTimeout({
6461
6779
  signer: context.signer,
6462
- sspIdentityPublicKey: context.config.ssp.identityPublicKey
6780
+ sspIdentityPublicKey: context.config.ssp.identityPublicKey,
6781
+ network: context.network
6463
6782
  }, options)
6464
6783
  };
6465
6784
  }
@@ -6628,7 +6947,7 @@ const COMPLETE_RETRY_DELAY_MS = 2e3;
6628
6947
  /** `address` must decode under this client's network before any signer or SSP work runs. */
6629
6948
  function checkWithdrawalAddress(address, network) {
6630
6949
  try {
6631
- Address(btcNetwork(network)).decode(address);
6950
+ bitcoinAddressScript(address, network);
6632
6951
  } catch (error) {
6633
6952
  throw new SparkInputError(`coop exit: invalid withdrawal address for ${network}`, { cause: error });
6634
6953
  }
@@ -6647,7 +6966,7 @@ function prevout0(txBytes, context) {
6647
6966
  }
6648
6967
  /** The sats `rawCoopExitTransaction` pays to `address` — an exit not paying it is an error. */
6649
6968
  function payoutSatsForAddress(rawCoopExitTransaction, address, network) {
6650
- const expectedScript = OutScript.encode(Address(btcNetwork(network)).decode(address));
6969
+ const expectedScript = bitcoinAddressScript(address, network);
6651
6970
  const tx = parseTransaction(rawCoopExitTransaction);
6652
6971
  for (let i = 0; i < tx.outputsLength; i++) {
6653
6972
  const output = tx.getOutput(i);
@@ -7405,4 +7724,4 @@ function createMemorySparkStore() {
7405
7724
  };
7406
7725
  }
7407
7726
  //#endregion
7408
- export { EPHEMERAL_ANCHOR_SCRIPT, MIN_STATIC_REFUND_FEE_SATS, SparkCryptoError, SparkError, SparkInputError, SparkRequestError, SparkTokenBroadcastError, addressToScript, buildCpfpChild, createMemorySparkStore, createSatsInvoice, createSparkClient, createTokensInvoice, decodeBolt11, decodeSparkAddress, decodeTokenIdentifier, encodeSparkAddress, encodeTokenIdentifier, exitTransactions, isExpired, parseSparkInvoice, sparkNetworkConfig, uuidv7, verifySparkAddressSignature };
7727
+ export { EPHEMERAL_ANCHOR_SCRIPT, MIN_STATIC_REFUND_FEE_SATS, SparkCryptoError, SparkError, SparkInputError, SparkRequestError, SparkTokenBroadcastError, bitcoinAddressScript, buildCpfpChild, createMemorySparkStore, createSatsInvoice, createSparkClient, createTokensInvoice, decodeBolt11, decodeSparkAddress, decodeTokenIdentifier, encodeSparkAddress, encodeTokenIdentifier, exitTransactions, isExpired, parseSparkInvoice, sparkNetworkConfig, uuidv7, verifySparkAddressSignature };
package/dist/server.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as SparkClient } from "./index-rHuqmVV3.mjs";
1
+ import { n as SparkClient } from "./index-CsGON46O.mjs";
2
2
  //#region src/server/store.d.ts
3
3
  type LightningAddressUser = {
4
4
  /** Lowercase LUD-16 local-part. */
package/dist/signer.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as SparkCrypto } from "./index-DUSx3L3J.mjs";
2
2
  import { a as sparkNetworkConfig, n as SparkNetwork } from "./lightning-address-CRULmi9v.mjs";
3
3
  import { r as decodeBolt11 } from "./bolt11-DsNTTS_O.mjs";
4
- import { _ as SparkOperator, a as HtlcTimeoutSignRequest, b as SigningTarget, c as PrepareClaimRequest, d as PreparedLightningReceive, f as PreparedTransfer, g as SparkLeafKey, h as SparkKey, i as FrostSignJob, l as PrepareTransferRequest, m as SigningCommitment, n as EPHEMERAL_ANCHOR_SCRIPT, o as IdentityStatement, p as PreparedTransferLeaf, r as FrostAggregateJob, s as OperatorCommitment, t as addressToScript, u as PreparedClaim, v as SparkSigner, y as StaticDepositClaimRequest } from "./transactions-DjTZU8ev.mjs";
4
+ import { _ as SparkOperator, a as HtlcTimeoutSignRequest, b as SigningTarget, c as PrepareClaimRequest, d as PreparedLightningReceive, f as PreparedTransfer, g as SparkLeafKey, h as SparkKey, i as FrostSignJob, l as PrepareTransferRequest, m as SigningCommitment, n as EPHEMERAL_ANCHOR_SCRIPT, o as IdentityStatement, p as PreparedTransferLeaf, r as FrostAggregateJob, s as OperatorCommitment, t as bitcoinAddressScript, u as PreparedClaim, v as SparkSigner, y as StaticDepositClaimRequest } from "./transactions-p89sj_IQ.mjs";
5
5
  import { secp256k1 } from "@noble/curves/secp256k1.js";
6
6
  //#region src/signer/outflow.d.ts
7
7
  /** What an authorized signature sends out, derived inside the signer (never caller-supplied). */
@@ -139,4 +139,4 @@ export declare function createLnurlAuthSigner(options: {
139
139
  readonly rootKey: Uint8Array;
140
140
  }): LnurlAuthSigner;
141
141
  //#endregion
142
- export { type AuthorizeOutflow, EPHEMERAL_ANCHOR_SCRIPT, type FrostAggregateJob, type FrostSignJob, type HtlcTimeoutSignRequest, type IdentityStatement, type LnurlAuthSigner, type OperatorCommitment, type PrepareClaimRequest, type PrepareTransferRequest, type PreparedClaim, type PreparedLightningReceive, type PreparedTransfer, type PreparedTransferLeaf, type SigningCommitment, type SigningTarget, type SparkKey, type SparkLeafKey, type SparkNetwork, type SparkOperator, type SparkOutflow, type SparkSigner, type StaticDepositClaimRequest, addressToScript, decodeBolt11, sparkNetworkConfig };
142
+ export { type AuthorizeOutflow, EPHEMERAL_ANCHOR_SCRIPT, type FrostAggregateJob, type FrostSignJob, type HtlcTimeoutSignRequest, type IdentityStatement, type LnurlAuthSigner, type OperatorCommitment, type PrepareClaimRequest, type PrepareTransferRequest, type PreparedClaim, type PreparedLightningReceive, type PreparedTransfer, type PreparedTransferLeaf, type SigningCommitment, type SigningTarget, type SparkKey, type SparkLeafKey, type SparkNetwork, type SparkOperator, type SparkOutflow, type SparkSigner, type StaticDepositClaimRequest, bitcoinAddressScript, decodeBolt11, sparkNetworkConfig };
package/dist/signer.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as SparkError, r as SparkInputError, t as SparkCryptoError } from "./errors-5xLkExNL.mjs";
2
- import { A as EPHEMERAL_ANCHOR_SCRIPT, At as SecretShareSchema, B as parseTransaction, F as checkIfValidSequence, H as taprootScriptSpendSighash, It as SparkInvoiceFieldsSchema, K as PartialTokenTransactionSchema, Mt as SendLeafKeyTweaksSchema, N as p2trScriptFromPublicKey, O as txIdInputBytes, Q as ChallengeSchema, R as getTimelockFromSequence, V as taprootKeySpendSighash, _ as addressToScript, bt as ClaimPackageSchema, c as staticDepositStatementDigest, ct as uint64be, d as LIGHTNING_HTLC_SEQUENCE, et as hashSparkInvoice, ft as requireLength, g as lightningHtlcOutputScript, i as claimPackageDigest, jt as SendLeafKeyTweakSchema, l as transferPackageDigest, m as createSequenceLockScript, mt as sparkNetworkConfig, n as hashPartialTokenTransaction, nt as protoInvoiceToPlain, o as sendLeafSigningDigest, r as authnChallengeDigest, s as sspChallengeDigest, u as watchtowerRecoveryStatementDigest, vt as ClaimLeafKeyTweakSchema, yt as ClaimLeafKeyTweaksSchema, zt as TransferPackageSchema } from "./token-DmojVTWi.mjs";
2
+ import { A as EPHEMERAL_ANCHOR_SCRIPT, At as SecretShareSchema, B as parseTransaction, F as checkIfValidSequence, H as taprootScriptSpendSighash, It as SparkInvoiceFieldsSchema, K as PartialTokenTransactionSchema, Mt as SendLeafKeyTweaksSchema, N as p2trScriptFromPublicKey, O as txIdInputBytes, Q as ChallengeSchema, R as getTimelockFromSequence, V as taprootKeySpendSighash, _ as bitcoinAddressScript, bt as ClaimPackageSchema, c as staticDepositStatementDigest, ct as uint64be, d as LIGHTNING_HTLC_SEQUENCE, et as hashSparkInvoice, ft as requireLength, g as lightningHtlcOutputScript, i as claimPackageDigest, jt as SendLeafKeyTweakSchema, l as transferPackageDigest, m as createSequenceLockScript, mt as sparkNetworkConfig, n as hashPartialTokenTransaction, nt as protoInvoiceToPlain, o as sendLeafSigningDigest, r as authnChallengeDigest, s as sspChallengeDigest, u as watchtowerRecoveryStatementDigest, vt as ClaimLeafKeyTweakSchema, yt as ClaimLeafKeyTweaksSchema, zt as TransferPackageSchema } from "./token-C3vqRH-k.mjs";
3
3
  import { t as decodeBolt11 } from "./bolt11-rfxnyLcb.mjs";
4
4
  import { i as lightningAddressMessageDigest, r as lightningAddressMessage } from "./lightning-address-CZrb8x4p.mjs";
5
5
  import "./crypto.mjs";
@@ -1424,4 +1424,4 @@ function createLnurlAuthSigner(options) {
1424
1424
  };
1425
1425
  }
1426
1426
  //#endregion
1427
- export { EPHEMERAL_ANCHOR_SCRIPT, addressToScript, createLnurlAuthSigner, createSparkSigner, decodeBolt11, lightningSendHtlcScript, lnurlAuthRootKey, sparkAccountKey, sparkNetworkConfig };
1427
+ export { EPHEMERAL_ANCHOR_SCRIPT, bitcoinAddressScript, createLnurlAuthSigner, createSparkSigner, decodeBolt11, lightningSendHtlcScript, lnurlAuthRootKey, sparkAccountKey, sparkNetworkConfig };
@@ -1208,15 +1208,16 @@ function prevOutAt(tx, vout) {
1208
1208
  };
1209
1209
  }
1210
1210
  /**
1211
- * Decodes a Bitcoin address to its output script under any network — matching upstream
1212
- * `Address::from_str(..).assume_checked()`, which never checks that the address's network matches
1213
- * the operating network.
1211
+ * Decodes a Bitcoin address to its output script under `network` — bech32 HRP and base58 version
1212
+ * bytes must match. An address that only decodes under the other network is an input error, not a
1213
+ * silent retry: a coop-exit or sweep to a foreign-network address would burn sats.
1214
1214
  */
1215
- function addressToScript(address) {
1216
- for (const net of [btcNetwork("mainnet"), btcNetwork("regtest")]) try {
1217
- return OutScript.encode(Address(net).decode(address));
1218
- } catch {}
1219
- throw new SparkInputError("address: not a decodable Bitcoin address");
1215
+ function bitcoinAddressScript(address, network) {
1216
+ try {
1217
+ return OutScript.encode(Address(btcNetwork(network)).decode(address));
1218
+ } catch (error) {
1219
+ throw new SparkInputError(`address: not a ${network} Bitcoin address`, { cause: error });
1220
+ }
1220
1221
  }
1221
1222
  /**
1222
1223
  * Shared builder for node/refund transactions: one input spending `parentTxBytes`'s `vout`, one
@@ -1255,10 +1256,10 @@ function buildSingleOutputTx(parentTxBytes, vout, outputScript, sequence, applyF
1255
1256
  * anchor output at `sequence`; the direct variant deducts the fee, has no anchor, and uses
1256
1257
  * `directSequence`.
1257
1258
  */
1258
- function constructNodeTxPair(parentTx, vout, address, sequence, directSequence, feeSats) {
1259
+ function constructNodeTxPair(parentTx, vout, address, network, sequence, directSequence, feeSats) {
1259
1260
  checkIfValidSequence(sequence);
1260
1261
  checkIfValidSequence(directSequence);
1261
- const outputScript = addressToScript(address);
1262
+ const outputScript = bitcoinAddressScript(address, network);
1262
1263
  return {
1263
1264
  cpfp: buildSingleOutputTx(parentTx, vout, outputScript, sequence, false, feeSats, true),
1264
1265
  direct: buildSingleOutputTx(parentTx, vout, outputScript, directSequence, true, feeSats, false)
@@ -1284,7 +1285,7 @@ function constructRefundTxTrio(cpfpNodeTx, directNodeTx, vout, receivingPublicKe
1284
1285
  function createNodeTxs(params) {
1285
1286
  const address = p2trAddressFromScript(prevOutAt(parseTransaction(params.parentTx), params.vout).script, params.network);
1286
1287
  const directSequence = params.directSequence ?? params.sequence + 50;
1287
- return constructNodeTxPair(params.parentTx, params.vout, address, params.sequence, directSequence, 955);
1288
+ return constructNodeTxPair(params.parentTx, params.vout, address, params.network, params.sequence, directSequence, 955);
1288
1289
  }
1289
1290
  /** Zero-timelock node transactions over output 0 (root variant of `createNodeTxs`). */
1290
1291
  function createZeroTimelockNodeTx(parentTx, network) {
@@ -2119,4 +2120,4 @@ function hashFinalTokenTransaction(finalTokenTransaction) {
2119
2120
  return hashProto(FinalTokenTransactionSchema, finalTokenTransaction);
2120
2121
  }
2121
2122
  //#endregion
2122
- export { SparkAuthnService as $, EPHEMERAL_ANCHOR_SCRIPT as A, SecretShareSchema as At, parseTransaction as B, TransferReceiverStatus as Bt, createInitialTimelockRefundTxs as C, InitiatePreimageSwapRequest_Reason as Ct, txId as D, RenewNodeTimelockSigningJobSchema as Dt, estimateVbytes as E, Order as Et, checkIfValidSequence as F, SparkAddressSchema as Ft, PartialTokenOutputSchema as G, SignatureScheme as Gt, taprootScriptSpendSighash as H, TransferType as Ht, doesTxnNeedRenewed as I, SparkInvoiceFieldsSchema as It, SparkTokenService as J, PartialTokenTransactionSchema as K, getNextHTLCTransactionSequence as L, SparkService as Lt, computeTaprootKeyNoScript as M, SendLeafKeyTweaksSchema as Mt, p2trScriptFromPublicKey as N, SenderTransferPackageSchema as Nt, txIdInputBytes as O, RenewNodeZeroTimelockSigningJobSchema as Ot, xOnlyPublicKey as P, SigningJobSchema as Pt, ChallengeSchema as Q, getTimelockFromSequence as R, StartTransferRequestSchema as Rt, createInitialTimelockNodeTx as S, HashVariant as St, createZeroTimelockNodeTx as T, InvoiceStatus as Tt, CommitStatus as U, TreeNodeStatus as Ut, taprootKeySpendSighash as V, TransferStatus as Vt, InvoiceAttachmentSchema as W, UserSignedTxSigningJobSchema as Wt, TokenTransactionMetadataSchema as X, TokenOutputStatus as Y, TokenTransactionStatus as Z, addressToScript as _, AdaptorPublicKeyPackageSchema as _t, proofOfPossessionDigest as a, uuidToBytes as at, createDecrementedTimelockNodeTx as b, ClaimPackageSchema as bt, staticDepositStatementDigest as c, uint64be as ct, LIGHTNING_HTLC_SEQUENCE as d, assertU32 as dt, hashSparkInvoice as et, constructHtlcSenderSpend as f, requireLength as ft, lightningHtlcOutputScript as g, sparkNetworkProto as gt, finalizeHtlcSpend as h, sparkNetworkFromProto as ht, claimPackageDigest as i, uuidFromBytes as it, btcNetwork as j, SendLeafKeyTweakSchema as jt, verifyFinalizedTaprootSignature as k, RenewRefundTimelockSigningJobSchema as kt, transferPackageDigest as l, assertCompressedKey as lt, createSequenceLockScript as m, sparkNetworkConfig as mt, hashPartialTokenTransaction as n, protoInvoiceToPlain as nt, sendLeafSigningDigest as o, uuidv7 as ot, createRefundTxsForLightning as p, u64ToSats as pt, SignatureWithIndexSchema as q, authnChallengeDigest as r, validateInvoiceFields as rt, sspChallengeDigest as s, compareBytes as st, hashFinalTokenTransaction as t, encodeInvoiceFields as tt, watchtowerRecoveryStatementDigest as u, assertSats as ut, createConnectorRefundTxs as v, ClaimLeafKeyTweakSchema as vt, createMultiInputRootTx as w, InputSigningDataSchema as wt, createDecrementedTimelockRefundTxs as x, Direction as xt, createCurrentTimelockRefundTxs as y, ClaimLeafKeyTweaksSchema as yt, isZeroTimelock as z, TransferPackageSchema as zt };
2123
+ export { SparkAuthnService as $, EPHEMERAL_ANCHOR_SCRIPT as A, SecretShareSchema as At, parseTransaction as B, TransferReceiverStatus as Bt, createInitialTimelockRefundTxs as C, InitiatePreimageSwapRequest_Reason as Ct, txId as D, RenewNodeTimelockSigningJobSchema as Dt, estimateVbytes as E, Order as Et, checkIfValidSequence as F, SparkAddressSchema as Ft, PartialTokenOutputSchema as G, SignatureScheme as Gt, taprootScriptSpendSighash as H, TransferType as Ht, doesTxnNeedRenewed as I, SparkInvoiceFieldsSchema as It, SparkTokenService as J, PartialTokenTransactionSchema as K, getNextHTLCTransactionSequence as L, SparkService as Lt, computeTaprootKeyNoScript as M, SendLeafKeyTweaksSchema as Mt, p2trScriptFromPublicKey as N, SenderTransferPackageSchema as Nt, txIdInputBytes as O, RenewNodeZeroTimelockSigningJobSchema as Ot, xOnlyPublicKey as P, SigningJobSchema as Pt, ChallengeSchema as Q, getTimelockFromSequence as R, StartTransferRequestSchema as Rt, createInitialTimelockNodeTx as S, HashVariant as St, createZeroTimelockNodeTx as T, InvoiceStatus as Tt, CommitStatus as U, TreeNodeStatus as Ut, taprootKeySpendSighash as V, TransferStatus as Vt, InvoiceAttachmentSchema as W, UserSignedTxSigningJobSchema as Wt, TokenTransactionMetadataSchema as X, TokenOutputStatus as Y, TokenTransactionStatus as Z, bitcoinAddressScript as _, AdaptorPublicKeyPackageSchema as _t, proofOfPossessionDigest as a, uuidToBytes as at, createDecrementedTimelockNodeTx as b, ClaimPackageSchema as bt, staticDepositStatementDigest as c, uint64be as ct, LIGHTNING_HTLC_SEQUENCE as d, assertU32 as dt, hashSparkInvoice as et, constructHtlcSenderSpend as f, requireLength as ft, lightningHtlcOutputScript as g, sparkNetworkProto as gt, finalizeHtlcSpend as h, sparkNetworkFromProto as ht, claimPackageDigest as i, uuidFromBytes as it, btcNetwork as j, SendLeafKeyTweakSchema as jt, verifyFinalizedTaprootSignature as k, RenewRefundTimelockSigningJobSchema as kt, transferPackageDigest as l, assertCompressedKey as lt, createSequenceLockScript as m, sparkNetworkConfig as mt, hashPartialTokenTransaction as n, protoInvoiceToPlain as nt, sendLeafSigningDigest as o, uuidv7 as ot, createRefundTxsForLightning as p, u64ToSats as pt, SignatureWithIndexSchema as q, authnChallengeDigest as r, validateInvoiceFields as rt, sspChallengeDigest as s, compareBytes as st, hashFinalTokenTransaction as t, encodeInvoiceFields as tt, watchtowerRecoveryStatementDigest as u, assertSats as ut, createConnectorRefundTxs as v, ClaimLeafKeyTweakSchema as vt, createMultiInputRootTx as w, InputSigningDataSchema as wt, createDecrementedTimelockRefundTxs as x, Direction as xt, createCurrentTimelockRefundTxs as y, ClaimLeafKeyTweaksSchema as yt, isZeroTimelock as z, TransferPackageSchema as zt };
@@ -336,10 +336,10 @@ declare const EPHEMERAL_ANCHOR_SCRIPT: Uint8Array;
336
336
  //#endregion
337
337
  //#region src/core/bitcoin/transactions.d.ts
338
338
  /**
339
- * Decodes a Bitcoin address to its output script under any network — matching upstream
340
- * `Address::from_str(..).assume_checked()`, which never checks that the address's network matches
341
- * the operating network.
339
+ * Decodes a Bitcoin address to its output script under `network` — bech32 HRP and base58 version
340
+ * bytes must match. An address that only decodes under the other network is an input error, not a
341
+ * silent retry: a coop-exit or sweep to a foreign-network address would burn sats.
342
342
  */
343
- declare function addressToScript(address: string): Uint8Array;
343
+ declare function bitcoinAddressScript(address: string, network: SparkNetwork): Uint8Array;
344
344
  //#endregion
345
- export { SparkOperator as _, HtlcTimeoutSignRequest as a, SigningTarget as b, PrepareClaimRequest as c, PreparedLightningReceive as d, PreparedTransfer as f, SparkLeafKey as g, SparkKey as h, FrostSignJob as i, PrepareTransferRequest as l, SigningCommitment as m, EPHEMERAL_ANCHOR_SCRIPT as n, IdentityStatement as o, PreparedTransferLeaf as p, FrostAggregateJob as r, OperatorCommitment as s, addressToScript as t, PreparedClaim as u, SparkSigner as v, StaticDepositClaimRequest as y };
345
+ export { SparkOperator as _, HtlcTimeoutSignRequest as a, SigningTarget as b, PrepareClaimRequest as c, PreparedLightningReceive as d, PreparedTransfer as f, SparkLeafKey as g, SparkKey as h, FrostSignJob as i, PrepareTransferRequest as l, SigningCommitment as m, EPHEMERAL_ANCHOR_SCRIPT as n, IdentityStatement as o, PreparedTransferLeaf as p, FrostAggregateJob as r, OperatorCommitment as s, bitcoinAddressScript as t, PreparedClaim as u, SparkSigner as v, StaticDepositClaimRequest as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qntx/spark",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Spark Bitcoin L2 protocol for TypeScript: platform-neutral client, signer and crypto-backend interfaces.",
5
5
  "keywords": [
6
6
  "bitcoin",