@buildonspark/spark-sdk 0.1.44 → 0.1.46

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.
Files changed (143) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{RequestLightningSendInput-BxbCtwpV.d.cts → RequestLightningSendInput-2cSh_In4.d.cts} +1 -1
  3. package/dist/{RequestLightningSendInput-RGel43ks.d.ts → RequestLightningSendInput-CN6BNg_g.d.ts} +1 -1
  4. package/dist/address/index.cjs +2 -2
  5. package/dist/address/index.d.cts +2 -2
  6. package/dist/address/index.d.ts +2 -2
  7. package/dist/address/index.js +2 -2
  8. package/dist/{chunk-EKFD62HN.js → chunk-4EMV7HHW.js} +2 -1
  9. package/dist/{chunk-4Q2ZDYYU.js → chunk-BGGEVUJK.js} +1157 -208
  10. package/dist/{chunk-CIZNCBKE.js → chunk-C2S227QR.js} +648 -45
  11. package/dist/{chunk-WPTRVD2V.js → chunk-DXR2PXJU.js} +15 -15
  12. package/dist/{chunk-NBCNYDWJ.js → chunk-HHNQ3ZHC.js} +2 -2
  13. package/dist/{chunk-DAXGVPVM.js → chunk-HSCLBJEL.js} +2 -2
  14. package/dist/{chunk-6AFUC5M2.js → chunk-HWJWKEIU.js} +8 -2
  15. package/dist/{chunk-A2ZLMH6I.js → chunk-JB64OQES.js} +259 -327
  16. package/dist/{chunk-KEKGSH7B.js → chunk-KMUMFYFX.js} +3 -3
  17. package/dist/chunk-LHRD2WT6.js +2374 -0
  18. package/dist/{chunk-HTMXTJRK.js → chunk-N5VZVCGJ.js} +4 -4
  19. package/dist/{chunk-SQKXGAIR.js → chunk-NTFKFRQ2.js} +1 -1
  20. package/dist/{chunk-K4BJARWM.js → chunk-OBFKIEMP.js} +1 -1
  21. package/dist/{chunk-UBT6EDVJ.js → chunk-OFCJFZ4I.js} +1 -1
  22. package/dist/{chunk-XX4RRWOX.js → chunk-UXDODSDT.js} +8 -10
  23. package/dist/graphql/objects/index.d.cts +5 -4
  24. package/dist/graphql/objects/index.d.ts +5 -4
  25. package/dist/index-CKL5DodV.d.cts +214 -0
  26. package/dist/index-COm59SPw.d.ts +214 -0
  27. package/dist/index.cjs +4026 -1315
  28. package/dist/index.d.cts +764 -19
  29. package/dist/index.d.ts +764 -19
  30. package/dist/index.js +23 -27
  31. package/dist/index.node.cjs +4026 -1319
  32. package/dist/index.node.d.cts +10 -8
  33. package/dist/index.node.d.ts +10 -8
  34. package/dist/index.node.js +23 -31
  35. package/dist/native/index.cjs +4027 -1316
  36. package/dist/native/index.d.cts +281 -85
  37. package/dist/native/index.d.ts +281 -85
  38. package/dist/native/index.js +4018 -1307
  39. package/dist/{network-CfxLnaot.d.cts → network-Css46DAz.d.cts} +1 -1
  40. package/dist/{network-CroCOQ0B.d.ts → network-hynb7iTZ.d.ts} +1 -1
  41. package/dist/proto/lrc20.cjs +222 -19
  42. package/dist/proto/lrc20.d.cts +1 -1
  43. package/dist/proto/lrc20.d.ts +1 -1
  44. package/dist/proto/lrc20.js +2 -2
  45. package/dist/proto/spark.cjs +1154 -205
  46. package/dist/proto/spark.d.cts +1 -1
  47. package/dist/proto/spark.d.ts +1 -1
  48. package/dist/proto/spark.js +3 -1
  49. package/dist/proto/spark_token.cjs +1377 -58
  50. package/dist/proto/spark_token.d.cts +153 -15
  51. package/dist/proto/spark_token.d.ts +153 -15
  52. package/dist/proto/spark_token.js +40 -4
  53. package/dist/{sdk-types-CTbTdDbE.d.ts → sdk-types-CKBsylfW.d.ts} +1 -1
  54. package/dist/{sdk-types-BeCBoozO.d.cts → sdk-types-Ct8xmN7l.d.cts} +1 -1
  55. package/dist/services/config.cjs +2 -2
  56. package/dist/services/config.d.cts +5 -4
  57. package/dist/services/config.d.ts +5 -4
  58. package/dist/services/config.js +6 -6
  59. package/dist/services/connection.cjs +2438 -262
  60. package/dist/services/connection.d.cts +5 -4
  61. package/dist/services/connection.d.ts +5 -4
  62. package/dist/services/connection.js +4 -4
  63. package/dist/services/index.cjs +5937 -3154
  64. package/dist/services/index.d.cts +7 -6
  65. package/dist/services/index.d.ts +7 -6
  66. package/dist/services/index.js +17 -15
  67. package/dist/services/lrc-connection.cjs +223 -20
  68. package/dist/services/lrc-connection.d.cts +5 -4
  69. package/dist/services/lrc-connection.d.ts +5 -4
  70. package/dist/services/lrc-connection.js +4 -4
  71. package/dist/services/token-transactions.cjs +840 -236
  72. package/dist/services/token-transactions.d.cts +25 -7
  73. package/dist/services/token-transactions.d.ts +25 -7
  74. package/dist/services/token-transactions.js +5 -4
  75. package/dist/services/wallet-config.cjs +3 -1
  76. package/dist/services/wallet-config.d.cts +7 -5
  77. package/dist/services/wallet-config.d.ts +7 -5
  78. package/dist/services/wallet-config.js +3 -1
  79. package/dist/signer/signer.cjs +1 -1
  80. package/dist/signer/signer.d.cts +3 -2
  81. package/dist/signer/signer.d.ts +3 -2
  82. package/dist/signer/signer.js +2 -2
  83. package/dist/{signer-D7vfYik9.d.ts → signer-BP6F__oR.d.cts} +2 -6
  84. package/dist/{signer-DaY8c60s.d.cts → signer-BVZJXcq7.d.ts} +2 -6
  85. package/dist/{spark-C4ZrsgjC.d.cts → spark-DbzGfse6.d.cts} +93 -15
  86. package/dist/{spark-C4ZrsgjC.d.ts → spark-DbzGfse6.d.ts} +93 -15
  87. package/dist/spark_bindings/native/index.cjs +183 -0
  88. package/dist/spark_bindings/native/index.d.cts +14 -0
  89. package/dist/spark_bindings/native/index.d.ts +14 -0
  90. package/dist/spark_bindings/native/index.js +141 -0
  91. package/dist/spark_bindings/wasm/index.cjs +1093 -0
  92. package/dist/spark_bindings/wasm/index.d.cts +47 -0
  93. package/dist/spark_bindings/wasm/index.d.ts +47 -0
  94. package/dist/{chunk-K4C4W5FC.js → spark_bindings/wasm/index.js} +7 -6
  95. package/dist/types/index.cjs +1156 -208
  96. package/dist/types/index.d.cts +5 -4
  97. package/dist/types/index.d.ts +5 -4
  98. package/dist/types/index.js +2 -2
  99. package/dist/types-C-Rp0Oo7.d.cts +46 -0
  100. package/dist/types-C-Rp0Oo7.d.ts +46 -0
  101. package/dist/utils/index.cjs +65 -13
  102. package/dist/utils/index.d.cts +14 -134
  103. package/dist/utils/index.d.ts +14 -134
  104. package/dist/utils/index.js +13 -13
  105. package/package.json +22 -2
  106. package/src/index.node.ts +0 -1
  107. package/src/index.ts +0 -1
  108. package/src/native/index.ts +1 -2
  109. package/src/proto/common.ts +5 -5
  110. package/src/proto/google/protobuf/descriptor.ts +34 -34
  111. package/src/proto/google/protobuf/duration.ts +2 -2
  112. package/src/proto/google/protobuf/empty.ts +2 -2
  113. package/src/proto/google/protobuf/timestamp.ts +2 -2
  114. package/src/proto/mock.ts +4 -4
  115. package/src/proto/spark.ts +1452 -185
  116. package/src/proto/spark_authn.ts +7 -7
  117. package/src/proto/spark_token.ts +1668 -105
  118. package/src/proto/validate/validate.ts +24 -24
  119. package/src/services/bolt11-spark.ts +62 -187
  120. package/src/services/coop-exit.ts +3 -0
  121. package/src/services/lrc20.ts +1 -1
  122. package/src/services/token-transactions.ts +197 -9
  123. package/src/services/transfer.ts +22 -0
  124. package/src/services/tree-creation.ts +13 -0
  125. package/src/services/wallet-config.ts +2 -2
  126. package/src/spark-wallet/spark-wallet.node.ts +0 -4
  127. package/src/spark-wallet/spark-wallet.ts +76 -108
  128. package/src/spark-wallet/types.ts +39 -3
  129. package/src/tests/bolt11-spark.test.ts +7 -15
  130. package/src/tests/integration/ssp/coop-exit.test.ts +7 -7
  131. package/src/tests/integration/swap.test.ts +453 -433
  132. package/src/tests/integration/transfer.test.ts +261 -248
  133. package/src/tests/token-identifier.test.ts +54 -0
  134. package/src/tests/tokens.test.ts +218 -23
  135. package/src/utils/token-hashing.ts +320 -44
  136. package/src/utils/token-identifier.ts +88 -0
  137. package/src/utils/token-transaction-validation.ts +350 -5
  138. package/src/utils/token-transactions.ts +12 -8
  139. package/src/utils/transaction.ts +0 -6
  140. package/dist/chunk-B3AMIGJG.js +0 -1073
  141. package/dist/index-CZmDdSts.d.cts +0 -829
  142. package/dist/index-ClIRO_3y.d.ts +0 -829
  143. package/dist/wasm-7OWFHDMS.js +0 -21
@@ -43,7 +43,6 @@ import {
43
43
  QueryNodesResponse,
44
44
  SigningJob,
45
45
  SubscribeToEventsResponse,
46
- TokenTransactionWithStatus,
47
46
  Transfer,
48
47
  TransferStatus,
49
48
  TransferType,
@@ -102,7 +101,7 @@ import {
102
101
  SparkAddressFormat,
103
102
  } from "../address/index.js";
104
103
  import { isReactNative } from "../constants.js";
105
- import { networkToJSON, Network as NetworkProto } from "../proto/spark.js";
104
+ import { Network as NetworkProto, networkToJSON } from "../proto/spark.js";
106
105
  import {
107
106
  decodeInvoice,
108
107
  getNetworkFromInvoice,
@@ -125,9 +124,12 @@ import type {
125
124
  InitWalletResponse,
126
125
  PayLightningInvoiceParams,
127
126
  SparkWalletProps,
128
- TokenInfo,
127
+ TokenMetadata,
129
128
  TransferParams,
129
+ TokenBalanceMap,
130
130
  } from "./types.js";
131
+ import { encodeHumanReadableTokenIdentifier } from "../utils/token-identifier.js";
132
+ import { TokenTransactionWithStatus } from "../proto/spark_token.js";
131
133
 
132
134
  /**
133
135
  * The SparkWallet class is the primary interface for interacting with the Spark network.
@@ -164,6 +166,7 @@ export class SparkWallet extends EventEmitter {
164
166
  private streamController: AbortController | null = null;
165
167
 
166
168
  protected leaves: TreeNode[] = [];
169
+
167
170
  protected tokenOutputs: Map<string, OutputWithPreviousTransactionData[]> =
168
171
  new Map();
169
172
 
@@ -486,8 +489,7 @@ export class SparkWallet extends EventEmitter {
486
489
  leaf.signingKeyshare.publicKey,
487
490
  operatorLeaf.signingKeyshare.publicKey,
488
491
  ) ||
489
- !equalBytes(leaf.nodeTx, operatorLeaf.nodeTx) ||
490
- !equalBytes(leaf.refundTx, operatorLeaf.refundTx)
492
+ !equalBytes(leaf.nodeTx, operatorLeaf.nodeTx)
491
493
  ) {
492
494
  leavesToIgnore.add(nodeId);
493
495
  }
@@ -1182,32 +1184,6 @@ export class SparkWallet extends EventEmitter {
1182
1184
  };
1183
1185
  }
1184
1186
 
1185
- /**
1186
- * Gets the held token info for the wallet.
1187
- *
1188
- * @deprecated The information is returned in getBalance
1189
- */
1190
- public async getTokenInfo(): Promise<TokenInfo[]> {
1191
- console.warn("getTokenInfo is deprecated. Use getBalance instead.");
1192
-
1193
- await this.syncTokenOutputs();
1194
-
1195
- const lrc20Client = await this.lrc20ConnectionManager.createLrc20Client();
1196
- const { balance, tokenBalances } = await this.getBalance();
1197
-
1198
- const tokenInfo = await lrc20Client.getTokenPubkeyInfo({
1199
- publicKeys: Array.from(tokenBalances.keys()).map(hexToBytes),
1200
- });
1201
-
1202
- return tokenInfo.tokenPubkeyInfos.map((info) => ({
1203
- tokenPublicKey: bytesToHex(info.announcement!.publicKey!.publicKey),
1204
- tokenName: info.announcement!.name,
1205
- tokenSymbol: info.announcement!.symbol,
1206
- tokenDecimals: Number(bytesToNumberBE(info.announcement!.decimal)),
1207
- maxSupply: bytesToNumberBE(info.announcement!.maxSupply),
1208
- }));
1209
- }
1210
-
1211
1187
  /**
1212
1188
  * Gets the current balance of the wallet.
1213
1189
  * You can use the forceRefetch option to synchronize your wallet and claim any
@@ -1215,24 +1191,21 @@ export class SparkWallet extends EventEmitter {
1215
1191
  *
1216
1192
  * @returns {Promise<Object>} Object containing:
1217
1193
  * - balance: The wallet's current balance in satoshis
1218
- * - tokenBalances: Map of token public keys to token balances and token info
1194
+ * - tokenBalances: Map of the human readable token identifier to token balances and token info
1219
1195
  */
1220
1196
  public async getBalance(): Promise<{
1221
1197
  balance: bigint;
1222
- tokenBalances: Map<string, { balance: bigint; tokenInfo: TokenInfo }>;
1198
+ tokenBalances: TokenBalanceMap;
1223
1199
  }> {
1224
1200
  const leaves = await this.getLeaves(true);
1225
1201
  await this.syncTokenOutputs();
1226
1202
 
1227
- let tokenBalances: Map<string, { balance: bigint; tokenInfo: TokenInfo }>;
1203
+ let tokenBalances: TokenBalanceMap;
1228
1204
 
1229
1205
  if (this.tokenOutputs.size !== 0) {
1230
1206
  tokenBalances = await this.getTokenBalance();
1231
1207
  } else {
1232
- tokenBalances = new Map<
1233
- string,
1234
- { balance: bigint; tokenInfo: TokenInfo }
1235
- >();
1208
+ tokenBalances = new Map();
1236
1209
  }
1237
1210
 
1238
1211
  return {
@@ -1241,32 +1214,33 @@ export class SparkWallet extends EventEmitter {
1241
1214
  };
1242
1215
  }
1243
1216
 
1244
- private async getTokenBalance(): Promise<
1245
- Map<string, { balance: bigint; tokenInfo: TokenInfo }>
1246
- > {
1247
- const lrc20Client = await this.lrc20ConnectionManager.createLrc20Client();
1217
+ private async getTokenBalance(): Promise<TokenBalanceMap> {
1218
+ const sparkTokenClient =
1219
+ await this.connectionManager.createSparkTokenClient(
1220
+ this.config.getCoordinatorAddress(),
1221
+ );
1248
1222
 
1249
- // Get token info for all tokens
1250
- const tokenInfo = await lrc20Client.getTokenPubkeyInfo({
1251
- publicKeys: Array.from(this.tokenOutputs.keys()).map(hexToBytes),
1223
+ const tokenMetadata = await sparkTokenClient.query_token_metadata({
1224
+ issuerPublicKeys: Array.from(this.tokenOutputs.keys()).map(hexToBytes),
1252
1225
  });
1226
+ const result: TokenBalanceMap = new Map();
1253
1227
 
1254
- const result = new Map<string, { balance: bigint; tokenInfo: TokenInfo }>();
1255
-
1256
- for (const info of tokenInfo.tokenPubkeyInfos) {
1257
- const tokenPublicKey = bytesToHex(
1258
- info.announcement!.publicKey!.publicKey,
1259
- );
1228
+ for (const metadata of tokenMetadata.tokenMetadata) {
1229
+ const tokenPublicKey = bytesToHex(metadata.issuerPublicKey);
1260
1230
  const leaves = this.tokenOutputs.get(tokenPublicKey);
1261
-
1262
- result.set(tokenPublicKey, {
1231
+ const humanReadableTokenIdentifier = encodeHumanReadableTokenIdentifier({
1232
+ tokenIdentifier: metadata.tokenIdentifier,
1233
+ network: this.config.getNetworkType(),
1234
+ });
1235
+ result.set(humanReadableTokenIdentifier, {
1263
1236
  balance: leaves ? calculateAvailableTokenAmount(leaves) : BigInt(0),
1264
- tokenInfo: {
1237
+ tokenMetadata: {
1265
1238
  tokenPublicKey,
1266
- tokenName: info.announcement!.name,
1267
- tokenSymbol: info.announcement!.symbol,
1268
- tokenDecimals: Number(bytesToNumberBE(info.announcement!.decimal)),
1269
- maxSupply: bytesToNumberBE(info.announcement!.maxSupply),
1239
+ rawTokenIdentifier: metadata.tokenIdentifier,
1240
+ tokenName: metadata.tokenName,
1241
+ tokenTicker: metadata.tokenTicker,
1242
+ decimals: metadata.decimals,
1243
+ maxSupply: bytesToNumberBE(metadata.maxSupply),
1270
1244
  },
1271
1245
  });
1272
1246
  }
@@ -2611,27 +2585,9 @@ export class SparkWallet extends EventEmitter {
2611
2585
  invoice.invoice.encodedInvoice,
2612
2586
  ).fallbackAddress;
2613
2587
 
2614
- if (
2615
- sparkFallbackAddress &&
2616
- isValidSparkFallback(hexToBytes(sparkFallbackAddress))
2617
- ) {
2618
- const invoiceIdentityPubkey = sparkFallbackAddress.slice(6); // remove the 3 byte header
2619
- const expectedIdentityPubkey =
2620
- receiverIdentityPubkey ?? (await this.getIdentityPublicKey());
2621
-
2622
- if (invoiceIdentityPubkey !== expectedIdentityPubkey) {
2623
- throw new ValidationError(
2624
- "Mismatch between spark identity embedded in lightning invoice and designated recipient spark identity",
2625
- {
2626
- field: "sparkFallbackAddress",
2627
- value: invoiceIdentityPubkey,
2628
- expected: expectedIdentityPubkey,
2629
- },
2630
- );
2631
- }
2632
- } else {
2588
+ if (!sparkFallbackAddress) {
2633
2589
  throw new ValidationError(
2634
- "No valid spark fallback address found in lightning invoice",
2590
+ "No spark fallback address found in lightning invoice",
2635
2591
  {
2636
2592
  field: "sparkFallbackAddress",
2637
2593
  value: sparkFallbackAddress,
@@ -2639,6 +2595,20 @@ export class SparkWallet extends EventEmitter {
2639
2595
  },
2640
2596
  );
2641
2597
  }
2598
+
2599
+ const expectedIdentityPubkey =
2600
+ receiverIdentityPubkey ?? (await this.getIdentityPublicKey());
2601
+
2602
+ if (sparkFallbackAddress !== expectedIdentityPubkey) {
2603
+ throw new ValidationError(
2604
+ "Mismatch between spark identity embedded in lightning invoice and designated recipient spark identity",
2605
+ {
2606
+ field: "sparkFallbackAddress",
2607
+ value: sparkFallbackAddress,
2608
+ expected: expectedIdentityPubkey,
2609
+ },
2610
+ );
2611
+ }
2642
2612
  }
2643
2613
 
2644
2614
  return invoice;
@@ -2736,9 +2706,8 @@ export class SparkWallet extends EventEmitter {
2736
2706
  "No valid spark address found in invoice. Defaulting to lightning.",
2737
2707
  );
2738
2708
  } else {
2739
- const identityPublicKey = sparkFallbackAddress.slice(6); // remove the 3 byte header
2740
2709
  const receiverSparkAddress = encodeSparkAddress({
2741
- identityPublicKey,
2710
+ identityPublicKey: sparkFallbackAddress,
2742
2711
  network: Network[invoiceNetwork] as NetworkType,
2743
2712
  });
2744
2713
  return await this.transfer({
@@ -3181,8 +3150,15 @@ export class SparkWallet extends EventEmitter {
3181
3150
  * @param {string} id - The ID of the transfer
3182
3151
  * @returns {Promise<Transfer | undefined>} The transfer
3183
3152
  */
3184
- public async getTransfer(id: string): Promise<Transfer | undefined> {
3185
- return await this.transferService.queryTransfer(id);
3153
+ public async getTransfer(id: string): Promise<WalletTransfer | undefined> {
3154
+ const transfer = await this.transferService.queryTransfer(id);
3155
+ if (!transfer) {
3156
+ return undefined;
3157
+ }
3158
+ return mapTransferToWalletTransfer(
3159
+ transfer,
3160
+ bytesToHex(await this.config.signer.getIdentityPublicKey()),
3161
+ );
3186
3162
  }
3187
3163
 
3188
3164
  // ***** Token Flow *****
@@ -3197,10 +3173,9 @@ export class SparkWallet extends EventEmitter {
3197
3173
  this.tokenOutputs.clear();
3198
3174
 
3199
3175
  const unsortedTokenOutputs =
3200
- await this.tokenTransactionService.fetchOwnedTokenOutputs(
3201
- [await this.config.signer.getIdentityPublicKey()],
3202
- [],
3203
- );
3176
+ await this.tokenTransactionService.fetchOwnedTokenOutputs({
3177
+ ownerPublicKeys: [await this.config.signer.getIdentityPublicKey()],
3178
+ });
3204
3179
 
3205
3180
  const filteredTokenOutputs = unsortedTokenOutputs.filter(
3206
3181
  (output) =>
@@ -3331,34 +3306,27 @@ export class SparkWallet extends EventEmitter {
3331
3306
  * Retrieves token transaction history for specified tokens owned by the wallet.
3332
3307
  * Can optionally filter by specific transaction hashes.
3333
3308
  *
3334
- * @param tokenPublicKeys - Array of token public keys to query transactions for
3309
+ * @param ownerPublicKeys - Optional array of owner public keys to query transactions for
3310
+ * @param issuerPublicKeys - Optional array of issuer public keys to query transactions for
3335
3311
  * @param tokenTransactionHashes - Optional array of specific transaction hashes to filter by
3312
+ * @param tokenIdentifiers - Optional array of token identifiers to filter by
3313
+ * @param outputIds - Optional array of output IDs to filter by
3336
3314
  * @returns Promise resolving to array of token transactions with their current status
3337
3315
  */
3338
3316
  public async queryTokenTransactions(
3339
- tokenPublicKeys: string[],
3317
+ ownerPublicKeys?: string[],
3318
+ issuerPublicKeys?: string[],
3340
3319
  tokenTransactionHashes?: string[],
3320
+ tokenIdentifiers?: string[],
3321
+ outputIds?: string[],
3341
3322
  ): Promise<TokenTransactionWithStatus[]> {
3342
- const sparkClient = await this.connectionManager.createSparkClient(
3343
- this.config.getCoordinatorAddress(),
3344
- );
3345
-
3346
- let queryParams;
3347
- if (tokenTransactionHashes?.length) {
3348
- queryParams = {
3349
- tokenPublicKeys: tokenPublicKeys?.map(hexToBytes)!,
3350
- ownerPublicKeys: [hexToBytes(await this.getIdentityPublicKey())],
3351
- tokenTransactionHashes: tokenTransactionHashes.map(hexToBytes),
3352
- };
3353
- } else {
3354
- queryParams = {
3355
- tokenPublicKeys: tokenPublicKeys?.map(hexToBytes)!,
3356
- ownerPublicKeys: [hexToBytes(await this.getIdentityPublicKey())],
3357
- };
3358
- }
3359
-
3360
- const response = await sparkClient.query_token_transactions(queryParams);
3361
- return response.tokenTransactionsWithStatus;
3323
+ return this.tokenTransactionService.queryTokenTransactions({
3324
+ ownerPublicKeys,
3325
+ issuerPublicKeys,
3326
+ tokenTransactionHashes,
3327
+ tokenIdentifiers,
3328
+ outputIds,
3329
+ }) as Promise<TokenTransactionWithStatus[]>;
3362
3330
  }
3363
3331
 
3364
3332
  public async getTokenL1Address(): Promise<string> {
@@ -1,6 +1,7 @@
1
1
  import type { Transaction } from "@scure/btc-signer";
2
2
  import { ConfigOptions } from "../services/wallet-config.js";
3
3
  import type { SparkSigner } from "../signer/signer.js";
4
+ import { HumanReadableTokenIdentifier } from "../utils/token-identifier.js";
4
5
 
5
6
  export type CreateLightningInvoiceParams = {
6
7
  amountSats: number;
@@ -30,14 +31,49 @@ export type DepositParams = {
30
31
  vout: number;
31
32
  };
32
33
 
33
- export type TokenInfo = {
34
+ /**
35
+ * Token metadata containing essential information about a token.
36
+ * This is the wallet's internal representation with JavaScript-friendly types.
37
+ *
38
+ * rawTokenIdentifier: This is the raw binary token identifier - This is used to encode the human readable token identifier.
39
+ *
40
+ * tokenPublicKey: This is the hex-encoded public key of the token issuer - Same as issuerPublicKey.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const tokenMetadata: TokenMetadata = {
45
+ * rawTokenIdentifier: new Uint8Array([1, 2, 3]),
46
+ * tokenPublicKey: "0348fbb...",
47
+ * tokenName: "SparkToken",
48
+ * tokenTicker: "SPK",
49
+ * decimals: 8,
50
+ * maxSupply: 1000000n
51
+ * };
52
+ * ```
53
+ */
54
+ export type TokenMetadata = {
55
+ /** Raw binary token identifier - This is used to encode the human readable token identifier */
56
+ rawTokenIdentifier: Uint8Array;
57
+ /** Hex-encoded public key of the token issuer - Same as issuerPublicKey */
34
58
  tokenPublicKey: string;
59
+ /** Human-readable name of the token (e.g., SparkToken)*/
35
60
  tokenName: string;
36
- tokenSymbol: string;
37
- tokenDecimals: number;
61
+ /** Short ticker symbol for the token (e.g., "SPK") */
62
+ tokenTicker: string;
63
+ /** Number of decimal places for token amounts */
64
+ decimals: number;
65
+ /** Maximum supply of tokens that can ever be minted */
38
66
  maxSupply: bigint;
39
67
  };
40
68
 
69
+ export type TokenBalanceMap = Map<
70
+ HumanReadableTokenIdentifier,
71
+ {
72
+ balance: bigint;
73
+ tokenMetadata: TokenMetadata;
74
+ }
75
+ >;
76
+
41
77
  export type InitWalletResponse = {
42
78
  mnemonic?: string | undefined;
43
79
  };
@@ -62,7 +62,7 @@ describe("spark bolt11 invoice decoding", () => {
62
62
  "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny";
63
63
  expect(() => {
64
64
  decodeInvoice(invoice);
65
- }).toThrow('Letter "1" must be present between prefix and data only');
65
+ }).toThrow("Not a proper lightning payment request");
66
66
  });
67
67
 
68
68
  it("fails to decode malformed Bolt11 invoice - mixed case", () => {
@@ -73,20 +73,12 @@ describe("spark bolt11 invoice decoding", () => {
73
73
  }).toThrow("String must be lowercase or uppercase");
74
74
  });
75
75
 
76
- it("fails to decode bolt11 invoice with invalid signature", () => {
77
- const invoice =
78
- "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqwgt7mcn5yqw3yx0w94pswkpq6j9uh6xfqqqtsk4tnarugeektd4hg5975x9am52rz4qskukxdmjemg92vvqz8nvmsye63r5ykel43pgz7zq0g2";
79
- expect(() => {
80
- decodeInvoice(invoice);
81
- }).toThrow("Invalid BOLT11 signature");
82
- });
83
-
84
76
  it("fails to decode bolt11 invoice with invalid multiplier", () => {
85
77
  const invoice =
86
78
  "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqrrzc4cvfue4zp3hggxp47ag7xnrlr8vgcmkjxk3j5jqethnumgkpqp23z9jclu3v0a7e0aruz366e9wqdykw6dxhdzcjjhldxq0w6wgqcnu43j";
87
79
  expect(() => {
88
80
  decodeInvoice(invoice);
89
- }).toThrow("Invalid multiplier: x");
81
+ }).toThrow("Not a valid multiplier for the amount");
90
82
  });
91
83
 
92
84
  it("fails to decode bolt11 invoice with invalid submillisatoshi precision", () => {
@@ -94,7 +86,7 @@ describe("spark bolt11 invoice decoding", () => {
94
86
  "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgq0lzc236j96a95uv0m3umg28gclm5lqxtqqwk32uuk4k6673k6n5kfvx3d2h8s295fad45fdhmusm8sjudfhlf6dcsxmfvkeywmjdkxcp99202x";
95
87
  expect(() => {
96
88
  decodeInvoice(invoice);
97
- }).toThrow("Invalid submillisatoshi precision");
89
+ }).toThrow("Amount is outside of valid range");
98
90
  });
99
91
 
100
92
  it("fails to decode bolt11 invoice with invalid payment secret", () => {
@@ -107,17 +99,17 @@ describe("spark bolt11 invoice decoding", () => {
107
99
 
108
100
  it("decodes a bolt11 invoice with spark address embedded", () => {
109
101
  const invoice =
110
- "lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgqfpml2dgykqjsjj0vxkcz9cuftlfhw5qs9720aqf4y0azyqggx29gz7gt7eadu5h5wqmn7ns8rju0ps0tk8jx70eg8jxek3usgsehql0ztdxmfjj58nqjky6w9wp324ctcnj9vnrgc8j9dpujfqjrc8lv9z4twr2pur2cgqujn2dx";
102
+ "lnbc13u1p5xalmkpp5z79uwgne7znz76plf0q4zxmh8t3wke6gsnm5kn67h4satpgflkmssp5azht5ywc5s4m40jf9h0nwlr959a34n72pns50lfm93zz8lvs7nqsxq9z0rgqnp4q0p92sfan5vj2a4f8q3gsfsy8qp60maeuxz858c5x0hvt5u0p0h9jr9yqtqd37k2ya0pv8pqeyjs4lklcexjyw600g9qqp62r4j0ph8fcmlfwqqqqzfv7u6g85qqqqqqqqqqthqq9qpz9cat0ndmwmfx036y9fxfhdufta3mn95ta9xw34ynlwg7euxjck85ysq0gfqqqqq7u6egqrhxk2qqn3qqcqzpgdq2w3jhxap3xv9qyyssqfahd64hu0lffl7cw2e4evu400s09yeupypvnfjvjjyq8rh05y9gzd3dqnmkvuyd9jszyhmdey75dujz8xaufgahsxkqktf3wxny8ghsqpk4mg8";
111
103
 
112
104
  const { amountMSats, fallbackAddress, paymentHash } =
113
105
  decodeInvoice(invoice);
114
106
 
115
- expect(amountMSats).toBe(null);
107
+ expect(amountMSats).toBe(1300000n);
116
108
  expect(fallbackAddress).toBe(
117
- "53504b0250949ec35b022e3895fd37750102f94fe813523fa220108328a81790bf67ade5",
109
+ "0222e3ab7cdbb76d267c7442a4c9bb7895f63b9968be94ce8d493fb91ecf0d2c58",
118
110
  );
119
111
  expect(paymentHash).toBe(
120
- "0001020304050607080900010203040506070809000102030405060708090102",
112
+ "178bc72279f0a62f683f4bc1511b773ae2eb674884f74b4f5ebd61d58509fdb7",
121
113
  );
122
114
  });
123
115
  });
@@ -41,22 +41,22 @@ describe("SSP coop exit integration", () => {
41
41
 
42
42
  expect(feeEstimate).toBeDefined();
43
43
  expect(feeEstimate?.l1BroadcastFeeFast).toBeDefined();
44
- expect(feeEstimate?.l1BroadcastFeeFast).toBeGreaterThan(0);
44
+ expect(feeEstimate?.l1BroadcastFeeFast.originalValue).toBeGreaterThan(0);
45
45
  expect(feeEstimate?.userFeeFast).toBeDefined();
46
- expect(feeEstimate?.userFeeFast).toBeGreaterThan(0);
46
+ expect(feeEstimate?.userFeeFast.originalValue).toBeGreaterThan(0);
47
47
 
48
48
  expect(feeEstimate?.l1BroadcastFeeMedium).toBeDefined();
49
- expect(feeEstimate?.l1BroadcastFeeMedium).toBeGreaterThan(0);
49
+ expect(feeEstimate?.l1BroadcastFeeMedium.originalValue).toBeGreaterThan(0);
50
50
  expect(feeEstimate?.userFeeMedium).toBeDefined();
51
- expect(feeEstimate?.userFeeMedium).toBeGreaterThan(0);
51
+ expect(feeEstimate?.userFeeMedium.originalValue).toBeGreaterThan(0);
52
52
 
53
53
  expect(feeEstimate?.l1BroadcastFeeSlow).toBeDefined();
54
- expect(feeEstimate?.l1BroadcastFeeSlow).toBeGreaterThan(0);
54
+ expect(feeEstimate?.l1BroadcastFeeSlow.originalValue).toBeGreaterThan(0);
55
55
  expect(feeEstimate?.userFeeSlow).toBeDefined();
56
- expect(feeEstimate?.userFeeSlow).toBeGreaterThan(0);
56
+ expect(feeEstimate?.userFeeSlow.originalValue).toBeGreaterThan(0);
57
57
  }, 60000);
58
58
 
59
- it("should complete coop exit without deducting fees from withdrawal amount", async () => {
59
+ it.skip("should complete coop exit without deducting fees from withdrawal amount", async () => {
60
60
  const faucet = BitcoinFaucet.getInstance();
61
61
 
62
62
  const { wallet: userWallet } = await SparkWalletTesting.initialize(