@buildonspark/spark-sdk 0.1.43 → 0.1.45
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/CHANGELOG.md +16 -0
- package/dist/{RequestLightningSendInput-D7fZdT4A.d.ts → RequestLightningSendInput-DEPd_fPO.d.ts} +43 -4
- package/dist/{RequestLightningSendInput-Na1mHdWg.d.cts → RequestLightningSendInput-Du0z7Om7.d.cts} +43 -4
- package/dist/address/index.cjs +2 -2
- package/dist/address/index.d.cts +2 -2
- package/dist/address/index.d.ts +2 -2
- package/dist/address/index.js +2 -2
- package/dist/{chunk-IRW5TWMH.js → chunk-5FUB65LX.js} +7 -9
- package/dist/{chunk-BUTZWYBW.js → chunk-6264CGDM.js} +4 -4
- package/dist/{chunk-VFJQNBFX.js → chunk-7V6N75CC.js} +5 -2
- package/dist/{chunk-M6A4KFIG.js → chunk-BGGEVUJK.js} +1505 -445
- package/dist/{chunk-DQYKQJRZ.js → chunk-C2S227QR.js} +675 -52
- package/dist/{chunk-GYQR4B4P.js → chunk-GZ5IPPJ2.js} +2 -2
- package/dist/{chunk-6AFUC5M2.js → chunk-HWJWKEIU.js} +8 -2
- package/dist/{chunk-TOSP3INR.js → chunk-I54FARY2.js} +4 -2
- package/dist/{chunk-WWOTVNPP.js → chunk-J2IE4Z7Y.js} +544 -431
- package/dist/{chunk-O4RYNJNB.js → chunk-KMUMFYFX.js} +3 -3
- package/dist/chunk-LHRD2WT6.js +2374 -0
- package/dist/{chunk-ABZA6R5S.js → chunk-NTFKFRQ2.js} +1 -1
- package/dist/{chunk-MIVX3GHD.js → chunk-OBFKIEMP.js} +1 -1
- package/dist/{chunk-HRQRRDSS.js → chunk-PQN3C2MF.js} +15 -15
- package/dist/{chunk-DOA6QXYQ.js → chunk-R5PXJZQS.js} +3 -1
- package/dist/{chunk-TIUBYNN5.js → chunk-YUPMXTCJ.js} +4 -4
- package/dist/graphql/objects/index.d.cts +6 -43
- package/dist/graphql/objects/index.d.ts +6 -43
- package/dist/graphql/objects/index.js +1 -1
- package/dist/index-B2AwKW5J.d.cts +214 -0
- package/dist/index-CJDi1HWc.d.ts +214 -0
- package/dist/index.cjs +4150 -1026
- package/dist/index.d.cts +764 -19
- package/dist/index.d.ts +764 -19
- package/dist/index.js +17 -21
- package/dist/index.node.cjs +4153 -1033
- package/dist/index.node.d.cts +10 -8
- package/dist/index.node.d.ts +10 -8
- package/dist/index.node.js +20 -28
- package/dist/native/index.cjs +4166 -1042
- package/dist/native/index.d.cts +369 -108
- package/dist/native/index.d.ts +369 -108
- package/dist/native/index.js +4138 -1015
- package/dist/{network-xkBSpaTn.d.ts → network-BTJl-Sul.d.ts} +1 -1
- package/dist/{network-D5lKssVl.d.cts → network-CqgsdUF2.d.cts} +1 -1
- package/dist/proto/lrc20.cjs +222 -19
- package/dist/proto/lrc20.d.cts +1 -1
- package/dist/proto/lrc20.d.ts +1 -1
- package/dist/proto/lrc20.js +2 -2
- package/dist/proto/spark.cjs +1502 -442
- package/dist/proto/spark.d.cts +1 -1
- package/dist/proto/spark.d.ts +1 -1
- package/dist/proto/spark.js +5 -5
- package/dist/proto/spark_token.cjs +1515 -56
- package/dist/proto/spark_token.d.cts +153 -15
- package/dist/proto/spark_token.d.ts +153 -15
- package/dist/proto/spark_token.js +40 -4
- package/dist/{sdk-types-B-q9py_P.d.cts → sdk-types-B0SwjolI.d.cts} +1 -1
- package/dist/{sdk-types-BPoPgzda.d.ts → sdk-types-Cc4l4kb1.d.ts} +1 -1
- package/dist/services/config.cjs +7 -3
- package/dist/services/config.d.cts +5 -4
- package/dist/services/config.d.ts +5 -4
- package/dist/services/config.js +6 -6
- package/dist/services/connection.cjs +2938 -646
- package/dist/services/connection.d.cts +5 -4
- package/dist/services/connection.d.ts +5 -4
- package/dist/services/connection.js +4 -4
- package/dist/services/index.cjs +6381 -3461
- package/dist/services/index.d.cts +7 -6
- package/dist/services/index.d.ts +7 -6
- package/dist/services/index.js +15 -13
- package/dist/services/lrc-connection.cjs +227 -21
- package/dist/services/lrc-connection.d.cts +5 -4
- package/dist/services/lrc-connection.d.ts +5 -4
- package/dist/services/lrc-connection.js +4 -4
- package/dist/services/token-transactions.cjs +868 -244
- package/dist/services/token-transactions.d.cts +25 -7
- package/dist/services/token-transactions.d.ts +25 -7
- package/dist/services/token-transactions.js +5 -4
- package/dist/services/wallet-config.cjs +4 -1
- package/dist/services/wallet-config.d.cts +7 -5
- package/dist/services/wallet-config.d.ts +7 -5
- package/dist/services/wallet-config.js +3 -1
- package/dist/signer/signer.cjs +5 -2
- package/dist/signer/signer.d.cts +3 -2
- package/dist/signer/signer.d.ts +3 -2
- package/dist/signer/signer.js +2 -2
- package/dist/{signer-wqesWifN.d.ts → signer-BocS_J6B.d.ts} +2 -6
- package/dist/{signer-IO3oMRNj.d.cts → signer-DKS0AJkw.d.cts} +2 -6
- package/dist/{spark-CDm4gqS6.d.cts → spark-dM7EYXYQ.d.cts} +138 -42
- package/dist/{spark-CDm4gqS6.d.ts → spark-dM7EYXYQ.d.ts} +138 -42
- package/dist/spark_bindings/native/index.cjs +183 -0
- package/dist/spark_bindings/native/index.d.cts +14 -0
- package/dist/spark_bindings/native/index.d.ts +14 -0
- package/dist/spark_bindings/native/index.js +141 -0
- package/dist/spark_bindings/wasm/index.cjs +1093 -0
- package/dist/spark_bindings/wasm/index.d.cts +47 -0
- package/dist/spark_bindings/wasm/index.d.ts +47 -0
- package/dist/{chunk-K4C4W5FC.js → spark_bindings/wasm/index.js} +7 -6
- package/dist/types/index.cjs +1503 -443
- package/dist/types/index.d.cts +6 -5
- package/dist/types/index.d.ts +6 -5
- package/dist/types/index.js +3 -3
- package/dist/types-C-Rp0Oo7.d.cts +46 -0
- package/dist/types-C-Rp0Oo7.d.ts +46 -0
- package/dist/utils/index.cjs +358 -36
- package/dist/utils/index.d.cts +14 -134
- package/dist/utils/index.d.ts +14 -134
- package/dist/utils/index.js +8 -8
- package/package.json +21 -1
- package/src/constants.ts +5 -1
- package/src/graphql/client.ts +28 -0
- package/src/graphql/mutations/RequestCoopExit.ts +6 -0
- package/src/graphql/mutations/RequestSwapLeaves.ts +2 -0
- package/src/graphql/queries/GetCoopExitFeeQuote.ts +20 -0
- package/src/index.node.ts +0 -1
- package/src/index.ts +0 -1
- package/src/native/index.ts +1 -2
- package/src/proto/common.ts +5 -5
- package/src/proto/google/protobuf/descriptor.ts +34 -34
- package/src/proto/google/protobuf/duration.ts +2 -2
- package/src/proto/google/protobuf/empty.ts +2 -2
- package/src/proto/google/protobuf/timestamp.ts +2 -2
- package/src/proto/mock.ts +4 -4
- package/src/proto/spark.ts +1924 -525
- package/src/proto/spark_authn.ts +7 -7
- package/src/proto/spark_token.ts +1668 -105
- package/src/proto/validate/validate.ts +24 -24
- package/src/services/bolt11-spark.ts +62 -187
- package/src/services/coop-exit.ts +3 -0
- package/src/services/lrc20.ts +1 -1
- package/src/services/token-transactions.ts +209 -9
- package/src/services/transfer.ts +22 -3
- package/src/services/tree-creation.ts +13 -0
- package/src/services/wallet-config.ts +2 -1
- package/src/spark-wallet/spark-wallet.node.ts +3 -7
- package/src/spark-wallet/spark-wallet.ts +376 -232
- package/src/spark-wallet/types.ts +39 -3
- package/src/tests/bolt11-spark.test.ts +7 -15
- package/src/tests/integration/deposit.test.ts +16 -0
- package/src/tests/integration/ssp/coop-exit.test.ts +85 -21
- package/src/tests/integration/ssp/swap.test.ts +47 -0
- package/src/tests/integration/swap.test.ts +453 -433
- package/src/tests/integration/transfer.test.ts +261 -248
- package/src/tests/token-identifier.test.ts +54 -0
- package/src/tests/tokens.test.ts +218 -22
- package/src/utils/token-hashing.ts +346 -52
- package/src/utils/token-identifier.ts +88 -0
- package/src/utils/token-transaction-validation.ts +350 -5
- package/src/utils/token-transactions.ts +12 -8
- package/src/utils/transaction.ts +2 -8
- package/dist/chunk-VA7MV4MZ.js +0 -1073
- package/dist/index-7RYRH5wc.d.ts +0 -815
- package/dist/index-BJOc8Ur-.d.cts +0 -815
- package/dist/wasm-7OWFHDMS.js +0 -21
- package/src/logger.ts +0 -3
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ConnectionManager
|
|
3
|
-
} from "./chunk-HRQRRDSS.js";
|
|
4
1
|
import {
|
|
5
2
|
Lrc20ConnectionManager
|
|
6
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GZ5IPPJ2.js";
|
|
7
4
|
import {
|
|
8
5
|
TokenTransactionService
|
|
9
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-C2S227QR.js";
|
|
10
7
|
import {
|
|
11
8
|
DEFAULT_FEE_SATS,
|
|
12
9
|
computeTaprootKeyNoScript,
|
|
@@ -23,16 +20,17 @@ import {
|
|
|
23
20
|
getTxFromRawTxHex,
|
|
24
21
|
getTxId,
|
|
25
22
|
proofOfPossessionMessageHashForDepositAddress
|
|
26
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-5FUB65LX.js";
|
|
27
24
|
import {
|
|
28
25
|
calculateAvailableTokenAmount
|
|
29
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-HWJWKEIU.js";
|
|
30
27
|
import {
|
|
31
28
|
mapTransferToWalletTransfer,
|
|
32
29
|
mapTreeNodeToWalletLeaf
|
|
33
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-OBFKIEMP.js";
|
|
34
31
|
import {
|
|
35
32
|
ClaimStaticDepositRequestType_default,
|
|
33
|
+
CoopExitFeeQuoteFromJson,
|
|
36
34
|
CurrencyAmountFromJson,
|
|
37
35
|
ExitSpeed_default,
|
|
38
36
|
FRAGMENT,
|
|
@@ -40,20 +38,21 @@ import {
|
|
|
40
38
|
FRAGMENT3,
|
|
41
39
|
FRAGMENT4,
|
|
42
40
|
FRAGMENT5,
|
|
41
|
+
FRAGMENT6,
|
|
43
42
|
LeavesSwapRequestFromJson,
|
|
44
43
|
LightningReceiveRequestFromJson,
|
|
45
44
|
LightningSendRequestFromJson,
|
|
46
45
|
SparkCoopExitRequestStatus_default,
|
|
47
46
|
TransferFromJson
|
|
48
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-I54FARY2.js";
|
|
49
48
|
import {
|
|
50
49
|
decodeSparkAddress,
|
|
51
50
|
encodeSparkAddress,
|
|
52
51
|
isValidPublicKey
|
|
53
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-KMUMFYFX.js";
|
|
54
53
|
import {
|
|
55
54
|
WalletConfigService
|
|
56
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-6264CGDM.js";
|
|
57
56
|
import {
|
|
58
57
|
LRC_WALLET_NETWORK,
|
|
59
58
|
LRC_WALLET_NETWORK_TYPE,
|
|
@@ -63,17 +62,7 @@ import {
|
|
|
63
62
|
} from "./chunk-Z5HIAYFT.js";
|
|
64
63
|
import {
|
|
65
64
|
ELECTRS_CREDENTIALS
|
|
66
|
-
} from "./chunk-
|
|
67
|
-
import {
|
|
68
|
-
BitcoinNetwork_default
|
|
69
|
-
} from "./chunk-HMLOC6TE.js";
|
|
70
|
-
import {
|
|
71
|
-
SendLeafKeyTweaks,
|
|
72
|
-
networkToJSON
|
|
73
|
-
} from "./chunk-M6A4KFIG.js";
|
|
74
|
-
import {
|
|
75
|
-
isReactNative
|
|
76
|
-
} from "./chunk-VFJQNBFX.js";
|
|
65
|
+
} from "./chunk-R5PXJZQS.js";
|
|
77
66
|
import {
|
|
78
67
|
addPublicKeys,
|
|
79
68
|
applyAdaptorToSignature,
|
|
@@ -84,6 +73,15 @@ import {
|
|
|
84
73
|
import {
|
|
85
74
|
getCrypto
|
|
86
75
|
} from "./chunk-QNNSEJ4P.js";
|
|
76
|
+
import {
|
|
77
|
+
BitcoinNetwork_default
|
|
78
|
+
} from "./chunk-HMLOC6TE.js";
|
|
79
|
+
import {
|
|
80
|
+
ConnectionManager
|
|
81
|
+
} from "./chunk-PQN3C2MF.js";
|
|
82
|
+
import {
|
|
83
|
+
isReactNative
|
|
84
|
+
} from "./chunk-7V6N75CC.js";
|
|
87
85
|
import {
|
|
88
86
|
AuthenticationError,
|
|
89
87
|
ConfigurationError,
|
|
@@ -91,6 +89,10 @@ import {
|
|
|
91
89
|
RPCError,
|
|
92
90
|
ValidationError
|
|
93
91
|
} from "./chunk-GSI4OLXZ.js";
|
|
92
|
+
import {
|
|
93
|
+
SendLeafKeyTweaks,
|
|
94
|
+
networkToJSON
|
|
95
|
+
} from "./chunk-BGGEVUJK.js";
|
|
94
96
|
import {
|
|
95
97
|
Buffer
|
|
96
98
|
} from "./chunk-MVRQ5US7.js";
|
|
@@ -104,7 +106,7 @@ import {
|
|
|
104
106
|
hexToBytes as hexToBytes7,
|
|
105
107
|
numberToVarBytesBE
|
|
106
108
|
} from "@noble/curves/abstract/utils";
|
|
107
|
-
import { secp256k1 as
|
|
109
|
+
import { secp256k1 as secp256k15 } from "@noble/curves/secp256k1";
|
|
108
110
|
import { validateMnemonic } from "@scure/bip39";
|
|
109
111
|
import { wordlist } from "@scure/bip39/wordlists/english";
|
|
110
112
|
import { Address as Address4, OutScript as OutScript4, Transaction as Transaction6 } from "@scure/btc-signer";
|
|
@@ -126,7 +128,7 @@ var ClaimStaticDepositOutputFromJson = (obj) => {
|
|
|
126
128
|
transferId: obj["claim_static_deposit_output_transfer_id"]
|
|
127
129
|
};
|
|
128
130
|
};
|
|
129
|
-
var
|
|
131
|
+
var FRAGMENT7 = `
|
|
130
132
|
fragment ClaimStaticDepositOutputFragment on ClaimStaticDepositOutput {
|
|
131
133
|
__typename
|
|
132
134
|
claim_static_deposit_output_transfer_id: transfer_id
|
|
@@ -159,7 +161,7 @@ var ClaimStaticDeposit = `
|
|
|
159
161
|
}
|
|
160
162
|
}
|
|
161
163
|
|
|
162
|
-
${
|
|
164
|
+
${FRAGMENT7}
|
|
163
165
|
`;
|
|
164
166
|
|
|
165
167
|
// src/graphql/objects/CoopExitRequest.ts
|
|
@@ -185,7 +187,7 @@ var CoopExitRequestFromJson = (obj) => {
|
|
|
185
187
|
transfer: !!obj["coop_exit_request_transfer"] ? TransferFromJson(obj["coop_exit_request_transfer"]) : void 0
|
|
186
188
|
};
|
|
187
189
|
};
|
|
188
|
-
var
|
|
190
|
+
var FRAGMENT8 = `
|
|
189
191
|
fragment CoopExitRequestFragment on CoopExitRequest {
|
|
190
192
|
__typename
|
|
191
193
|
coop_exit_request_id: id
|
|
@@ -250,7 +252,7 @@ var CompleteCoopExit = `
|
|
|
250
252
|
}
|
|
251
253
|
}
|
|
252
254
|
|
|
253
|
-
${
|
|
255
|
+
${FRAGMENT8}
|
|
254
256
|
`;
|
|
255
257
|
|
|
256
258
|
// src/graphql/mutations/CompleteLeavesSwap.ts
|
|
@@ -276,7 +278,7 @@ var GetChallengeOutputFromJson = (obj) => {
|
|
|
276
278
|
protectedChallenge: obj["get_challenge_output_protected_challenge"]
|
|
277
279
|
};
|
|
278
280
|
};
|
|
279
|
-
var
|
|
281
|
+
var FRAGMENT9 = `
|
|
280
282
|
fragment GetChallengeOutputFragment on GetChallengeOutput {
|
|
281
283
|
__typename
|
|
282
284
|
get_challenge_output_protected_challenge: protected_challenge
|
|
@@ -294,7 +296,7 @@ var GetChallenge = `
|
|
|
294
296
|
}
|
|
295
297
|
}
|
|
296
298
|
|
|
297
|
-
${
|
|
299
|
+
${FRAGMENT9}
|
|
298
300
|
`;
|
|
299
301
|
|
|
300
302
|
// src/graphql/mutations/RequestCoopExit.ts
|
|
@@ -304,6 +306,9 @@ var RequestCoopExit = `
|
|
|
304
306
|
$withdrawal_address: String!
|
|
305
307
|
$idempotency_key: String!
|
|
306
308
|
$exit_speed: ExitSpeed!
|
|
309
|
+
$withdraw_all: Boolean
|
|
310
|
+
$fee_leaf_external_ids: [UUID!]
|
|
311
|
+
$fee_quote_id: ID
|
|
307
312
|
) {
|
|
308
313
|
request_coop_exit(
|
|
309
314
|
input: {
|
|
@@ -311,6 +316,9 @@ var RequestCoopExit = `
|
|
|
311
316
|
withdrawal_address: $withdrawal_address
|
|
312
317
|
idempotency_key: $idempotency_key
|
|
313
318
|
exit_speed: $exit_speed
|
|
319
|
+
withdraw_all: $withdraw_all
|
|
320
|
+
fee_leaf_external_ids: $fee_leaf_external_ids
|
|
321
|
+
fee_quote_id: $fee_quote_id
|
|
314
322
|
}
|
|
315
323
|
) {
|
|
316
324
|
request {
|
|
@@ -318,7 +326,7 @@ var RequestCoopExit = `
|
|
|
318
326
|
}
|
|
319
327
|
}
|
|
320
328
|
}
|
|
321
|
-
${
|
|
329
|
+
${FRAGMENT8}
|
|
322
330
|
`;
|
|
323
331
|
|
|
324
332
|
// src/graphql/mutations/RequestLightningReceive.ts
|
|
@@ -382,6 +390,7 @@ var RequestSwapLeaves = `
|
|
|
382
390
|
$fee_sats: Long!
|
|
383
391
|
$user_leaves: [UserLeafInput!]!
|
|
384
392
|
$idempotency_key: String!
|
|
393
|
+
$target_amount_sats_list: [Long!]
|
|
385
394
|
) {
|
|
386
395
|
request_leaves_swap(input: {
|
|
387
396
|
adaptor_pubkey: $adaptor_pubkey
|
|
@@ -390,6 +399,7 @@ var RequestSwapLeaves = `
|
|
|
390
399
|
fee_sats: $fee_sats
|
|
391
400
|
user_leaves: $user_leaves
|
|
392
401
|
idempotency_key: $idempotency_key
|
|
402
|
+
target_amount_sats_list: $target_amount_sats_list
|
|
393
403
|
}) {
|
|
394
404
|
request {
|
|
395
405
|
...LeavesSwapRequestFragment
|
|
@@ -406,7 +416,7 @@ var VerifyChallengeOutputFromJson = (obj) => {
|
|
|
406
416
|
sessionToken: obj["verify_challenge_output_session_token"]
|
|
407
417
|
};
|
|
408
418
|
};
|
|
409
|
-
var
|
|
419
|
+
var FRAGMENT10 = `
|
|
410
420
|
fragment VerifyChallengeOutputFragment on VerifyChallengeOutput {
|
|
411
421
|
__typename
|
|
412
422
|
verify_challenge_output_valid_until: valid_until
|
|
@@ -431,7 +441,7 @@ var VerifyChallenge = `
|
|
|
431
441
|
}
|
|
432
442
|
}
|
|
433
443
|
|
|
434
|
-
${
|
|
444
|
+
${FRAGMENT10}
|
|
435
445
|
`;
|
|
436
446
|
|
|
437
447
|
// src/graphql/objects/CoopExitFeeEstimate.ts
|
|
@@ -450,7 +460,7 @@ var CoopExitFeeEstimatesOutputFromJson = (obj) => {
|
|
|
450
460
|
speedSlow: !!obj["coop_exit_fee_estimates_output_speed_slow"] ? CoopExitFeeEstimateFromJson(obj["coop_exit_fee_estimates_output_speed_slow"]) : void 0
|
|
451
461
|
};
|
|
452
462
|
};
|
|
453
|
-
var
|
|
463
|
+
var FRAGMENT11 = `
|
|
454
464
|
fragment CoopExitFeeEstimatesOutputFragment on CoopExitFeeEstimatesOutput {
|
|
455
465
|
__typename
|
|
456
466
|
coop_exit_fee_estimates_output_speed_fast: speed_fast {
|
|
@@ -518,7 +528,7 @@ var LeavesSwapFeeEstimateOutputFromJson = (obj) => {
|
|
|
518
528
|
feeEstimate: CurrencyAmountFromJson(obj["leaves_swap_fee_estimate_output_fee_estimate"])
|
|
519
529
|
};
|
|
520
530
|
};
|
|
521
|
-
var
|
|
531
|
+
var FRAGMENT12 = `
|
|
522
532
|
fragment LeavesSwapFeeEstimateOutputFragment on LeavesSwapFeeEstimateOutput {
|
|
523
533
|
__typename
|
|
524
534
|
leaves_swap_fee_estimate_output_fee_estimate: fee_estimate {
|
|
@@ -537,7 +547,7 @@ var LightningSendFeeEstimateOutputFromJson = (obj) => {
|
|
|
537
547
|
feeEstimate: CurrencyAmountFromJson(obj["lightning_send_fee_estimate_output_fee_estimate"])
|
|
538
548
|
};
|
|
539
549
|
};
|
|
540
|
-
var
|
|
550
|
+
var FRAGMENT13 = `
|
|
541
551
|
fragment LightningSendFeeEstimateOutputFragment on LightningSendFeeEstimateOutput {
|
|
542
552
|
__typename
|
|
543
553
|
lightning_send_fee_estimate_output_fee_estimate: fee_estimate {
|
|
@@ -560,7 +570,7 @@ var StaticDepositQuoteOutputFromJson = (obj) => {
|
|
|
560
570
|
signature: obj["static_deposit_quote_output_signature"]
|
|
561
571
|
};
|
|
562
572
|
};
|
|
563
|
-
var
|
|
573
|
+
var FRAGMENT14 = `
|
|
564
574
|
fragment StaticDepositQuoteOutputFragment on StaticDepositQuoteOutput {
|
|
565
575
|
__typename
|
|
566
576
|
static_deposit_quote_output_transaction_id: transaction_id
|
|
@@ -585,7 +595,7 @@ var CoopExitFeeEstimate2 = `
|
|
|
585
595
|
...CoopExitFeeEstimatesOutputFragment
|
|
586
596
|
}
|
|
587
597
|
}
|
|
588
|
-
${
|
|
598
|
+
${FRAGMENT11}
|
|
589
599
|
`;
|
|
590
600
|
|
|
591
601
|
// src/graphql/queries/GetClaimDepositQuote.ts
|
|
@@ -605,7 +615,27 @@ var GetClaimDepositQuote = `
|
|
|
605
615
|
...StaticDepositQuoteOutputFragment
|
|
606
616
|
}
|
|
607
617
|
}
|
|
608
|
-
${
|
|
618
|
+
${FRAGMENT14}
|
|
619
|
+
`;
|
|
620
|
+
|
|
621
|
+
// src/graphql/queries/GetCoopExitFeeQuote.ts
|
|
622
|
+
var GetCoopExitFeeQuote = `
|
|
623
|
+
query CoopExitFeeQuote(
|
|
624
|
+
$leaf_external_ids: [UUID!]!
|
|
625
|
+
$withdrawal_address: String!
|
|
626
|
+
) {
|
|
627
|
+
coop_exit_fee_quote(
|
|
628
|
+
input: {
|
|
629
|
+
leaf_external_ids: $leaf_external_ids,
|
|
630
|
+
withdrawal_address: $withdrawal_address
|
|
631
|
+
}
|
|
632
|
+
) {
|
|
633
|
+
quote {
|
|
634
|
+
...CoopExitFeeQuoteFragment
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
${FRAGMENT5}
|
|
609
639
|
`;
|
|
610
640
|
|
|
611
641
|
// src/graphql/queries/LeavesSwapFeeEstimate.ts
|
|
@@ -621,7 +651,7 @@ var LeavesSwapFeeEstimate = `
|
|
|
621
651
|
...LeavesSwapFeeEstimateOutputFragment
|
|
622
652
|
}
|
|
623
653
|
}
|
|
624
|
-
${
|
|
654
|
+
${FRAGMENT12}
|
|
625
655
|
`;
|
|
626
656
|
|
|
627
657
|
// src/graphql/queries/LightningSendFeeEstimate.ts
|
|
@@ -639,7 +669,7 @@ var LightningSendFeeEstimate = `
|
|
|
639
669
|
...LightningSendFeeEstimateOutputFragment
|
|
640
670
|
}
|
|
641
671
|
}
|
|
642
|
-
${
|
|
672
|
+
${FRAGMENT13}
|
|
643
673
|
`;
|
|
644
674
|
|
|
645
675
|
// src/graphql/queries/Transfer.ts
|
|
@@ -659,7 +689,7 @@ var UserRequest = `
|
|
|
659
689
|
...UserRequestFragment
|
|
660
690
|
}
|
|
661
691
|
}
|
|
662
|
-
${
|
|
692
|
+
${FRAGMENT6}
|
|
663
693
|
`;
|
|
664
694
|
|
|
665
695
|
// src/graphql/client.ts
|
|
@@ -781,7 +811,10 @@ var SspClient = class {
|
|
|
781
811
|
leafExternalIds,
|
|
782
812
|
withdrawalAddress,
|
|
783
813
|
idempotencyKey,
|
|
784
|
-
exitSpeed
|
|
814
|
+
exitSpeed,
|
|
815
|
+
feeLeafExternalIds,
|
|
816
|
+
feeQuoteId,
|
|
817
|
+
withdrawAll
|
|
785
818
|
}) {
|
|
786
819
|
return await this.executeRawQuery({
|
|
787
820
|
queryPayload: RequestCoopExit,
|
|
@@ -789,7 +822,10 @@ var SspClient = class {
|
|
|
789
822
|
leaf_external_ids: leafExternalIds,
|
|
790
823
|
withdrawal_address: withdrawalAddress,
|
|
791
824
|
idempotency_key: idempotencyKey,
|
|
792
|
-
exit_speed: exitSpeed
|
|
825
|
+
exit_speed: exitSpeed,
|
|
826
|
+
fee_leaf_external_ids: feeLeafExternalIds,
|
|
827
|
+
fee_quote_id: feeQuoteId,
|
|
828
|
+
withdraw_all: withdrawAll
|
|
793
829
|
},
|
|
794
830
|
constructObject: (response) => {
|
|
795
831
|
return CoopExitRequestFromJson(response.request_coop_exit.request);
|
|
@@ -851,7 +887,8 @@ var SspClient = class {
|
|
|
851
887
|
targetAmountSats,
|
|
852
888
|
feeSats,
|
|
853
889
|
userLeaves,
|
|
854
|
-
idempotencyKey
|
|
890
|
+
idempotencyKey,
|
|
891
|
+
targetAmountSatsList
|
|
855
892
|
}) {
|
|
856
893
|
const query = {
|
|
857
894
|
queryPayload: RequestSwapLeaves,
|
|
@@ -861,7 +898,8 @@ var SspClient = class {
|
|
|
861
898
|
target_amount_sats: targetAmountSats,
|
|
862
899
|
fee_sats: feeSats,
|
|
863
900
|
user_leaves: userLeaves,
|
|
864
|
-
idempotency_key: idempotencyKey
|
|
901
|
+
idempotency_key: idempotencyKey,
|
|
902
|
+
target_amount_sats_list: targetAmountSatsList
|
|
865
903
|
},
|
|
866
904
|
constructObject: (response) => {
|
|
867
905
|
if (!response.request_leaves_swap) {
|
|
@@ -1053,6 +1091,21 @@ var SspClient = class {
|
|
|
1053
1091
|
new Date(verifyChallenge.validUntil)
|
|
1054
1092
|
);
|
|
1055
1093
|
}
|
|
1094
|
+
async getCoopExitFeeQuote({
|
|
1095
|
+
leafExternalIds,
|
|
1096
|
+
withdrawalAddress
|
|
1097
|
+
}) {
|
|
1098
|
+
return await this.executeRawQuery({
|
|
1099
|
+
queryPayload: GetCoopExitFeeQuote,
|
|
1100
|
+
variables: {
|
|
1101
|
+
leaf_external_ids: leafExternalIds,
|
|
1102
|
+
withdrawal_address: withdrawalAddress
|
|
1103
|
+
},
|
|
1104
|
+
constructObject: (response) => {
|
|
1105
|
+
return CoopExitFeeQuoteFromJson(response.coop_exit_fee_quote.quote);
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1056
1109
|
};
|
|
1057
1110
|
var SparkAuthProvider = class {
|
|
1058
1111
|
sessionToken;
|
|
@@ -1263,7 +1316,10 @@ var BaseTransferService = class {
|
|
|
1263
1316
|
const transferPackage = {
|
|
1264
1317
|
leavesToSend: leafSigningJobs,
|
|
1265
1318
|
keyTweakPackage: encryptedKeyTweaks,
|
|
1266
|
-
userSignature: new Uint8Array()
|
|
1319
|
+
userSignature: new Uint8Array(),
|
|
1320
|
+
// TODO: Add direct refund signature
|
|
1321
|
+
directLeavesToSend: [],
|
|
1322
|
+
directFromCpfpLeavesToSend: []
|
|
1267
1323
|
};
|
|
1268
1324
|
const transferPackageSigningPayload = getTransferPackageSigningPayload(
|
|
1269
1325
|
transferID,
|
|
@@ -1362,7 +1418,11 @@ var BaseTransferService = class {
|
|
|
1362
1418
|
nodeSignatures.push({
|
|
1363
1419
|
nodeId: operatorSigningResult.leafId,
|
|
1364
1420
|
refundTxSignature: refundAggregate,
|
|
1365
|
-
nodeTxSignature: new Uint8Array()
|
|
1421
|
+
nodeTxSignature: new Uint8Array(),
|
|
1422
|
+
// TODO: Add direct refund signature
|
|
1423
|
+
directNodeTxSignature: new Uint8Array(),
|
|
1424
|
+
directRefundTxSignature: new Uint8Array(),
|
|
1425
|
+
directFromCpfpRefundTxSignature: new Uint8Array()
|
|
1366
1426
|
});
|
|
1367
1427
|
}
|
|
1368
1428
|
return nodeSignatures;
|
|
@@ -1444,7 +1504,10 @@ var BaseTransferService = class {
|
|
|
1444
1504
|
pubkeySharesTweak: Object.fromEntries(pubkeySharesTweak),
|
|
1445
1505
|
secretCipher,
|
|
1446
1506
|
signature,
|
|
1447
|
-
refundSignature: refundSignature ?? new Uint8Array()
|
|
1507
|
+
refundSignature: refundSignature ?? new Uint8Array(),
|
|
1508
|
+
// TODO: Add direct refund signature
|
|
1509
|
+
directRefundSignature: new Uint8Array(),
|
|
1510
|
+
directFromCpfpRefundSignature: new Uint8Array()
|
|
1448
1511
|
});
|
|
1449
1512
|
}
|
|
1450
1513
|
return leafTweaksMap;
|
|
@@ -1726,7 +1789,11 @@ var TransferService = class extends BaseTransferService {
|
|
|
1726
1789
|
signingPublicKey: refundSigningData.signingPubKey,
|
|
1727
1790
|
rawTx: refundTx.toBytes(),
|
|
1728
1791
|
signingNonceCommitment: refundNonceCommitmentProto
|
|
1729
|
-
}
|
|
1792
|
+
},
|
|
1793
|
+
// TODO: Add direct refund signature
|
|
1794
|
+
directRefundTxSigningJob: void 0,
|
|
1795
|
+
// TODO: Add direct refund signature
|
|
1796
|
+
directFromCpfpRefundTxSigningJob: void 0
|
|
1730
1797
|
});
|
|
1731
1798
|
}
|
|
1732
1799
|
return signingJobs;
|
|
@@ -2093,7 +2160,11 @@ var TransferService = class extends BaseTransferService {
|
|
|
2093
2160
|
nodeSignatures.push({
|
|
2094
2161
|
nodeId,
|
|
2095
2162
|
nodeTxSignature: signature,
|
|
2096
|
-
refundTxSignature: new Uint8Array()
|
|
2163
|
+
refundTxSignature: new Uint8Array(),
|
|
2164
|
+
// TODO: Add direct refund signature
|
|
2165
|
+
directNodeTxSignature: new Uint8Array(),
|
|
2166
|
+
directRefundTxSignature: new Uint8Array(),
|
|
2167
|
+
directFromCpfpRefundTxSignature: new Uint8Array()
|
|
2097
2168
|
});
|
|
2098
2169
|
} else if (i === nodes.length) {
|
|
2099
2170
|
refundSignature = signature;
|
|
@@ -2108,7 +2179,11 @@ var TransferService = class extends BaseTransferService {
|
|
|
2108
2179
|
nodeSignatures.push({
|
|
2109
2180
|
nodeId: leafNodeId,
|
|
2110
2181
|
nodeTxSignature: leafSignature,
|
|
2111
|
-
refundTxSignature: refundSignature
|
|
2182
|
+
refundTxSignature: refundSignature,
|
|
2183
|
+
// TODO: Add direct refund signature
|
|
2184
|
+
directNodeTxSignature: new Uint8Array(),
|
|
2185
|
+
directRefundTxSignature: new Uint8Array(),
|
|
2186
|
+
directFromCpfpRefundTxSignature: new Uint8Array()
|
|
2112
2187
|
});
|
|
2113
2188
|
const result = await sparkClient.finalize_node_signatures({
|
|
2114
2189
|
intent: 3 /* REFRESH */,
|
|
@@ -2425,7 +2500,10 @@ var CoopExitService = class extends BaseTransferService {
|
|
|
2425
2500
|
signingPublicKey: leaf.signingPubKey,
|
|
2426
2501
|
rawTx: refundTx.toBytes(),
|
|
2427
2502
|
signingNonceCommitment
|
|
2428
|
-
}
|
|
2503
|
+
},
|
|
2504
|
+
// TODO: Add direct refund signature
|
|
2505
|
+
directRefundTxSigningJob: void 0,
|
|
2506
|
+
directFromCpfpRefundTxSigningJob: void 0
|
|
2429
2507
|
};
|
|
2430
2508
|
signingJobs.push(signingJob);
|
|
2431
2509
|
const tx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
|
|
@@ -2798,98 +2876,58 @@ import {
|
|
|
2798
2876
|
hexToBytes as hexToBytes3,
|
|
2799
2877
|
numberToBytesBE as numberToBytesBE2
|
|
2800
2878
|
} from "@noble/curves/abstract/utils";
|
|
2801
|
-
import { secp256k1 as
|
|
2802
|
-
import { sha256 as
|
|
2879
|
+
import { secp256k1 as secp256k13 } from "@noble/curves/secp256k1";
|
|
2880
|
+
import { sha256 as sha2564 } from "@noble/hashes/sha2";
|
|
2803
2881
|
import { uuidv7 as uuidv73 } from "uuidv7";
|
|
2804
2882
|
|
|
2805
2883
|
// src/services/bolt11-spark.ts
|
|
2806
|
-
import {
|
|
2807
|
-
|
|
2808
|
-
|
|
2884
|
+
import { decode } from "light-bolt11-decoder";
|
|
2885
|
+
var RECEIVER_IDENTITY_PUBLIC_KEY_SHORT_CHANNEL_ID = "f42400f424000001";
|
|
2886
|
+
var PAYMENT_HASH_NAME = "payment_hash";
|
|
2887
|
+
var AMOUNT_MSATS_NAME = "amount";
|
|
2888
|
+
var PAYMENT_SECRET_NAME = "payment_secret";
|
|
2809
2889
|
function decodeInvoice(invoice) {
|
|
2810
|
-
const
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
let
|
|
2817
|
-
let
|
|
2818
|
-
let
|
|
2819
|
-
let
|
|
2820
|
-
const
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
} else if (tag === 9) {
|
|
2839
|
-
const verWord = words[start];
|
|
2840
|
-
if (verWord !== 31) {
|
|
2841
|
-
console.warn("Not our custom version-31");
|
|
2842
|
-
i = end;
|
|
2843
|
-
continue;
|
|
2844
|
-
}
|
|
2845
|
-
const payloadWords = words.slice(start + 1, end);
|
|
2846
|
-
const payloadBytes = bech32WordsToBytes(payloadWords);
|
|
2847
|
-
fallbackAddress = Buffer.from(payloadBytes).toString("hex");
|
|
2848
|
-
} else if (tag === 16) {
|
|
2849
|
-
if (len !== 52) {
|
|
2850
|
-
throw new ValidationError("Invalid payment secret length", {
|
|
2851
|
-
field: "paymentSecret",
|
|
2852
|
-
value: len,
|
|
2853
|
-
expected: "52 words (32 bytes for 256-bit secret)"
|
|
2854
|
-
});
|
|
2855
|
-
}
|
|
2856
|
-
const secretWords = words.slice(start, end);
|
|
2857
|
-
const secretBytes = bech32WordsToBytes(secretWords);
|
|
2858
|
-
if (secretBytes.length !== 32) {
|
|
2859
|
-
throw new ValidationError("Invalid payment secret size", {
|
|
2860
|
-
field: "paymentSecret",
|
|
2861
|
-
value: secretBytes.length,
|
|
2862
|
-
expected: "32 bytes (256 bits)"
|
|
2863
|
-
});
|
|
2890
|
+
const decodedInvoice = decode(invoice);
|
|
2891
|
+
const network = getNetworkFromInvoice(invoice);
|
|
2892
|
+
if (network === null) {
|
|
2893
|
+
throw new ValidationError("Invalid network found in invoice: " + invoice);
|
|
2894
|
+
}
|
|
2895
|
+
let paymentSection;
|
|
2896
|
+
let routeHints = [];
|
|
2897
|
+
let amountSection;
|
|
2898
|
+
let paymentSecretSection;
|
|
2899
|
+
let fallbackAddress;
|
|
2900
|
+
for (const section of decodedInvoice.sections) {
|
|
2901
|
+
if (section.name === PAYMENT_HASH_NAME) {
|
|
2902
|
+
paymentSection = section;
|
|
2903
|
+
}
|
|
2904
|
+
if (section.name === AMOUNT_MSATS_NAME) {
|
|
2905
|
+
amountSection = section;
|
|
2906
|
+
}
|
|
2907
|
+
if (section.name === PAYMENT_SECRET_NAME) {
|
|
2908
|
+
paymentSecretSection = section;
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
routeHints = decodedInvoice.route_hints;
|
|
2912
|
+
const amountMSats = amountSection?.value ? BigInt(amountSection.value) : null;
|
|
2913
|
+
const paymentHash = paymentSection?.value;
|
|
2914
|
+
for (const routeHintArray of routeHints) {
|
|
2915
|
+
for (const routeHint of routeHintArray) {
|
|
2916
|
+
if (routeHint.short_channel_id === RECEIVER_IDENTITY_PUBLIC_KEY_SHORT_CHANNEL_ID) {
|
|
2917
|
+
fallbackAddress = routeHint.pubkey;
|
|
2864
2918
|
}
|
|
2865
|
-
paymentSecret = Buffer.from(secretBytes).toString("hex");
|
|
2866
2919
|
}
|
|
2867
|
-
i = end;
|
|
2868
2920
|
}
|
|
2869
2921
|
if (paymentHash === void 0) {
|
|
2870
2922
|
throw new ValidationError("No payment hash found in invoice: " + invoice);
|
|
2871
2923
|
}
|
|
2872
|
-
if (
|
|
2924
|
+
if (paymentSecretSection?.value === void 0) {
|
|
2873
2925
|
throw new ValidationError(
|
|
2874
2926
|
"Invalid payment secret found in invoice: " + invoice
|
|
2875
2927
|
);
|
|
2876
2928
|
}
|
|
2877
2929
|
return { amountMSats, fallbackAddress, paymentHash };
|
|
2878
2930
|
}
|
|
2879
|
-
function bech32WordsToBytes(words) {
|
|
2880
|
-
let acc = 0, bits = 0;
|
|
2881
|
-
const out = [];
|
|
2882
|
-
for (const w of words) {
|
|
2883
|
-
if (w < 0 || w > 31) throw new Error(`bad word ${w}`);
|
|
2884
|
-
acc = acc << 5 | w;
|
|
2885
|
-
bits += 5;
|
|
2886
|
-
while (bits >= 8) {
|
|
2887
|
-
bits -= 8;
|
|
2888
|
-
out.push(acc >> bits & 255);
|
|
2889
|
-
}
|
|
2890
|
-
}
|
|
2891
|
-
return new Uint8Array(out);
|
|
2892
|
-
}
|
|
2893
2931
|
function getNetworkFromInvoice(invoice) {
|
|
2894
2932
|
if (invoice.startsWith("lnbcrt")) return 3 /* REGTEST */;
|
|
2895
2933
|
if (invoice.startsWith("lnbc")) return 0 /* MAINNET */;
|
|
@@ -2897,85 +2935,11 @@ function getNetworkFromInvoice(invoice) {
|
|
|
2897
2935
|
if (invoice.startsWith("lnsb")) return 2 /* SIGNET */;
|
|
2898
2936
|
return null;
|
|
2899
2937
|
}
|
|
2900
|
-
function extractMillisatoshiAmountFromInvoice(invoice) {
|
|
2901
|
-
const match = invoice.match(/^ln[a-z]+(\d+)([a-z]?)1/);
|
|
2902
|
-
if (!match) return null;
|
|
2903
|
-
const [, amount, multiplier] = match;
|
|
2904
|
-
if (!amount) return null;
|
|
2905
|
-
const value = BigInt(amount);
|
|
2906
|
-
const MILLISATS_PER_BTC = 100000000000n;
|
|
2907
|
-
const divisors = {
|
|
2908
|
-
m: 1000n,
|
|
2909
|
-
u: 1000000n,
|
|
2910
|
-
n: 1000000000n,
|
|
2911
|
-
p: 10000000000000n
|
|
2912
|
-
};
|
|
2913
|
-
if (multiplier) {
|
|
2914
|
-
if (!(multiplier in divisors)) {
|
|
2915
|
-
throw new ValidationError(`Invalid multiplier: ${multiplier}`, {
|
|
2916
|
-
field: "multiplier",
|
|
2917
|
-
value: multiplier,
|
|
2918
|
-
expected: "valid bolt11 multiplier: m, u, n, p"
|
|
2919
|
-
});
|
|
2920
|
-
}
|
|
2921
|
-
const divisor = divisors[multiplier];
|
|
2922
|
-
if (value * MILLISATS_PER_BTC % divisor !== 0n) {
|
|
2923
|
-
throw new ValidationError("Invalid submillisatoshi precision", {
|
|
2924
|
-
field: "amount",
|
|
2925
|
-
value: `${amount}${multiplier}`,
|
|
2926
|
-
expected: "amount must result in whole millisatoshis"
|
|
2927
|
-
});
|
|
2928
|
-
}
|
|
2929
|
-
return value * MILLISATS_PER_BTC / divisor;
|
|
2930
|
-
} else {
|
|
2931
|
-
return value * MILLISATS_PER_BTC;
|
|
2932
|
-
}
|
|
2933
|
-
}
|
|
2934
|
-
function hasSparkHeader(bytes) {
|
|
2935
|
-
if (bytes.length < 3) {
|
|
2936
|
-
return false;
|
|
2937
|
-
}
|
|
2938
|
-
return bytes[0] === 83 && // 'S'
|
|
2939
|
-
bytes[1] === 80 && // 'P'
|
|
2940
|
-
bytes[2] === 75;
|
|
2941
|
-
}
|
|
2942
2938
|
function isValidSparkFallback(bytes) {
|
|
2943
|
-
if (bytes.length !==
|
|
2939
|
+
if (bytes.length !== 33) {
|
|
2944
2940
|
return false;
|
|
2945
2941
|
}
|
|
2946
|
-
return
|
|
2947
|
-
}
|
|
2948
|
-
function verifySignature(words, prefix) {
|
|
2949
|
-
if (words.length < 104) {
|
|
2950
|
-
throw new ValidationError("Invoice too short for signature");
|
|
2951
|
-
}
|
|
2952
|
-
const signatureStart = words.length - 104;
|
|
2953
|
-
const signatureEnd = words.length - 1;
|
|
2954
|
-
const hrp = prefix;
|
|
2955
|
-
const hrpBytes = new TextEncoder().encode(hrp);
|
|
2956
|
-
const dataWords = words.slice(0, signatureStart);
|
|
2957
|
-
const dataBytes = bech32WordsToBytes(dataWords);
|
|
2958
|
-
const sigWords = words.slice(signatureStart, signatureEnd);
|
|
2959
|
-
const sigBytes = bech32WordsToBytes(sigWords);
|
|
2960
|
-
if (sigBytes.length !== 64) {
|
|
2961
|
-
throw new ValidationError("Invalid signature length");
|
|
2962
|
-
}
|
|
2963
|
-
const recoveryId = words[words.length - 1];
|
|
2964
|
-
if (recoveryId === void 0) {
|
|
2965
|
-
throw new ValidationError("Missing recovery ID in signature");
|
|
2966
|
-
}
|
|
2967
|
-
const messageBytes = new Uint8Array(hrpBytes.length + dataBytes.length);
|
|
2968
|
-
messageBytes.set(hrpBytes, 0);
|
|
2969
|
-
messageBytes.set(dataBytes, hrpBytes.length);
|
|
2970
|
-
const messageHash = sha2564(messageBytes);
|
|
2971
|
-
try {
|
|
2972
|
-
const signature = secp256k13.Signature.fromCompact(sigBytes).addRecoveryBit(recoveryId);
|
|
2973
|
-
signature.recoverPublicKey(messageHash);
|
|
2974
|
-
} catch (error) {
|
|
2975
|
-
throw new ValidationError(
|
|
2976
|
-
`Invalid BOLT11 signature: ${error.message}`
|
|
2977
|
-
);
|
|
2978
|
-
}
|
|
2942
|
+
return true;
|
|
2979
2943
|
}
|
|
2980
2944
|
|
|
2981
2945
|
// src/services/lightning.ts
|
|
@@ -2998,7 +2962,7 @@ var LightningService = class {
|
|
|
2998
2962
|
}) {
|
|
2999
2963
|
const randBytes = crypto.getRandomValues(new Uint8Array(32));
|
|
3000
2964
|
const preimage = numberToBytesBE2(
|
|
3001
|
-
bytesToNumberBE(randBytes) %
|
|
2965
|
+
bytesToNumberBE(randBytes) % secp256k13.CURVE.n,
|
|
3002
2966
|
32
|
|
3003
2967
|
);
|
|
3004
2968
|
return await this.createLightningInvoiceWithPreImage({
|
|
@@ -3018,7 +2982,7 @@ var LightningService = class {
|
|
|
3018
2982
|
receiverIdentityPubkey,
|
|
3019
2983
|
descriptionHash
|
|
3020
2984
|
}) {
|
|
3021
|
-
const paymentHash =
|
|
2985
|
+
const paymentHash = sha2564(preimage);
|
|
3022
2986
|
const invoice = await invoiceCreator(
|
|
3023
2987
|
amountSats,
|
|
3024
2988
|
paymentHash,
|
|
@@ -3035,7 +2999,7 @@ var LightningService = class {
|
|
|
3035
2999
|
}
|
|
3036
3000
|
const shares = await this.config.signer.splitSecretWithProofs({
|
|
3037
3001
|
secret: preimage,
|
|
3038
|
-
curveOrder:
|
|
3002
|
+
curveOrder: secp256k13.CURVE.n,
|
|
3039
3003
|
threshold: this.config.getThreshold(),
|
|
3040
3004
|
numShares: Object.keys(this.config.getSigningOperators()).length
|
|
3041
3005
|
});
|
|
@@ -3215,7 +3179,7 @@ var LightningService = class {
|
|
|
3215
3179
|
const sparkClient = await this.connectionManager.createSparkClient(
|
|
3216
3180
|
this.config.getCoordinatorAddress()
|
|
3217
3181
|
);
|
|
3218
|
-
const paymentHash =
|
|
3182
|
+
const paymentHash = sha2564(preimage);
|
|
3219
3183
|
let response;
|
|
3220
3184
|
try {
|
|
3221
3185
|
response = await sparkClient.provide_preimage({
|
|
@@ -3247,10 +3211,10 @@ var LightningService = class {
|
|
|
3247
3211
|
|
|
3248
3212
|
// src/services/tree-creation.ts
|
|
3249
3213
|
import { hexToBytes as hexToBytes4 } from "@noble/curves/abstract/utils";
|
|
3250
|
-
import { sha256 as
|
|
3214
|
+
import { sha256 as sha2565 } from "@noble/hashes/sha2";
|
|
3251
3215
|
import { Address as Address2, OutScript as OutScript2, Transaction as Transaction4 } from "@scure/btc-signer";
|
|
3252
3216
|
var INITIAL_TIME_LOCK3 = 2e3;
|
|
3253
|
-
function
|
|
3217
|
+
function maybeApplyFee(amount) {
|
|
3254
3218
|
if (amount > BigInt(DEFAULT_FEE_SATS)) {
|
|
3255
3219
|
return amount - BigInt(DEFAULT_FEE_SATS);
|
|
3256
3220
|
}
|
|
@@ -3403,7 +3367,7 @@ var TreeCreationService = class {
|
|
|
3403
3367
|
return finalizeResp;
|
|
3404
3368
|
}
|
|
3405
3369
|
async createDepositAddressTree(targetSigningPublicKey, nodeId) {
|
|
3406
|
-
const leftKey = await this.config.signer.generatePublicKey(
|
|
3370
|
+
const leftKey = await this.config.signer.generatePublicKey(sha2565(nodeId));
|
|
3407
3371
|
const leftNode = {
|
|
3408
3372
|
signingPublicKey: leftKey,
|
|
3409
3373
|
children: []
|
|
@@ -3452,7 +3416,10 @@ var TreeCreationService = class {
|
|
|
3452
3416
|
const internalCreationNode = {
|
|
3453
3417
|
nodeTxSigningJob: void 0,
|
|
3454
3418
|
refundTxSigningJob: void 0,
|
|
3455
|
-
children: []
|
|
3419
|
+
children: [],
|
|
3420
|
+
directNodeTxSigningJob: void 0,
|
|
3421
|
+
directRefundTxSigningJob: void 0,
|
|
3422
|
+
directFromCpfpRefundTxSigningJob: void 0
|
|
3456
3423
|
};
|
|
3457
3424
|
const tx = new Transaction4({ version: 3 });
|
|
3458
3425
|
tx.addInput({
|
|
@@ -3481,7 +3448,10 @@ var TreeCreationService = class {
|
|
|
3481
3448
|
const childCreationNode = {
|
|
3482
3449
|
nodeTxSigningJob: void 0,
|
|
3483
3450
|
refundTxSigningJob: void 0,
|
|
3484
|
-
children: []
|
|
3451
|
+
children: [],
|
|
3452
|
+
directNodeTxSigningJob: void 0,
|
|
3453
|
+
directRefundTxSigningJob: void 0,
|
|
3454
|
+
directFromCpfpRefundTxSigningJob: void 0
|
|
3485
3455
|
};
|
|
3486
3456
|
const childTx = new Transaction4({ version: 3 });
|
|
3487
3457
|
childTx.addInput({
|
|
@@ -3519,7 +3489,7 @@ var TreeCreationService = class {
|
|
|
3519
3489
|
const refundPkScript = OutScript2.encode(refundAddress);
|
|
3520
3490
|
refundTx.addOutput({
|
|
3521
3491
|
script: refundPkScript,
|
|
3522
|
-
amount:
|
|
3492
|
+
amount: maybeApplyFee(parentTxOut.amount)
|
|
3523
3493
|
});
|
|
3524
3494
|
refundTx.addOutput(getEphemeralAnchorOutput());
|
|
3525
3495
|
const refundSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
|
|
@@ -3566,7 +3536,10 @@ var TreeCreationService = class {
|
|
|
3566
3536
|
const rootCreationNode = {
|
|
3567
3537
|
nodeTxSigningJob: rootNodeSigningJob,
|
|
3568
3538
|
refundTxSigningJob: void 0,
|
|
3569
|
-
children: []
|
|
3539
|
+
children: [],
|
|
3540
|
+
directNodeTxSigningJob: void 0,
|
|
3541
|
+
directRefundTxSigningJob: void 0,
|
|
3542
|
+
directFromCpfpRefundTxSigningJob: void 0
|
|
3570
3543
|
};
|
|
3571
3544
|
rootCreationNode.nodeTxSigningCommitment = rootNodeSigningCommitment;
|
|
3572
3545
|
const leftChild = root.children[0];
|
|
@@ -3656,7 +3629,11 @@ var TreeCreationService = class {
|
|
|
3656
3629
|
signature: {
|
|
3657
3630
|
nodeId: creationResponseNode.nodeId,
|
|
3658
3631
|
nodeTxSignature,
|
|
3659
|
-
refundTxSignature
|
|
3632
|
+
refundTxSignature,
|
|
3633
|
+
// TODO: Add direct refund signature
|
|
3634
|
+
directNodeTxSignature: new Uint8Array(),
|
|
3635
|
+
directRefundTxSignature: new Uint8Array(),
|
|
3636
|
+
directFromCpfpRefundTxSignature: new Uint8Array()
|
|
3660
3637
|
}
|
|
3661
3638
|
};
|
|
3662
3639
|
}
|
|
@@ -3708,7 +3685,7 @@ var TreeCreationService = class {
|
|
|
3708
3685
|
|
|
3709
3686
|
// src/spark-wallet/spark-wallet.ts
|
|
3710
3687
|
import { LRCWallet } from "@buildonspark/lrc20-sdk";
|
|
3711
|
-
import { sha256 as
|
|
3688
|
+
import { sha256 as sha2566 } from "@noble/hashes/sha2";
|
|
3712
3689
|
import { EventEmitter } from "eventemitter3";
|
|
3713
3690
|
|
|
3714
3691
|
// src/services/signing.ts
|
|
@@ -3789,7 +3766,7 @@ var SigningService = class {
|
|
|
3789
3766
|
|
|
3790
3767
|
// src/tests/utils/test-faucet.ts
|
|
3791
3768
|
import { bytesToHex as bytesToHex3, hexToBytes as hexToBytes6 } from "@noble/curves/abstract/utils";
|
|
3792
|
-
import { schnorr as schnorr2, secp256k1 as
|
|
3769
|
+
import { schnorr as schnorr2, secp256k1 as secp256k14 } from "@noble/curves/secp256k1";
|
|
3793
3770
|
import * as btc2 from "@scure/btc-signer";
|
|
3794
3771
|
import { Address as Address3, OutScript as OutScript3, SigHash, Transaction as Transaction5 } from "@scure/btc-signer";
|
|
3795
3772
|
import { taprootTweakPrivKey } from "@scure/btc-signer/utils";
|
|
@@ -3809,7 +3786,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
3809
3786
|
this.username = username;
|
|
3810
3787
|
this.password = password;
|
|
3811
3788
|
this.miningAddress = getP2TRAddressFromPublicKey(
|
|
3812
|
-
|
|
3789
|
+
secp256k14.getPublicKey(STATIC_MINING_KEY),
|
|
3813
3790
|
4 /* LOCAL */
|
|
3814
3791
|
);
|
|
3815
3792
|
}
|
|
@@ -3848,7 +3825,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
3848
3825
|
});
|
|
3849
3826
|
}
|
|
3850
3827
|
async refill() {
|
|
3851
|
-
const minerPubKey =
|
|
3828
|
+
const minerPubKey = secp256k14.getPublicKey(STATIC_MINING_KEY);
|
|
3852
3829
|
const address = getP2TRAddressFromPublicKey(minerPubKey, 4 /* LOCAL */);
|
|
3853
3830
|
const scanResult = await this.call("scantxoutset", [
|
|
3854
3831
|
"start",
|
|
@@ -3897,7 +3874,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
3897
3874
|
txid: selectedUtxo.txid,
|
|
3898
3875
|
index: selectedUtxo.vout
|
|
3899
3876
|
});
|
|
3900
|
-
const faucetPubKey =
|
|
3877
|
+
const faucetPubKey = secp256k14.getPublicKey(STATIC_FAUCET_KEY);
|
|
3901
3878
|
const script = getP2TRScriptFromPublicKey(faucetPubKey, 4 /* LOCAL */);
|
|
3902
3879
|
for (let i = 0; i < numCoinsToCreate; i++) {
|
|
3903
3880
|
splitTx.addOutput({
|
|
@@ -3958,7 +3935,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
3958
3935
|
await this.broadcastTx(bytesToHex3(signedTx.extract()));
|
|
3959
3936
|
}
|
|
3960
3937
|
async signFaucetCoin(unsignedTx, fundingTxOut, key) {
|
|
3961
|
-
const pubKey =
|
|
3938
|
+
const pubKey = secp256k14.getPublicKey(key);
|
|
3962
3939
|
const internalKey = pubKey.slice(1);
|
|
3963
3940
|
const script = getP2TRScriptFromPublicKey(pubKey, 4 /* LOCAL */);
|
|
3964
3941
|
unsignedTx.updateInput(0, {
|
|
@@ -4040,8 +4017,8 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
4040
4017
|
return response;
|
|
4041
4018
|
}
|
|
4042
4019
|
async getNewAddress() {
|
|
4043
|
-
const key =
|
|
4044
|
-
const pubKey =
|
|
4020
|
+
const key = secp256k14.utils.randomPrivateKey();
|
|
4021
|
+
const pubKey = secp256k14.getPublicKey(key);
|
|
4045
4022
|
return getP2TRAddressFromPublicKey(pubKey, 4 /* LOCAL */);
|
|
4046
4023
|
}
|
|
4047
4024
|
async sendToAddress(address, amount) {
|
|
@@ -4062,8 +4039,8 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
4062
4039
|
});
|
|
4063
4040
|
const changeAmount = availableAmount - amount;
|
|
4064
4041
|
if (changeAmount > 0) {
|
|
4065
|
-
const changeKey =
|
|
4066
|
-
const changePubKey =
|
|
4042
|
+
const changeKey = secp256k14.utils.randomPrivateKey();
|
|
4043
|
+
const changePubKey = secp256k14.getPublicKey(changeKey);
|
|
4067
4044
|
const changeScript = getP2TRScriptFromPublicKey(
|
|
4068
4045
|
changePubKey,
|
|
4069
4046
|
4 /* LOCAL */
|
|
@@ -4076,8 +4053,8 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
4076
4053
|
const signedTx = await this.signFaucetCoin(tx, coin.txout, coin.key);
|
|
4077
4054
|
const txHex = bytesToHex3(signedTx.extract());
|
|
4078
4055
|
await this.broadcastTx(txHex);
|
|
4079
|
-
const randomKey =
|
|
4080
|
-
const randomPubKey =
|
|
4056
|
+
const randomKey = secp256k14.utils.randomPrivateKey();
|
|
4057
|
+
const randomPubKey = secp256k14.getPublicKey(randomKey);
|
|
4081
4058
|
const randomAddress = getP2TRAddressFromPublicKey(
|
|
4082
4059
|
randomPubKey,
|
|
4083
4060
|
4 /* LOCAL */
|
|
@@ -4099,6 +4076,35 @@ function chunkArray(arr, size) {
|
|
|
4099
4076
|
return chunks;
|
|
4100
4077
|
}
|
|
4101
4078
|
|
|
4079
|
+
// src/utils/token-identifier.ts
|
|
4080
|
+
import { bech32m } from "@scure/base";
|
|
4081
|
+
var HumanReadableTokenIdentifierNetworkPrefix = {
|
|
4082
|
+
MAINNET: "btk",
|
|
4083
|
+
REGTEST: "btkrt",
|
|
4084
|
+
TESTNET: "btkt",
|
|
4085
|
+
SIGNET: "btks",
|
|
4086
|
+
LOCAL: "btkl"
|
|
4087
|
+
};
|
|
4088
|
+
function encodeHumanReadableTokenIdentifier(payload) {
|
|
4089
|
+
try {
|
|
4090
|
+
const words = bech32m.toWords(payload.tokenIdentifier);
|
|
4091
|
+
return bech32m.encode(
|
|
4092
|
+
HumanReadableTokenIdentifierNetworkPrefix[payload.network],
|
|
4093
|
+
words,
|
|
4094
|
+
500
|
|
4095
|
+
);
|
|
4096
|
+
} catch (error) {
|
|
4097
|
+
throw new ValidationError(
|
|
4098
|
+
"Failed to encode human readable token identifier",
|
|
4099
|
+
{
|
|
4100
|
+
field: "tokenIdentifier",
|
|
4101
|
+
value: payload.tokenIdentifier
|
|
4102
|
+
},
|
|
4103
|
+
error
|
|
4104
|
+
);
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
|
|
4102
4108
|
// src/spark-wallet/spark-wallet.ts
|
|
4103
4109
|
var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
4104
4110
|
config;
|
|
@@ -4209,7 +4215,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4209
4215
|
} else if (event?.$case === "deposit" && event.deposit.deposit) {
|
|
4210
4216
|
const deposit = event.deposit.deposit;
|
|
4211
4217
|
const signingKey = await this.config.signer.generatePublicKey(
|
|
4212
|
-
|
|
4218
|
+
sha2566(deposit.id)
|
|
4213
4219
|
);
|
|
4214
4220
|
const newLeaf = await this.transferService.extendTimelock(
|
|
4215
4221
|
deposit,
|
|
@@ -4364,7 +4370,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4364
4370
|
if (leaf.status !== operatorLeaf.status || !leaf.signingKeyshare || !operatorLeaf.signingKeyshare || !equalBytes3(
|
|
4365
4371
|
leaf.signingKeyshare.publicKey,
|
|
4366
4372
|
operatorLeaf.signingKeyshare.publicKey
|
|
4367
|
-
) || !equalBytes3(leaf.nodeTx, operatorLeaf.nodeTx)
|
|
4373
|
+
) || !equalBytes3(leaf.nodeTx, operatorLeaf.nodeTx)) {
|
|
4368
4374
|
leavesToIgnore.add(nodeId);
|
|
4369
4375
|
}
|
|
4370
4376
|
}
|
|
@@ -4376,7 +4382,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4376
4382
|
};
|
|
4377
4383
|
for (const [id, leaf] of Object.entries(leaves.nodes)) {
|
|
4378
4384
|
if (!verifyKey(
|
|
4379
|
-
await this.config.signer.generatePublicKey(
|
|
4385
|
+
await this.config.signer.generatePublicKey(sha2566(leaf.id)),
|
|
4380
4386
|
leaf.signingKeyshare?.publicKey ?? new Uint8Array(),
|
|
4381
4387
|
leaf.verifyingPublicKey
|
|
4382
4388
|
)) {
|
|
@@ -4387,13 +4393,34 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4387
4393
|
([_, node]) => node.status === "AVAILABLE" && !leavesToIgnore.has(node.id)
|
|
4388
4394
|
).map(([_, node]) => node);
|
|
4389
4395
|
}
|
|
4390
|
-
async selectLeaves(
|
|
4391
|
-
if (
|
|
4396
|
+
async selectLeaves(targetAmounts) {
|
|
4397
|
+
if (targetAmounts.length === 0) {
|
|
4398
|
+
throw new ValidationError("Target amounts must be non-empty", {
|
|
4399
|
+
field: "targetAmounts",
|
|
4400
|
+
value: targetAmounts
|
|
4401
|
+
});
|
|
4402
|
+
}
|
|
4403
|
+
if (targetAmounts.some((amount) => amount <= 0)) {
|
|
4392
4404
|
throw new ValidationError("Target amount must be positive", {
|
|
4393
|
-
field: "
|
|
4394
|
-
value:
|
|
4405
|
+
field: "targetAmounts",
|
|
4406
|
+
value: targetAmounts
|
|
4395
4407
|
});
|
|
4396
4408
|
}
|
|
4409
|
+
const totalTargetAmount = targetAmounts.reduce(
|
|
4410
|
+
(acc, amount) => acc + amount,
|
|
4411
|
+
0
|
|
4412
|
+
);
|
|
4413
|
+
const totalBalance = this.getInternalBalance();
|
|
4414
|
+
if (totalTargetAmount > totalBalance) {
|
|
4415
|
+
throw new ValidationError(
|
|
4416
|
+
"Total target amount exceeds available balance",
|
|
4417
|
+
{
|
|
4418
|
+
field: "targetAmounts",
|
|
4419
|
+
value: totalTargetAmount,
|
|
4420
|
+
expected: `less than or equal to ${totalBalance}`
|
|
4421
|
+
}
|
|
4422
|
+
);
|
|
4423
|
+
}
|
|
4397
4424
|
const leaves = await this.getLeaves();
|
|
4398
4425
|
if (leaves.length === 0) {
|
|
4399
4426
|
throw new ValidationError("No owned leaves found", {
|
|
@@ -4401,33 +4428,49 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4401
4428
|
});
|
|
4402
4429
|
}
|
|
4403
4430
|
leaves.sort((a, b) => b.value - a.value);
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
nodes
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
amount += leaf.value;
|
|
4421
|
-
nodes.push(leaf);
|
|
4431
|
+
const selectLeavesForTargets = (targetAmounts2, leaves2) => {
|
|
4432
|
+
const usedLeaves = /* @__PURE__ */ new Set();
|
|
4433
|
+
const results2 = /* @__PURE__ */ new Map();
|
|
4434
|
+
let totalAmount = 0;
|
|
4435
|
+
for (const targetAmount of targetAmounts2) {
|
|
4436
|
+
const nodes = [];
|
|
4437
|
+
let amount = 0;
|
|
4438
|
+
for (const leaf of leaves2) {
|
|
4439
|
+
if (usedLeaves.has(leaf.id)) {
|
|
4440
|
+
continue;
|
|
4441
|
+
}
|
|
4442
|
+
if (targetAmount - amount >= leaf.value) {
|
|
4443
|
+
amount += leaf.value;
|
|
4444
|
+
nodes.push(leaf);
|
|
4445
|
+
usedLeaves.add(leaf.id);
|
|
4446
|
+
}
|
|
4422
4447
|
}
|
|
4448
|
+
totalAmount += amount;
|
|
4449
|
+
results2.set(targetAmount, nodes);
|
|
4423
4450
|
}
|
|
4451
|
+
return {
|
|
4452
|
+
results: results2,
|
|
4453
|
+
foundSelections: totalAmount === totalTargetAmount
|
|
4454
|
+
};
|
|
4455
|
+
};
|
|
4456
|
+
let { results, foundSelections } = selectLeavesForTargets(
|
|
4457
|
+
targetAmounts,
|
|
4458
|
+
leaves
|
|
4459
|
+
);
|
|
4460
|
+
if (!foundSelections) {
|
|
4461
|
+
const newLeaves = await this.requestLeavesSwap({ targetAmounts });
|
|
4462
|
+
newLeaves.sort((a, b) => b.value - a.value);
|
|
4463
|
+
({ results, foundSelections } = selectLeavesForTargets(
|
|
4464
|
+
targetAmounts,
|
|
4465
|
+
newLeaves
|
|
4466
|
+
));
|
|
4424
4467
|
}
|
|
4425
|
-
if (
|
|
4468
|
+
if (!foundSelections) {
|
|
4426
4469
|
throw new Error(
|
|
4427
|
-
`Failed to select leaves for target amount ${
|
|
4470
|
+
`Failed to select leaves for target amount ${totalTargetAmount}`
|
|
4428
4471
|
);
|
|
4429
4472
|
}
|
|
4430
|
-
return
|
|
4473
|
+
return results;
|
|
4431
4474
|
}
|
|
4432
4475
|
async selectLeavesForSwap(targetAmount) {
|
|
4433
4476
|
if (targetAmount == 0) {
|
|
@@ -4660,27 +4703,44 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4660
4703
|
* @private
|
|
4661
4704
|
*/
|
|
4662
4705
|
async requestLeavesSwap({
|
|
4663
|
-
|
|
4706
|
+
targetAmounts,
|
|
4664
4707
|
leaves
|
|
4665
4708
|
}) {
|
|
4666
|
-
if (
|
|
4667
|
-
throw new Error("targetAmount must be positive");
|
|
4709
|
+
if (targetAmounts && targetAmounts.some((amount) => amount <= 0)) {
|
|
4710
|
+
throw new Error("specified targetAmount must be positive");
|
|
4668
4711
|
}
|
|
4669
|
-
if (
|
|
4712
|
+
if (targetAmounts && targetAmounts.some((amount) => !Number.isSafeInteger(amount))) {
|
|
4670
4713
|
throw new ValidationError("targetAmount must be less than 2^53", {
|
|
4671
|
-
field: "
|
|
4672
|
-
value:
|
|
4714
|
+
field: "targetAmounts",
|
|
4715
|
+
value: targetAmounts,
|
|
4673
4716
|
expected: "smaller or equal to " + Number.MAX_SAFE_INTEGER
|
|
4674
4717
|
});
|
|
4675
4718
|
}
|
|
4676
4719
|
let leavesToSwap;
|
|
4677
|
-
|
|
4678
|
-
|
|
4720
|
+
const totalTargetAmount = targetAmounts?.reduce(
|
|
4721
|
+
(acc, amount) => acc + amount,
|
|
4722
|
+
0
|
|
4723
|
+
);
|
|
4724
|
+
if (totalTargetAmount) {
|
|
4725
|
+
const totalBalance = this.getInternalBalance();
|
|
4726
|
+
if (totalTargetAmount > totalBalance) {
|
|
4727
|
+
throw new ValidationError(
|
|
4728
|
+
"Total target amount exceeds available balance",
|
|
4729
|
+
{
|
|
4730
|
+
field: "targetAmounts",
|
|
4731
|
+
value: totalTargetAmount,
|
|
4732
|
+
expected: `less than or equal to ${totalBalance}`
|
|
4733
|
+
}
|
|
4734
|
+
);
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
if (totalTargetAmount && leaves && leaves.length > 0) {
|
|
4738
|
+
if (totalTargetAmount < leaves.reduce((acc, leaf) => acc + leaf.value, 0)) {
|
|
4679
4739
|
throw new Error("targetAmount is less than the sum of leaves");
|
|
4680
4740
|
}
|
|
4681
4741
|
leavesToSwap = leaves;
|
|
4682
|
-
} else if (
|
|
4683
|
-
leavesToSwap = await this.selectLeavesForSwap(
|
|
4742
|
+
} else if (totalTargetAmount) {
|
|
4743
|
+
leavesToSwap = await this.selectLeavesForSwap(totalTargetAmount);
|
|
4684
4744
|
} else if (leaves && leaves.length > 0) {
|
|
4685
4745
|
leavesToSwap = leaves;
|
|
4686
4746
|
} else {
|
|
@@ -4690,20 +4750,20 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4690
4750
|
const batches = chunkArray(leavesToSwap, 100);
|
|
4691
4751
|
const results = [];
|
|
4692
4752
|
for (const batch of batches) {
|
|
4693
|
-
const result = await this.processSwapBatch(batch,
|
|
4694
|
-
results.push(...result
|
|
4753
|
+
const result = await this.processSwapBatch(batch, targetAmounts);
|
|
4754
|
+
results.push(...result);
|
|
4695
4755
|
}
|
|
4696
4756
|
return results;
|
|
4697
4757
|
}
|
|
4698
4758
|
/**
|
|
4699
4759
|
* Processes a single batch of leaves for swapping.
|
|
4700
4760
|
*/
|
|
4701
|
-
async processSwapBatch(leavesBatch,
|
|
4761
|
+
async processSwapBatch(leavesBatch, targetAmounts) {
|
|
4702
4762
|
const leafKeyTweaks = await Promise.all(
|
|
4703
4763
|
leavesBatch.map(async (leaf) => ({
|
|
4704
4764
|
leaf,
|
|
4705
4765
|
signingPubKey: await this.config.signer.generatePublicKey(
|
|
4706
|
-
|
|
4766
|
+
sha2566(leaf.id)
|
|
4707
4767
|
),
|
|
4708
4768
|
newSigningPubKey: await this.config.signer.generatePublicKey()
|
|
4709
4769
|
}))
|
|
@@ -4756,14 +4816,15 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4756
4816
|
}
|
|
4757
4817
|
const sspClient = this.getSspClient();
|
|
4758
4818
|
const adaptorPubkey = bytesToHex4(
|
|
4759
|
-
|
|
4819
|
+
secp256k15.getPublicKey(adaptorPrivateKey)
|
|
4760
4820
|
);
|
|
4761
4821
|
let request = null;
|
|
4762
4822
|
request = await sspClient.requestLeaveSwap({
|
|
4763
4823
|
userLeaves,
|
|
4764
4824
|
adaptorPubkey,
|
|
4765
|
-
targetAmountSats:
|
|
4825
|
+
targetAmountSats: targetAmounts?.reduce((acc, amount) => acc + amount, 0) || leavesBatch.reduce((acc, leaf) => acc + leaf.value, 0),
|
|
4766
4826
|
totalAmountSats: leavesBatch.reduce((acc, leaf) => acc + leaf.value, 0),
|
|
4827
|
+
targetAmountSatsList: targetAmounts,
|
|
4767
4828
|
// TODO: Request fee from SSP
|
|
4768
4829
|
feeSats: 0,
|
|
4769
4830
|
idempotencyKey: uuidv74()
|
|
@@ -4819,11 +4880,21 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4819
4880
|
userOutboundTransferExternalId: transfer.id,
|
|
4820
4881
|
leavesSwapRequestId: request.id
|
|
4821
4882
|
});
|
|
4822
|
-
if (!completeResponse) {
|
|
4883
|
+
if (!completeResponse || !completeResponse.inboundTransfer?.sparkId) {
|
|
4823
4884
|
throw new Error("Failed to complete leaves swap");
|
|
4824
4885
|
}
|
|
4825
|
-
await this.
|
|
4826
|
-
|
|
4886
|
+
const incomingTransfer = await this.transferService.queryTransfer(
|
|
4887
|
+
completeResponse.inboundTransfer.sparkId
|
|
4888
|
+
);
|
|
4889
|
+
if (!incomingTransfer) {
|
|
4890
|
+
throw new Error("Failed to get incoming transfer");
|
|
4891
|
+
}
|
|
4892
|
+
return await this.claimTransfer({
|
|
4893
|
+
transfer: incomingTransfer,
|
|
4894
|
+
emit: false,
|
|
4895
|
+
retryCount: 0,
|
|
4896
|
+
optimize: false
|
|
4897
|
+
});
|
|
4827
4898
|
} catch (e) {
|
|
4828
4899
|
await this.cancelAllSenderInitiatedTransfers();
|
|
4829
4900
|
throw new Error(`Failed to request leaves swap: ${e}`);
|
|
@@ -4851,27 +4922,6 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4851
4922
|
offset: transfers.offset
|
|
4852
4923
|
};
|
|
4853
4924
|
}
|
|
4854
|
-
/**
|
|
4855
|
-
* Gets the held token info for the wallet.
|
|
4856
|
-
*
|
|
4857
|
-
* @deprecated The information is returned in getBalance
|
|
4858
|
-
*/
|
|
4859
|
-
async getTokenInfo() {
|
|
4860
|
-
console.warn("getTokenInfo is deprecated. Use getBalance instead.");
|
|
4861
|
-
await this.syncTokenOutputs();
|
|
4862
|
-
const lrc20Client = await this.lrc20ConnectionManager.createLrc20Client();
|
|
4863
|
-
const { balance, tokenBalances } = await this.getBalance();
|
|
4864
|
-
const tokenInfo = await lrc20Client.getTokenPubkeyInfo({
|
|
4865
|
-
publicKeys: Array.from(tokenBalances.keys()).map(hexToBytes7)
|
|
4866
|
-
});
|
|
4867
|
-
return tokenInfo.tokenPubkeyInfos.map((info) => ({
|
|
4868
|
-
tokenPublicKey: bytesToHex4(info.announcement.publicKey.publicKey),
|
|
4869
|
-
tokenName: info.announcement.name,
|
|
4870
|
-
tokenSymbol: info.announcement.symbol,
|
|
4871
|
-
tokenDecimals: Number(bytesToNumberBE2(info.announcement.decimal)),
|
|
4872
|
-
maxSupply: bytesToNumberBE2(info.announcement.maxSupply)
|
|
4873
|
-
}));
|
|
4874
|
-
}
|
|
4875
4925
|
/**
|
|
4876
4926
|
* Gets the current balance of the wallet.
|
|
4877
4927
|
* You can use the forceRefetch option to synchronize your wallet and claim any
|
|
@@ -4879,7 +4929,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4879
4929
|
*
|
|
4880
4930
|
* @returns {Promise<Object>} Object containing:
|
|
4881
4931
|
* - balance: The wallet's current balance in satoshis
|
|
4882
|
-
* - tokenBalances: Map of token
|
|
4932
|
+
* - tokenBalances: Map of the human readable token identifier to token balances and token info
|
|
4883
4933
|
*/
|
|
4884
4934
|
async getBalance() {
|
|
4885
4935
|
const leaves = await this.getLeaves(true);
|
|
@@ -4896,24 +4946,29 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4896
4946
|
};
|
|
4897
4947
|
}
|
|
4898
4948
|
async getTokenBalance() {
|
|
4899
|
-
const
|
|
4900
|
-
|
|
4901
|
-
|
|
4949
|
+
const sparkTokenClient = await this.connectionManager.createSparkTokenClient(
|
|
4950
|
+
this.config.getCoordinatorAddress()
|
|
4951
|
+
);
|
|
4952
|
+
const tokenMetadata = await sparkTokenClient.query_token_metadata({
|
|
4953
|
+
issuerPublicKeys: Array.from(this.tokenOutputs.keys()).map(hexToBytes7)
|
|
4902
4954
|
});
|
|
4903
4955
|
const result = /* @__PURE__ */ new Map();
|
|
4904
|
-
for (const
|
|
4905
|
-
const tokenPublicKey = bytesToHex4(
|
|
4906
|
-
info.announcement.publicKey.publicKey
|
|
4907
|
-
);
|
|
4956
|
+
for (const metadata of tokenMetadata.tokenMetadata) {
|
|
4957
|
+
const tokenPublicKey = bytesToHex4(metadata.issuerPublicKey);
|
|
4908
4958
|
const leaves = this.tokenOutputs.get(tokenPublicKey);
|
|
4909
|
-
|
|
4959
|
+
const humanReadableTokenIdentifier = encodeHumanReadableTokenIdentifier({
|
|
4960
|
+
tokenIdentifier: metadata.tokenIdentifier,
|
|
4961
|
+
network: this.config.getNetworkType()
|
|
4962
|
+
});
|
|
4963
|
+
result.set(humanReadableTokenIdentifier, {
|
|
4910
4964
|
balance: leaves ? calculateAvailableTokenAmount(leaves) : BigInt(0),
|
|
4911
|
-
|
|
4965
|
+
tokenMetadata: {
|
|
4912
4966
|
tokenPublicKey,
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4967
|
+
rawTokenIdentifier: metadata.tokenIdentifier,
|
|
4968
|
+
tokenName: metadata.tokenName,
|
|
4969
|
+
tokenTicker: metadata.tokenTicker,
|
|
4970
|
+
decimals: metadata.decimals,
|
|
4971
|
+
maxSupply: bytesToNumberBE2(metadata.maxSupply)
|
|
4917
4972
|
}
|
|
4918
4973
|
});
|
|
4919
4974
|
}
|
|
@@ -4971,7 +5026,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
4971
5026
|
signingPubkey = await this.config.signer.generateStaticDepositKey(0);
|
|
4972
5027
|
} else {
|
|
4973
5028
|
signingPubkey = await this.config.signer.generatePublicKey(
|
|
4974
|
-
|
|
5029
|
+
sha2566(leafId)
|
|
4975
5030
|
);
|
|
4976
5031
|
}
|
|
4977
5032
|
const address = await this.depositService.generateDepositAddress({
|
|
@@ -5058,7 +5113,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5058
5113
|
creditAmountSats,
|
|
5059
5114
|
sspSignature
|
|
5060
5115
|
);
|
|
5061
|
-
const hashBuffer =
|
|
5116
|
+
const hashBuffer = sha2566(message);
|
|
5062
5117
|
const signatureBytes = await this.config.signer.signMessageWithIdentityKey(hashBuffer);
|
|
5063
5118
|
const signature = bytesToHex4(signatureBytes);
|
|
5064
5119
|
const response = await this.sspClient.claimStaticDeposit({
|
|
@@ -5147,7 +5202,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5147
5202
|
creditAmountSats,
|
|
5148
5203
|
bytesToHex4(spendTxSighash)
|
|
5149
5204
|
);
|
|
5150
|
-
const hashBuffer =
|
|
5205
|
+
const hashBuffer = sha2566(message);
|
|
5151
5206
|
const swapResponseUserSignature = await this.config.signer.signMessageWithIdentityKey(hashBuffer);
|
|
5152
5207
|
const sparkClient = await this.connectionManager.createSparkClient(
|
|
5153
5208
|
this.config.getCoordinatorAddress()
|
|
@@ -5360,13 +5415,45 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5360
5415
|
* @returns {Promise<string[]>} The unused deposit addresses
|
|
5361
5416
|
*/
|
|
5362
5417
|
async getUnusedDepositAddresses() {
|
|
5418
|
+
return (await this.queryAllUnusedDepositAddresses({})).map(
|
|
5419
|
+
(addr) => addr.depositAddress
|
|
5420
|
+
);
|
|
5421
|
+
}
|
|
5422
|
+
/**
|
|
5423
|
+
* Gets all unused deposit addresses for the wallet.
|
|
5424
|
+
*
|
|
5425
|
+
* @param {Object} params - Parameters for querying unused deposit addresses
|
|
5426
|
+
* @param {Uint8Array<ArrayBufferLike>} [params.identityPublicKey] - The identity public key
|
|
5427
|
+
* @param {NetworkProto} [params.network] - The network
|
|
5428
|
+
* @returns {Promise<DepositAddressQueryResult[]>} The unused deposit addresses
|
|
5429
|
+
*/
|
|
5430
|
+
async queryAllUnusedDepositAddresses({
|
|
5431
|
+
identityPublicKey,
|
|
5432
|
+
network
|
|
5433
|
+
}) {
|
|
5363
5434
|
const sparkClient = await this.connectionManager.createSparkClient(
|
|
5364
5435
|
this.config.getCoordinatorAddress()
|
|
5365
5436
|
);
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5437
|
+
let limit = 100;
|
|
5438
|
+
let offset = 0;
|
|
5439
|
+
const pastOffsets = /* @__PURE__ */ new Set();
|
|
5440
|
+
const depositAddresses = [];
|
|
5441
|
+
while (offset >= 0) {
|
|
5442
|
+
if (pastOffsets.has(offset)) {
|
|
5443
|
+
console.warn("Offset has already been seen, stopping");
|
|
5444
|
+
break;
|
|
5445
|
+
}
|
|
5446
|
+
const response = await sparkClient.query_unused_deposit_addresses({
|
|
5447
|
+
identityPublicKey: identityPublicKey ?? await this.config.signer.getIdentityPublicKey(),
|
|
5448
|
+
network: network ?? NetworkToProto[this.config.getNetwork()],
|
|
5449
|
+
limit,
|
|
5450
|
+
offset
|
|
5451
|
+
});
|
|
5452
|
+
depositAddresses.push(...response.depositAddresses);
|
|
5453
|
+
pastOffsets.add(offset);
|
|
5454
|
+
offset = response.offset;
|
|
5455
|
+
}
|
|
5456
|
+
return depositAddresses;
|
|
5370
5457
|
}
|
|
5371
5458
|
/**
|
|
5372
5459
|
* Claims a deposit to the wallet.
|
|
@@ -5415,14 +5502,11 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5415
5502
|
});
|
|
5416
5503
|
}
|
|
5417
5504
|
const depositTx = getTxFromRawTxHex(txHex);
|
|
5418
|
-
const sparkClient = await this.connectionManager.createSparkClient(
|
|
5419
|
-
this.config.getCoordinatorAddress()
|
|
5420
|
-
);
|
|
5421
5505
|
const unusedDepositAddresses = new Map(
|
|
5422
|
-
(await
|
|
5506
|
+
(await this.queryAllUnusedDepositAddresses({
|
|
5423
5507
|
identityPublicKey: await this.config.signer.getIdentityPublicKey(),
|
|
5424
5508
|
network: NetworkToProto[this.config.getNetwork()]
|
|
5425
|
-
})).
|
|
5509
|
+
})).map((addr) => [addr.depositAddress, addr])
|
|
5426
5510
|
);
|
|
5427
5511
|
let depositAddress;
|
|
5428
5512
|
let vout = 0;
|
|
@@ -5452,7 +5536,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5452
5536
|
signingPubKey = depositAddress.userSigningPublicKey;
|
|
5453
5537
|
} else {
|
|
5454
5538
|
signingPubKey = await this.config.signer.generatePublicKey(
|
|
5455
|
-
|
|
5539
|
+
sha2566(depositAddress.leafId)
|
|
5456
5540
|
);
|
|
5457
5541
|
}
|
|
5458
5542
|
const nodes2 = await this.finalizeDeposit({
|
|
@@ -5476,14 +5560,11 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5476
5560
|
*/
|
|
5477
5561
|
async advancedDeposit(txHex) {
|
|
5478
5562
|
const depositTx = getTxFromRawTxHex(txHex);
|
|
5479
|
-
const sparkClient = await this.connectionManager.createSparkClient(
|
|
5480
|
-
this.config.getCoordinatorAddress()
|
|
5481
|
-
);
|
|
5482
5563
|
const unusedDepositAddresses = new Map(
|
|
5483
|
-
(await
|
|
5564
|
+
(await this.queryAllUnusedDepositAddresses({
|
|
5484
5565
|
identityPublicKey: await this.config.signer.getIdentityPublicKey(),
|
|
5485
5566
|
network: NetworkToProto[this.config.getNetwork()]
|
|
5486
|
-
})).
|
|
5567
|
+
})).map((addr) => [addr.depositAddress, addr])
|
|
5487
5568
|
);
|
|
5488
5569
|
let vout = 0;
|
|
5489
5570
|
const responses = [];
|
|
@@ -5587,14 +5668,16 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5587
5668
|
hexToBytes7(receiverAddress.identityPublicKey)
|
|
5588
5669
|
);
|
|
5589
5670
|
return await this.withLeaves(async () => {
|
|
5590
|
-
let leavesToSend = await this.selectLeaves(amountSats)
|
|
5671
|
+
let leavesToSend = (await this.selectLeaves([amountSats])).get(
|
|
5672
|
+
amountSats
|
|
5673
|
+
);
|
|
5591
5674
|
leavesToSend = await this.checkRefreshTimelockNodes(leavesToSend);
|
|
5592
5675
|
leavesToSend = await this.checkExtendTimeLockNodes(leavesToSend);
|
|
5593
5676
|
const leafKeyTweaks = await Promise.all(
|
|
5594
5677
|
leavesToSend.map(async (leaf) => ({
|
|
5595
5678
|
leaf,
|
|
5596
5679
|
signingPubKey: await this.config.signer.generatePublicKey(
|
|
5597
|
-
|
|
5680
|
+
sha2566(leaf.id)
|
|
5598
5681
|
),
|
|
5599
5682
|
newSigningPubKey: await this.config.signer.generatePublicKey()
|
|
5600
5683
|
}))
|
|
@@ -5643,7 +5726,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5643
5726
|
const nodesToAdd = [];
|
|
5644
5727
|
for (const node of nodesToExtend) {
|
|
5645
5728
|
const signingPubKey = await this.config.signer.generatePublicKey(
|
|
5646
|
-
|
|
5729
|
+
sha2566(node.id)
|
|
5647
5730
|
);
|
|
5648
5731
|
const { nodes: nodes2 } = await this.transferService.extendTimelock(
|
|
5649
5732
|
node,
|
|
@@ -5710,7 +5793,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5710
5793
|
const { nodes: nodes2 } = await this.transferService.refreshTimelockNodes(
|
|
5711
5794
|
[node],
|
|
5712
5795
|
parentNode,
|
|
5713
|
-
await this.config.signer.generatePublicKey(
|
|
5796
|
+
await this.config.signer.generatePublicKey(sha2566(node.id))
|
|
5714
5797
|
);
|
|
5715
5798
|
if (nodes2.length !== 1) {
|
|
5716
5799
|
throw new Error(`expected 1 node, got ${nodes2.length}`);
|
|
@@ -5762,7 +5845,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5762
5845
|
},
|
|
5763
5846
|
signingPubKey: leafPubKey,
|
|
5764
5847
|
newSigningPubKey: await this.config.signer.generatePublicKey(
|
|
5765
|
-
|
|
5848
|
+
sha2566(leaf.leaf.id)
|
|
5766
5849
|
)
|
|
5767
5850
|
});
|
|
5768
5851
|
}
|
|
@@ -5830,7 +5913,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5830
5913
|
if (type && transfer.type !== type) {
|
|
5831
5914
|
continue;
|
|
5832
5915
|
}
|
|
5833
|
-
if (transfer.status !== 2 /* TRANSFER_STATUS_SENDER_KEY_TWEAKED */ && transfer.status !== 3 /* TRANSFER_STATUS_RECEIVER_KEY_TWEAKED */ && transfer.status !== 4 /*
|
|
5916
|
+
if (transfer.status !== 2 /* TRANSFER_STATUS_SENDER_KEY_TWEAKED */ && transfer.status !== 3 /* TRANSFER_STATUS_RECEIVER_KEY_TWEAKED */ && transfer.status !== 4 /* TRANSFER_STATUS_RECEIVER_REFUND_SIGNED */ && transfer.status !== 10 /* TRANSFER_STATUS_RECEIVER_KEY_TWEAK_APPLIED */) {
|
|
5834
5917
|
continue;
|
|
5835
5918
|
}
|
|
5836
5919
|
promises.push(
|
|
@@ -5955,22 +6038,9 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5955
6038
|
const sparkFallbackAddress = decodeInvoice(
|
|
5956
6039
|
invoice2.invoice.encodedInvoice
|
|
5957
6040
|
).fallbackAddress;
|
|
5958
|
-
if (sparkFallbackAddress
|
|
5959
|
-
const invoiceIdentityPubkey = sparkFallbackAddress.slice(6);
|
|
5960
|
-
const expectedIdentityPubkey = receiverIdentityPubkey2 ?? await this.getIdentityPublicKey();
|
|
5961
|
-
if (invoiceIdentityPubkey !== expectedIdentityPubkey) {
|
|
5962
|
-
throw new ValidationError(
|
|
5963
|
-
"Mismatch between spark identity embedded in lightning invoice and designated recipient spark identity",
|
|
5964
|
-
{
|
|
5965
|
-
field: "sparkFallbackAddress",
|
|
5966
|
-
value: invoiceIdentityPubkey,
|
|
5967
|
-
expected: expectedIdentityPubkey
|
|
5968
|
-
}
|
|
5969
|
-
);
|
|
5970
|
-
}
|
|
5971
|
-
} else {
|
|
6041
|
+
if (!sparkFallbackAddress) {
|
|
5972
6042
|
throw new ValidationError(
|
|
5973
|
-
"No
|
|
6043
|
+
"No spark fallback address found in lightning invoice",
|
|
5974
6044
|
{
|
|
5975
6045
|
field: "sparkFallbackAddress",
|
|
5976
6046
|
value: sparkFallbackAddress,
|
|
@@ -5978,6 +6048,17 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
5978
6048
|
}
|
|
5979
6049
|
);
|
|
5980
6050
|
}
|
|
6051
|
+
const expectedIdentityPubkey = receiverIdentityPubkey2 ?? await this.getIdentityPublicKey();
|
|
6052
|
+
if (sparkFallbackAddress !== expectedIdentityPubkey) {
|
|
6053
|
+
throw new ValidationError(
|
|
6054
|
+
"Mismatch between spark identity embedded in lightning invoice and designated recipient spark identity",
|
|
6055
|
+
{
|
|
6056
|
+
field: "sparkFallbackAddress",
|
|
6057
|
+
value: sparkFallbackAddress,
|
|
6058
|
+
expected: expectedIdentityPubkey
|
|
6059
|
+
}
|
|
6060
|
+
);
|
|
6061
|
+
}
|
|
5981
6062
|
}
|
|
5982
6063
|
return invoice2;
|
|
5983
6064
|
};
|
|
@@ -6056,9 +6137,8 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6056
6137
|
"No valid spark address found in invoice. Defaulting to lightning."
|
|
6057
6138
|
);
|
|
6058
6139
|
} else {
|
|
6059
|
-
const identityPublicKey = sparkFallbackAddress.slice(6);
|
|
6060
6140
|
const receiverSparkAddress = encodeSparkAddress({
|
|
6061
|
-
identityPublicKey,
|
|
6141
|
+
identityPublicKey: sparkFallbackAddress,
|
|
6062
6142
|
network: Network[invoiceNetwork]
|
|
6063
6143
|
});
|
|
6064
6144
|
return await this.transfer({
|
|
@@ -6089,14 +6169,14 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6089
6169
|
expected: `${totalAmount} sats`
|
|
6090
6170
|
});
|
|
6091
6171
|
}
|
|
6092
|
-
let leaves = await this.selectLeaves(totalAmount);
|
|
6172
|
+
let leaves = (await this.selectLeaves([totalAmount])).get(totalAmount);
|
|
6093
6173
|
leaves = await this.checkRefreshTimelockNodes(leaves);
|
|
6094
6174
|
leaves = await this.checkExtendTimeLockNodes(leaves);
|
|
6095
6175
|
const leavesToSend = await Promise.all(
|
|
6096
6176
|
leaves.map(async (leaf) => ({
|
|
6097
6177
|
leaf,
|
|
6098
6178
|
signingPubKey: await this.config.signer.generatePublicKey(
|
|
6099
|
-
|
|
6179
|
+
sha2566(leaf.id)
|
|
6100
6180
|
),
|
|
6101
6181
|
newSigningPubKey: await this.config.signer.generatePublicKey()
|
|
6102
6182
|
}))
|
|
@@ -6199,13 +6279,18 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6199
6279
|
*
|
|
6200
6280
|
* @param {Object} params - Parameters for the withdrawal
|
|
6201
6281
|
* @param {string} params.onchainAddress - The Bitcoin address where the funds should be sent
|
|
6202
|
-
* @param {
|
|
6282
|
+
* @param {CoopExitFeeQuote} params.feeQuote - The fee quote for the withdrawal
|
|
6283
|
+
* @param {ExitSpeed} params.exitSpeed - The exit speed chosen for the withdrawal
|
|
6284
|
+
* @param {number} [params.amountSats] - The amount in satoshis to withdraw. If not specified, attempts to withdraw all available funds and deductFeeFromWithdrawalAmount is set to true.
|
|
6285
|
+
* @param {boolean} [params.deductFeeFromWithdrawalAmount] - Controls how the withdrawal fee is handled. If true, the fee is deducted from the withdrawal amount (amountSats), meaning the recipient will receive amountSats minus the fee. If false, the fee is paid separately from the wallet balance, meaning the recipient will receive the full amountSats.
|
|
6203
6286
|
* @returns {Promise<CoopExitRequest | null | undefined>} The withdrawal request details, or null/undefined if the request cannot be completed
|
|
6204
6287
|
*/
|
|
6205
6288
|
async withdraw({
|
|
6206
6289
|
onchainAddress,
|
|
6207
6290
|
exitSpeed,
|
|
6208
|
-
|
|
6291
|
+
feeQuote,
|
|
6292
|
+
amountSats,
|
|
6293
|
+
deductFeeFromWithdrawalAmount = true
|
|
6209
6294
|
}) {
|
|
6210
6295
|
if (!Number.isSafeInteger(amountSats)) {
|
|
6211
6296
|
throw new ValidationError("Sats amount must be less than 2^53", {
|
|
@@ -6215,7 +6300,13 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6215
6300
|
});
|
|
6216
6301
|
}
|
|
6217
6302
|
return await this.withLeaves(async () => {
|
|
6218
|
-
return await this.coopExit(
|
|
6303
|
+
return await this.coopExit(
|
|
6304
|
+
onchainAddress,
|
|
6305
|
+
feeQuote,
|
|
6306
|
+
exitSpeed,
|
|
6307
|
+
deductFeeFromWithdrawalAmount,
|
|
6308
|
+
amountSats
|
|
6309
|
+
);
|
|
6219
6310
|
});
|
|
6220
6311
|
}
|
|
6221
6312
|
/**
|
|
@@ -6226,7 +6317,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6226
6317
|
* @returns {Promise<Object | null | undefined>} The exit request details
|
|
6227
6318
|
* @private
|
|
6228
6319
|
*/
|
|
6229
|
-
async coopExit(onchainAddress, exitSpeed, targetAmountSats) {
|
|
6320
|
+
async coopExit(onchainAddress, feeEstimate, exitSpeed, deductFeeFromWithdrawalAmount, targetAmountSats) {
|
|
6230
6321
|
if (!Number.isSafeInteger(targetAmountSats)) {
|
|
6231
6322
|
throw new ValidationError("Sats amount must be less than 2^53", {
|
|
6232
6323
|
field: "targetAmountSats",
|
|
@@ -6234,41 +6325,34 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6234
6325
|
expected: "smaller or equal to " + Number.MAX_SAFE_INTEGER
|
|
6235
6326
|
});
|
|
6236
6327
|
}
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
leavesToSend = await this.selectLeaves(targetAmountSats);
|
|
6240
|
-
} else {
|
|
6241
|
-
leavesToSend = this.leaves.map((leaf) => ({
|
|
6242
|
-
...leaf
|
|
6243
|
-
}));
|
|
6328
|
+
if (!targetAmountSats) {
|
|
6329
|
+
deductFeeFromWithdrawalAmount = true;
|
|
6244
6330
|
}
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
}
|
|
6269
|
-
if (fee !== void 0 && fee > leavesToSend.reduce((acc, leaf) => acc + leaf.value, 0)) {
|
|
6331
|
+
let fee;
|
|
6332
|
+
switch (exitSpeed) {
|
|
6333
|
+
case ExitSpeed_default.FAST:
|
|
6334
|
+
fee = (feeEstimate.l1BroadcastFeeFast?.originalValue || 0) + (feeEstimate.userFeeFast?.originalValue || 0);
|
|
6335
|
+
break;
|
|
6336
|
+
case ExitSpeed_default.MEDIUM:
|
|
6337
|
+
fee = (feeEstimate.l1BroadcastFeeMedium?.originalValue || 0) + (feeEstimate.userFeeMedium?.originalValue || 0);
|
|
6338
|
+
break;
|
|
6339
|
+
case ExitSpeed_default.SLOW:
|
|
6340
|
+
fee = (feeEstimate.l1BroadcastFeeSlow?.originalValue || 0) + (feeEstimate.userFeeSlow?.originalValue || 0);
|
|
6341
|
+
break;
|
|
6342
|
+
default:
|
|
6343
|
+
throw new ValidationError("Invalid exit speed", {
|
|
6344
|
+
field: "exitSpeed",
|
|
6345
|
+
value: exitSpeed,
|
|
6346
|
+
expected: "FAST, MEDIUM, or SLOW"
|
|
6347
|
+
});
|
|
6348
|
+
}
|
|
6349
|
+
let leavesToSendToSsp = [];
|
|
6350
|
+
let leavesToSendToSE = [];
|
|
6351
|
+
if (deductFeeFromWithdrawalAmount) {
|
|
6352
|
+
leavesToSendToSsp = targetAmountSats ? (await this.selectLeaves([targetAmountSats])).get(targetAmountSats) : this.leaves;
|
|
6353
|
+
if (fee > leavesToSendToSsp.reduce((acc, leaf) => acc + leaf.value, 0)) {
|
|
6270
6354
|
throw new ValidationError(
|
|
6271
|
-
"The fee for the withdrawal is greater than the target amount",
|
|
6355
|
+
"The fee for the withdrawal is greater than the target withdrawal amount",
|
|
6272
6356
|
{
|
|
6273
6357
|
field: "fee",
|
|
6274
6358
|
value: fee,
|
|
@@ -6276,25 +6360,56 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6276
6360
|
}
|
|
6277
6361
|
);
|
|
6278
6362
|
}
|
|
6363
|
+
} else {
|
|
6364
|
+
if (!targetAmountSats) {
|
|
6365
|
+
throw new ValidationError(
|
|
6366
|
+
"targetAmountSats is required when deductFeeFromWithdrawalAmount is false",
|
|
6367
|
+
{
|
|
6368
|
+
field: "targetAmountSats",
|
|
6369
|
+
value: targetAmountSats,
|
|
6370
|
+
expected: "defined when deductFeeFromWithdrawalAmount is false"
|
|
6371
|
+
}
|
|
6372
|
+
);
|
|
6373
|
+
}
|
|
6374
|
+
const leaves = await this.selectLeaves([targetAmountSats, fee]);
|
|
6375
|
+
const leavesForTargetAmount = leaves.get(targetAmountSats);
|
|
6376
|
+
const leavesForFee = leaves.get(fee);
|
|
6377
|
+
if (!leavesForTargetAmount || !leavesForFee) {
|
|
6378
|
+
throw new Error("Failed to select leaves for target amount and fee");
|
|
6379
|
+
}
|
|
6380
|
+
leavesToSendToSsp = leavesForTargetAmount;
|
|
6381
|
+
leavesToSendToSE = leavesForFee;
|
|
6279
6382
|
}
|
|
6280
|
-
|
|
6281
|
-
|
|
6383
|
+
leavesToSendToSsp = await this.checkRefreshTimelockNodes(leavesToSendToSsp);
|
|
6384
|
+
leavesToSendToSsp = await this.checkExtendTimeLockNodes(leavesToSendToSsp);
|
|
6385
|
+
leavesToSendToSE = await this.checkRefreshTimelockNodes(leavesToSendToSE);
|
|
6386
|
+
leavesToSendToSE = await this.checkExtendTimeLockNodes(leavesToSendToSE);
|
|
6282
6387
|
const leafKeyTweaks = await Promise.all(
|
|
6283
|
-
|
|
6388
|
+
[...leavesToSendToSE, ...leavesToSendToSsp].map(async (leaf) => ({
|
|
6284
6389
|
leaf,
|
|
6285
6390
|
signingPubKey: await this.config.signer.generatePublicKey(
|
|
6286
|
-
|
|
6391
|
+
sha2566(leaf.id)
|
|
6287
6392
|
),
|
|
6288
6393
|
newSigningPubKey: await this.config.signer.generatePublicKey()
|
|
6289
6394
|
}))
|
|
6290
6395
|
);
|
|
6291
|
-
const
|
|
6292
|
-
leafExternalIds:
|
|
6396
|
+
const requestCoopExitParams = {
|
|
6397
|
+
leafExternalIds: leavesToSendToSsp.map((leaf) => leaf.id),
|
|
6293
6398
|
withdrawalAddress: onchainAddress,
|
|
6294
6399
|
idempotencyKey: uuidv74(),
|
|
6295
6400
|
exitSpeed,
|
|
6296
|
-
withdrawAll:
|
|
6297
|
-
}
|
|
6401
|
+
withdrawAll: deductFeeFromWithdrawalAmount
|
|
6402
|
+
};
|
|
6403
|
+
if (!deductFeeFromWithdrawalAmount) {
|
|
6404
|
+
requestCoopExitParams.feeQuoteId = feeEstimate.id;
|
|
6405
|
+
requestCoopExitParams.feeLeafExternalIds = leavesToSendToSE.map(
|
|
6406
|
+
(leaf) => leaf.id
|
|
6407
|
+
);
|
|
6408
|
+
}
|
|
6409
|
+
const sspClient = this.getSspClient();
|
|
6410
|
+
const coopExitRequest = await sspClient.requestCoopExit(
|
|
6411
|
+
requestCoopExitParams
|
|
6412
|
+
);
|
|
6298
6413
|
if (!coopExitRequest?.rawConnectorTransaction) {
|
|
6299
6414
|
throw new Error("Failed to request coop exit");
|
|
6300
6415
|
}
|
|
@@ -6332,9 +6447,9 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6332
6447
|
* @param {Object} params - Input parameters for fee estimation
|
|
6333
6448
|
* @param {number} params.amountSats - The amount in satoshis to withdraw
|
|
6334
6449
|
* @param {string} params.withdrawalAddress - The Bitcoin address where the funds should be sent
|
|
6335
|
-
* @returns {Promise<
|
|
6450
|
+
* @returns {Promise<CoopExitFeeQuote | null>} Fee estimate for the withdrawal
|
|
6336
6451
|
*/
|
|
6337
|
-
async
|
|
6452
|
+
async getWithdrawalFeeQuote({
|
|
6338
6453
|
amountSats,
|
|
6339
6454
|
withdrawalAddress
|
|
6340
6455
|
}) {
|
|
@@ -6346,10 +6461,10 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6346
6461
|
expected: "smaller or equal to " + Number.MAX_SAFE_INTEGER
|
|
6347
6462
|
});
|
|
6348
6463
|
}
|
|
6349
|
-
let leaves = await this.selectLeaves(amountSats);
|
|
6464
|
+
let leaves = (await this.selectLeaves([amountSats])).get(amountSats);
|
|
6350
6465
|
leaves = await this.checkRefreshTimelockNodes(leaves);
|
|
6351
6466
|
leaves = await this.checkExtendTimeLockNodes(leaves);
|
|
6352
|
-
const feeEstimate = await sspClient.
|
|
6467
|
+
const feeEstimate = await sspClient.getCoopExitFeeQuote({
|
|
6353
6468
|
leafExternalIds: leaves.map((leaf) => leaf.id),
|
|
6354
6469
|
withdrawalAddress
|
|
6355
6470
|
});
|
|
@@ -6374,7 +6489,14 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6374
6489
|
* @returns {Promise<Transfer | undefined>} The transfer
|
|
6375
6490
|
*/
|
|
6376
6491
|
async getTransfer(id) {
|
|
6377
|
-
|
|
6492
|
+
const transfer = await this.transferService.queryTransfer(id);
|
|
6493
|
+
if (!transfer) {
|
|
6494
|
+
return void 0;
|
|
6495
|
+
}
|
|
6496
|
+
return mapTransferToWalletTransfer(
|
|
6497
|
+
transfer,
|
|
6498
|
+
bytesToHex4(await this.config.signer.getIdentityPublicKey())
|
|
6499
|
+
);
|
|
6378
6500
|
}
|
|
6379
6501
|
// ***** Token Flow *****
|
|
6380
6502
|
/**
|
|
@@ -6385,10 +6507,9 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6385
6507
|
*/
|
|
6386
6508
|
async syncTokenOutputs() {
|
|
6387
6509
|
this.tokenOutputs.clear();
|
|
6388
|
-
const unsortedTokenOutputs = await this.tokenTransactionService.fetchOwnedTokenOutputs(
|
|
6389
|
-
[await this.config.signer.getIdentityPublicKey()]
|
|
6390
|
-
|
|
6391
|
-
);
|
|
6510
|
+
const unsortedTokenOutputs = await this.tokenTransactionService.fetchOwnedTokenOutputs({
|
|
6511
|
+
ownerPublicKeys: [await this.config.signer.getIdentityPublicKey()]
|
|
6512
|
+
});
|
|
6392
6513
|
const filteredTokenOutputs = unsortedTokenOutputs.filter(
|
|
6393
6514
|
(output) => !this.pendingWithdrawnOutputIds.includes(output.output?.id || "")
|
|
6394
6515
|
);
|
|
@@ -6487,29 +6608,21 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6487
6608
|
* Retrieves token transaction history for specified tokens owned by the wallet.
|
|
6488
6609
|
* Can optionally filter by specific transaction hashes.
|
|
6489
6610
|
*
|
|
6490
|
-
* @param
|
|
6611
|
+
* @param ownerPublicKeys - Optional array of owner public keys to query transactions for
|
|
6612
|
+
* @param issuerPublicKeys - Optional array of issuer public keys to query transactions for
|
|
6491
6613
|
* @param tokenTransactionHashes - Optional array of specific transaction hashes to filter by
|
|
6614
|
+
* @param tokenIdentifiers - Optional array of token identifiers to filter by
|
|
6615
|
+
* @param outputIds - Optional array of output IDs to filter by
|
|
6492
6616
|
* @returns Promise resolving to array of token transactions with their current status
|
|
6493
6617
|
*/
|
|
6494
|
-
async queryTokenTransactions(
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
ownerPublicKeys: [hexToBytes7(await this.getIdentityPublicKey())],
|
|
6503
|
-
tokenTransactionHashes: tokenTransactionHashes.map(hexToBytes7)
|
|
6504
|
-
};
|
|
6505
|
-
} else {
|
|
6506
|
-
queryParams = {
|
|
6507
|
-
tokenPublicKeys: tokenPublicKeys?.map(hexToBytes7),
|
|
6508
|
-
ownerPublicKeys: [hexToBytes7(await this.getIdentityPublicKey())]
|
|
6509
|
-
};
|
|
6510
|
-
}
|
|
6511
|
-
const response = await sparkClient.query_token_transactions(queryParams);
|
|
6512
|
-
return response.tokenTransactionsWithStatus;
|
|
6618
|
+
async queryTokenTransactions(ownerPublicKeys, issuerPublicKeys, tokenTransactionHashes, tokenIdentifiers, outputIds) {
|
|
6619
|
+
return this.tokenTransactionService.queryTokenTransactions({
|
|
6620
|
+
ownerPublicKeys,
|
|
6621
|
+
issuerPublicKeys,
|
|
6622
|
+
tokenTransactionHashes,
|
|
6623
|
+
tokenIdentifiers,
|
|
6624
|
+
outputIds
|
|
6625
|
+
});
|
|
6513
6626
|
}
|
|
6514
6627
|
async getTokenL1Address() {
|
|
6515
6628
|
return getP2WPKHAddressFromPublicKey(
|
|
@@ -6525,7 +6638,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6525
6638
|
* @returns {Promise<string>} The signed message
|
|
6526
6639
|
*/
|
|
6527
6640
|
async signMessageWithIdentityKey(message, compact) {
|
|
6528
|
-
const hash =
|
|
6641
|
+
const hash = sha2566(message);
|
|
6529
6642
|
const signature = await this.config.signer.signMessageWithIdentityKey(
|
|
6530
6643
|
hash,
|
|
6531
6644
|
compact
|
|
@@ -6540,7 +6653,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6540
6653
|
* @returns {Promise<boolean>} Whether the message is valid
|
|
6541
6654
|
*/
|
|
6542
6655
|
async validateMessageWithIdentityKey(message, signature) {
|
|
6543
|
-
const hash =
|
|
6656
|
+
const hash = sha2566(message);
|
|
6544
6657
|
if (typeof signature === "string") {
|
|
6545
6658
|
signature = hexToBytes7(signature);
|
|
6546
6659
|
}
|
|
@@ -6847,7 +6960,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6847
6960
|
});
|
|
6848
6961
|
}
|
|
6849
6962
|
const signingPubKey = await this.config.signer.generatePublicKey(
|
|
6850
|
-
|
|
6963
|
+
sha2566(node.id)
|
|
6851
6964
|
);
|
|
6852
6965
|
const result = await this.transferService.refreshTimelockNodes(
|
|
6853
6966
|
[node],
|
|
@@ -6899,7 +7012,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
|
|
|
6899
7012
|
});
|
|
6900
7013
|
}
|
|
6901
7014
|
const signingPubKey = await this.config.signer.generatePublicKey(
|
|
6902
|
-
|
|
7015
|
+
sha2566(node.id)
|
|
6903
7016
|
);
|
|
6904
7017
|
const result = await this.transferService.refreshTimelockRefundTx(
|
|
6905
7018
|
node,
|