@buildonspark/spark-sdk 0.2.11 → 0.2.13
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 +15 -0
- package/dist/bare/index.cjs +761 -243
- package/dist/bare/index.d.cts +70 -11
- package/dist/bare/index.d.ts +70 -11
- package/dist/bare/index.js +684 -170
- package/dist/{chunk-A5M55UR3.js → chunk-5VWGOHED.js} +499 -8
- package/dist/{chunk-3WBPICWC.js → chunk-CKHJFQUA.js} +1 -1
- package/dist/{chunk-QNYJGFPD.js → chunk-LX45BCZW.js} +207 -160
- package/dist/{chunk-76SYPHOC.js → chunk-TB7DG5CU.js} +2 -2
- package/dist/{chunk-6CMNEDBK.js → chunk-XXTWWW6L.js} +1 -1
- package/dist/{client-Dd3QnxQu.d.ts → client-D7KDa4Ih.d.ts} +1 -1
- package/dist/{client-B9CAWKWz.d.cts → client-DVuA5-7M.d.cts} +1 -1
- package/dist/debug.cjs +761 -243
- package/dist/debug.d.cts +4 -4
- package/dist/debug.d.ts +4 -4
- package/dist/debug.js +4 -4
- package/dist/graphql/objects/index.d.cts +3 -3
- package/dist/graphql/objects/index.d.ts +3 -3
- package/dist/index.cjs +783 -265
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +5 -5
- package/dist/index.node.cjs +783 -265
- package/dist/index.node.d.cts +6 -6
- package/dist/index.node.d.ts +6 -6
- package/dist/index.node.js +4 -4
- package/dist/{logging-BOAzMqpM.d.cts → logging-BfTyKwqb.d.cts} +3 -3
- package/dist/{logging-Bt_WdZbu.d.ts → logging-CaNpBgiE.d.ts} +3 -3
- package/dist/native/index.cjs +782 -264
- package/dist/native/index.d.cts +70 -11
- package/dist/native/index.d.ts +70 -11
- package/dist/native/index.js +686 -172
- package/dist/proto/spark.cjs +499 -8
- package/dist/proto/spark.d.cts +1 -1
- package/dist/proto/spark.d.ts +1 -1
- package/dist/proto/spark.js +17 -1
- package/dist/proto/spark_token.d.cts +1 -1
- package/dist/proto/spark_token.d.ts +1 -1
- package/dist/proto/spark_token.js +2 -2
- package/dist/{spark-CtGJPkx4.d.cts → spark-C7OG9mGJ.d.cts} +79 -2
- package/dist/{spark-CtGJPkx4.d.ts → spark-C7OG9mGJ.d.ts} +79 -2
- package/dist/{spark-wallet-Cp3yv6cK.d.ts → spark-wallet-D0Df_P_x.d.ts} +26 -13
- package/dist/{spark-wallet-yc2KhsVY.d.cts → spark-wallet-Dvh1BLP6.d.cts} +26 -13
- package/dist/{spark-wallet.node-D0Qw5Wb4.d.cts → spark-wallet.node-B3V8_fgw.d.cts} +1 -1
- package/dist/{spark-wallet.node-D4IovOHu.d.ts → spark-wallet.node-bGmy8-T8.d.ts} +1 -1
- package/dist/tests/test-utils.cjs +573 -66
- package/dist/tests/test-utils.d.cts +4 -4
- package/dist/tests/test-utils.d.ts +4 -4
- package/dist/tests/test-utils.js +5 -5
- package/dist/{token-transactions-CwhlOgIP.d.cts → token-transactions-D1ta-sHH.d.cts} +2 -2
- package/dist/{token-transactions-0nmR9mQO.d.ts → token-transactions-DINiKBzd.d.ts} +2 -2
- package/dist/types/index.cjs +492 -9
- package/dist/types/index.d.cts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +2 -2
- package/package.json +3 -3
- package/src/proto/common.ts +1 -1
- package/src/proto/google/protobuf/descriptor.ts +4 -10
- package/src/proto/google/protobuf/duration.ts +1 -1
- package/src/proto/google/protobuf/empty.ts +1 -1
- package/src/proto/google/protobuf/timestamp.ts +1 -1
- package/src/proto/mock.ts +1 -1
- package/src/proto/spark.ts +593 -3
- package/src/proto/spark_authn.ts +1 -1
- package/src/proto/spark_token.ts +1 -1
- package/src/proto/validate/validate.ts +27 -79
- package/src/services/deposit.ts +55 -3
- package/src/services/lightning.ts +2 -2
- package/src/services/signing.ts +1 -1
- package/src/services/token-transactions.ts +2 -5
- package/src/services/transfer.ts +2 -28
- package/src/signer/signer.ts +2 -2
- package/src/spark-wallet/proto-descriptors.ts +22 -0
- package/src/spark-wallet/proto-hash.ts +743 -0
- package/src/spark-wallet/proto-reflection.ts +193 -0
- package/src/spark-wallet/spark-wallet.ts +95 -57
- package/src/spark_descriptors.pb +0 -0
- package/src/tests/address.test.ts +10 -10
- package/src/tests/bitcoin.test.ts +2 -2
- package/src/tests/bufbuild-reflection.test.ts +151 -0
- package/src/tests/cross-language-hash.test.ts +79 -0
- package/src/tests/integration/address.test.ts +3 -12
- package/src/tests/integration/coop-exit.test.ts +1 -1
- package/src/tests/integration/lightning.test.ts +1 -1
- package/src/tests/integration/ssp/static_deposit.test.ts +128 -1
- package/src/tests/integration/static_deposit.test.ts +26 -0
- package/src/tests/integration/swap.test.ts +1 -1
- package/src/tests/integration/transfer.test.ts +1 -129
- package/src/tests/integration/wallet.test.ts +7 -7
- package/src/tests/integration/watchtower.test.ts +1 -1
- package/src/tests/token-hashing.test.ts +3 -6
- package/src/tests/token-outputs.test.ts +3 -3
- package/src/tests/utils/test-faucet.ts +2 -2
- package/src/types/sdk-types.ts +1 -1
- package/src/utils/adaptor-signature.ts +1 -1
- package/src/utils/address.ts +1 -1
- package/src/utils/bitcoin.ts +1 -5
- package/src/utils/keys.ts +1 -1
- package/src/utils/secret-sharing.ts +1 -1
- package/src/utils/token-transactions.ts +1 -2
- package/src/utils/transfer_package.ts +1 -1
- package/src/utils/unilateral-exit.ts +1 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// sdks/js/packages/spark-sdk/src/tests/cross-language-hash.test.ts
|
|
2
|
+
/**
|
|
3
|
+
* Cross-language hash compatibility test for SparkInvoiceFields.
|
|
4
|
+
* This test validates that our JavaScript protoreflecthash implementation
|
|
5
|
+
* produces identical hashes to the Go implementation for the same data.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, expect, it } from "@jest/globals";
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import { SparkInvoiceFields } from "../proto/spark.js";
|
|
11
|
+
import { createProtoHasher } from "../spark-wallet/proto-hash.js";
|
|
12
|
+
import { getFieldNumbers } from "../spark-wallet/proto-reflection.js";
|
|
13
|
+
|
|
14
|
+
function toHex(bytes: Uint8Array): string {
|
|
15
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe("Cross-Language Hash Compatibility", () => {
|
|
19
|
+
const hasher = createProtoHasher();
|
|
20
|
+
|
|
21
|
+
// Load canonical protobuf JSON test cases from the repo
|
|
22
|
+
const candidates = [
|
|
23
|
+
new URL(
|
|
24
|
+
"../../../../../../spark/testdata/cross_language_hash_cases_proto.json",
|
|
25
|
+
import.meta.url,
|
|
26
|
+
),
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
let jsonData: any | null = null;
|
|
30
|
+
for (const u of candidates) {
|
|
31
|
+
try {
|
|
32
|
+
const raw = fs.readFileSync(u, "utf8");
|
|
33
|
+
jsonData = JSON.parse(raw);
|
|
34
|
+
break;
|
|
35
|
+
} catch {
|
|
36
|
+
// try next
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!jsonData) {
|
|
41
|
+
it("skips when proto-JSON dataset is absent", () => {
|
|
42
|
+
expect(true).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const allCases = (jsonData.testCases || []) as any[];
|
|
48
|
+
|
|
49
|
+
it("should extract correct field numbers from SparkInvoiceFields", () => {
|
|
50
|
+
const fieldNumbers = getFieldNumbers("spark.SparkInvoiceFields");
|
|
51
|
+
expect(fieldNumbers.version).toBe(1);
|
|
52
|
+
expect(fieldNumbers.id).toBe(2);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
for (const tc of allCases) {
|
|
56
|
+
it(`matches expected hash for ${tc.name}`, async () => {
|
|
57
|
+
const msg = SparkInvoiceFields.fromJSON(tc.sparkInvoiceFields);
|
|
58
|
+
const hash = await hasher.hashProto(msg, "spark.SparkInvoiceFields");
|
|
59
|
+
const hex = toHex(hash);
|
|
60
|
+
|
|
61
|
+
// Always 32 bytes and deterministic.
|
|
62
|
+
expect(hash).toHaveLength(32);
|
|
63
|
+
const hash2 = await hasher.hashProto(msg, "spark.SparkInvoiceFields");
|
|
64
|
+
expect(hash).toEqual(hash2);
|
|
65
|
+
|
|
66
|
+
// Compare against expected hash from JSON
|
|
67
|
+
expect(hex.toLowerCase()).toBe(String(tc.expectedHash).toLowerCase());
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
it("errors on nil/undefined messages", async () => {
|
|
72
|
+
await expect(hasher.hashProto(null as any)).rejects.toThrow(
|
|
73
|
+
/cannot hash nil/i,
|
|
74
|
+
);
|
|
75
|
+
await expect(hasher.hashProto(undefined as any)).rejects.toThrow(
|
|
76
|
+
/cannot hash nil/i,
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -12,7 +12,7 @@ describe("address", () => {
|
|
|
12
12
|
])(
|
|
13
13
|
".seedOrMnemonic(%s)",
|
|
14
14
|
(seedOrMnemonic) => {
|
|
15
|
-
test.
|
|
15
|
+
test.each([["LOCAL", "spl", "bcrt"]])(
|
|
16
16
|
`.network(%s)`,
|
|
17
17
|
async (network, sparkAddressPrefix, blockchainAddressPrefix) => {
|
|
18
18
|
const options: ConfigOptions = {
|
|
@@ -32,13 +32,8 @@ describe("address", () => {
|
|
|
32
32
|
);
|
|
33
33
|
expect(sparkAddress).toEqual(await wallet.getSparkAddress());
|
|
34
34
|
|
|
35
|
-
// Make multiple concurrent calls to getSingleUseDepositAddress
|
|
36
35
|
const depositAddresses = await Promise.all([
|
|
37
36
|
wallet.getSingleUseDepositAddress(),
|
|
38
|
-
wallet.getSingleUseDepositAddress(),
|
|
39
|
-
wallet.getSingleUseDepositAddress(),
|
|
40
|
-
wallet.getSingleUseDepositAddress(),
|
|
41
|
-
wallet.getSingleUseDepositAddress(),
|
|
42
37
|
]);
|
|
43
38
|
|
|
44
39
|
// Verify each address is unique and valid
|
|
@@ -49,7 +44,7 @@ describe("address", () => {
|
|
|
49
44
|
);
|
|
50
45
|
addressMap.set(depositAddress, depositAddress);
|
|
51
46
|
}
|
|
52
|
-
expect(addressMap.size).toBe(
|
|
47
|
+
expect(addressMap.size).toBe(1);
|
|
53
48
|
|
|
54
49
|
// Create a new wallet with the same seed or mnemonic
|
|
55
50
|
const { wallet: wallet2, ...rest2 } =
|
|
@@ -67,10 +62,6 @@ describe("address", () => {
|
|
|
67
62
|
// New wallet should continue to generate unique addresses
|
|
68
63
|
const depositAddresses2 = await Promise.all([
|
|
69
64
|
wallet2.getSingleUseDepositAddress(),
|
|
70
|
-
wallet2.getSingleUseDepositAddress(),
|
|
71
|
-
wallet2.getSingleUseDepositAddress(),
|
|
72
|
-
wallet2.getSingleUseDepositAddress(),
|
|
73
|
-
wallet2.getSingleUseDepositAddress(),
|
|
74
65
|
]);
|
|
75
66
|
|
|
76
67
|
// Verify each address is unique and valid
|
|
@@ -80,7 +71,7 @@ describe("address", () => {
|
|
|
80
71
|
);
|
|
81
72
|
addressMap.set(depositAddress, depositAddress);
|
|
82
73
|
}
|
|
83
|
-
expect(addressMap.size).toBe(
|
|
74
|
+
expect(addressMap.size).toBe(2);
|
|
84
75
|
},
|
|
85
76
|
30000,
|
|
86
77
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "@jest/globals";
|
|
2
|
-
import { hexToBytes } from "@noble/curves/abstract/utils";
|
|
3
2
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
3
|
+
import { hexToBytes } from "@noble/curves/utils";
|
|
4
4
|
import { Address, OutScript, Transaction } from "@scure/btc-signer";
|
|
5
5
|
import { TransactionInput } from "@scure/btc-signer/psbt";
|
|
6
6
|
import { equalBytes } from "@scure/btc-signer/utils";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, beforeAll, describe, expect, it } from "@jest/globals";
|
|
2
|
-
import { hexToBytes } from "@noble/curves/
|
|
2
|
+
import { hexToBytes } from "@noble/curves/utils";
|
|
3
3
|
import { sha256 } from "@noble/hashes/sha2";
|
|
4
4
|
import { equalBytes } from "@scure/btc-signer/utils";
|
|
5
5
|
import { uuidv7 } from "uuidv7";
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
import { bytesToHex } from "@noble/hashes/utils";
|
|
6
6
|
import { BitcoinFaucet } from "../../utils/test-faucet.js";
|
|
7
7
|
|
|
8
|
-
const SMALL_DEPOSIT_AMOUNT = 10n;
|
|
9
8
|
export const DEPOSIT_AMOUNT = 10000n;
|
|
10
9
|
const SECOND_DEPOSIT_AMOUNT = 20000n;
|
|
11
10
|
const THIRD_DEPOSIT_AMOUNT = 30000n;
|
|
@@ -168,6 +167,134 @@ describe("SSP static deposit address integration", () => {
|
|
|
168
167
|
|
|
169
168
|
expect(refundTx).not.toBe(refundTx2);
|
|
170
169
|
}, 60000);
|
|
170
|
+
|
|
171
|
+
it("should return the right amount of txns when querying for utxos sent to a static deposit address", async () => {
|
|
172
|
+
const faucet = BitcoinFaucet.getInstance();
|
|
173
|
+
const { wallet: userWallet } = await SparkWalletTesting.initialize(
|
|
174
|
+
{
|
|
175
|
+
options: {
|
|
176
|
+
network: "LOCAL",
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
false,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const depositAddress = await userWallet.getStaticDepositAddress();
|
|
183
|
+
expect(depositAddress).toBeDefined();
|
|
184
|
+
const signedTx = await faucet.sendToAddress(
|
|
185
|
+
depositAddress,
|
|
186
|
+
DEPOSIT_AMOUNT,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// Wait for the transaction to be mined
|
|
190
|
+
await faucet.mineBlocks(6);
|
|
191
|
+
expect(signedTx).toBeDefined();
|
|
192
|
+
const transactionId = signedTx.id;
|
|
193
|
+
let vout;
|
|
194
|
+
for (let i = 0; i < signedTx.outputsLength; i++) {
|
|
195
|
+
const output = signedTx.getOutput(i);
|
|
196
|
+
if (output.amount === DEPOSIT_AMOUNT) {
|
|
197
|
+
vout = i;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const quote = await userWallet.getClaimStaticDepositQuote(
|
|
203
|
+
transactionId,
|
|
204
|
+
vout!,
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
208
|
+
|
|
209
|
+
const quoteAmount = quote!.creditAmountSats;
|
|
210
|
+
const sspSignature = quote!.signature;
|
|
211
|
+
|
|
212
|
+
await userWallet.claimStaticDeposit({
|
|
213
|
+
transactionId,
|
|
214
|
+
creditAmountSats: quoteAmount,
|
|
215
|
+
sspSignature,
|
|
216
|
+
outputIndex: vout!,
|
|
217
|
+
});
|
|
218
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
219
|
+
const { balance } = await userWallet.getBalance();
|
|
220
|
+
expect(balance).toBe(BigInt(quoteAmount));
|
|
221
|
+
|
|
222
|
+
// Test depositing money to the same address and second time and claiming.
|
|
223
|
+
const signedTx2 = await faucet.sendToAddress(
|
|
224
|
+
depositAddress,
|
|
225
|
+
SECOND_DEPOSIT_AMOUNT,
|
|
226
|
+
);
|
|
227
|
+
const transactionId2 = signedTx2.id;
|
|
228
|
+
// Wait for the transaction to be mined
|
|
229
|
+
await faucet.mineBlocks(6);
|
|
230
|
+
// Test claiming and getting the quote without passing in the output index.
|
|
231
|
+
const quote2 =
|
|
232
|
+
await userWallet.getClaimStaticDepositQuote(transactionId2);
|
|
233
|
+
const quoteAmount2 = quote2!.creditAmountSats;
|
|
234
|
+
const sspSignature2 = quote2!.signature;
|
|
235
|
+
await userWallet.claimStaticDeposit({
|
|
236
|
+
transactionId: transactionId2,
|
|
237
|
+
creditAmountSats: quoteAmount2,
|
|
238
|
+
sspSignature: sspSignature2,
|
|
239
|
+
});
|
|
240
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
241
|
+
const { balance: balance2 } = await userWallet.getBalance();
|
|
242
|
+
expect(balance2).toBe(BigInt(quoteAmount + quoteAmount2));
|
|
243
|
+
|
|
244
|
+
// Test depositing money to the same address and test claim with max fee flow.
|
|
245
|
+
const signedTx3 = await faucet.sendToAddress(
|
|
246
|
+
depositAddress,
|
|
247
|
+
THIRD_DEPOSIT_AMOUNT,
|
|
248
|
+
);
|
|
249
|
+
const transactionId3 = signedTx3.id;
|
|
250
|
+
// Wait for the transaction to be mined
|
|
251
|
+
await faucet.mineBlocks(6);
|
|
252
|
+
// Get quote so we can calculate the expected balance. Not needed for actual flow.
|
|
253
|
+
const quote3 =
|
|
254
|
+
await userWallet.getClaimStaticDepositQuote(transactionId3);
|
|
255
|
+
const quoteAmount3 = quote3!.creditAmountSats;
|
|
256
|
+
await userWallet.claimStaticDepositWithMaxFee({
|
|
257
|
+
transactionId: transactionId3,
|
|
258
|
+
maxFee: 1000,
|
|
259
|
+
});
|
|
260
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
261
|
+
const { balance: balance3 } = await userWallet.getBalance();
|
|
262
|
+
expect(balance3).toBe(BigInt(quoteAmount + quoteAmount2 + quoteAmount3));
|
|
263
|
+
// Get transfers should include static deposit transfers.
|
|
264
|
+
const transfers = await userWallet.getTransfers();
|
|
265
|
+
expect(transfers.transfers.length).toBe(3);
|
|
266
|
+
|
|
267
|
+
for (let i = 0; i < 98; i++) {
|
|
268
|
+
await faucet.sendToAddress(depositAddress, THIRD_DEPOSIT_AMOUNT);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
await faucet.mineBlocks(6);
|
|
272
|
+
|
|
273
|
+
let utxosExcludeClaimed: any[] = [];
|
|
274
|
+
const utxosExcludeClaimedExpected = 98;
|
|
275
|
+
const maxAttempts = 10;
|
|
276
|
+
for (let attempt = 1; attempt <= 10; attempt++) {
|
|
277
|
+
utxosExcludeClaimed = await userWallet.getUtxosForDepositAddress(
|
|
278
|
+
depositAddress,
|
|
279
|
+
100,
|
|
280
|
+
0,
|
|
281
|
+
true,
|
|
282
|
+
);
|
|
283
|
+
if (utxosExcludeClaimed.length === utxosExcludeClaimedExpected) break;
|
|
284
|
+
if (attempt < maxAttempts)
|
|
285
|
+
await new Promise((r) => setTimeout(r, 5000));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
expect(utxosExcludeClaimed.length).toBe(98);
|
|
289
|
+
|
|
290
|
+
const utxos = await userWallet.getUtxosForDepositAddress(
|
|
291
|
+
depositAddress,
|
|
292
|
+
100,
|
|
293
|
+
0,
|
|
294
|
+
false,
|
|
295
|
+
);
|
|
296
|
+
expect(utxos.length).toBe(100);
|
|
297
|
+
}, 60000);
|
|
171
298
|
});
|
|
172
299
|
|
|
173
300
|
describe("Concurrency testing", () => {
|
|
@@ -52,6 +52,32 @@ describe("SSP static deposit address integration", () => {
|
|
|
52
52
|
).rejects.toThrow();
|
|
53
53
|
}, 600000);
|
|
54
54
|
|
|
55
|
+
it("should refund and broadcast a static deposit refund transaction", async () => {
|
|
56
|
+
const {
|
|
57
|
+
wallet: userWallet,
|
|
58
|
+
depositAddress,
|
|
59
|
+
signedTx,
|
|
60
|
+
vout,
|
|
61
|
+
faucet,
|
|
62
|
+
} = await initWallet(DEPOSIT_AMOUNT, "LOCAL");
|
|
63
|
+
|
|
64
|
+
// Wait for the transaction to be mined
|
|
65
|
+
await faucet.mineBlocks(6);
|
|
66
|
+
|
|
67
|
+
const transactionId = signedTx.id;
|
|
68
|
+
|
|
69
|
+
const txId = await userWallet.refundAndBroadcastStaticDeposit({
|
|
70
|
+
depositTransactionId: transactionId,
|
|
71
|
+
outputIndex: vout!,
|
|
72
|
+
destinationAddress: depositAddress,
|
|
73
|
+
satsPerVbyteFee: 2,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await faucet.mineBlocks(6);
|
|
77
|
+
|
|
78
|
+
expect(txId).toBeDefined();
|
|
79
|
+
}, 600000);
|
|
80
|
+
|
|
55
81
|
it("should fail due to low fee", async () => {
|
|
56
82
|
console.log("Initializing wallet for low-fee refund test...");
|
|
57
83
|
const {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "@jest/globals";
|
|
2
|
-
import { hexToBytes } from "@noble/curves/abstract/utils";
|
|
3
2
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
3
|
+
import { hexToBytes } from "@noble/curves/utils";
|
|
4
4
|
import { uuidv7 } from "uuidv7";
|
|
5
5
|
import { ValidationError } from "../../errors/types.js";
|
|
6
6
|
import { KeyDerivationType } from "../../index.js";
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it, jest } from "@jest/globals";
|
|
2
|
-
import {
|
|
3
|
-
bytesToHex,
|
|
4
|
-
equalBytes,
|
|
5
|
-
hexToBytes,
|
|
6
|
-
} from "@noble/curves/abstract/utils";
|
|
2
|
+
import { bytesToHex, equalBytes, hexToBytes } from "@noble/curves/utils";
|
|
7
3
|
import { generateMnemonic } from "@scure/bip39";
|
|
8
4
|
import { wordlist } from "@scure/bip39/wordlists/english";
|
|
9
5
|
import { uuidv7 } from "uuidv7";
|
|
@@ -309,130 +305,6 @@ describe.each(walletTypes)(
|
|
|
309
305
|
);
|
|
310
306
|
});
|
|
311
307
|
|
|
312
|
-
testLocalOnly(`${name} - cancel transfer`, async () => {
|
|
313
|
-
const faucet = BitcoinFaucet.getInstance();
|
|
314
|
-
|
|
315
|
-
const options: ConfigOptions = {
|
|
316
|
-
network: "LOCAL",
|
|
317
|
-
};
|
|
318
|
-
const { wallet: senderWallet } = await SparkWalletTesting.initialize({
|
|
319
|
-
options,
|
|
320
|
-
signer: new Signer(),
|
|
321
|
-
});
|
|
322
|
-
const mnemonic = generateMnemonic(wordlist);
|
|
323
|
-
|
|
324
|
-
const { wallet: receiverWallet } = await SparkWalletTesting.initialize({
|
|
325
|
-
options,
|
|
326
|
-
});
|
|
327
|
-
const receiverPubkey = await receiverWallet.getIdentityPublicKey();
|
|
328
|
-
|
|
329
|
-
const receiverConfigService = new WalletConfigService(
|
|
330
|
-
options,
|
|
331
|
-
receiverWallet.getSigner(),
|
|
332
|
-
);
|
|
333
|
-
const receiverConnectionManager = new ConnectionManager(
|
|
334
|
-
receiverConfigService,
|
|
335
|
-
);
|
|
336
|
-
const receiverSigningService = new SigningService(receiverConfigService);
|
|
337
|
-
|
|
338
|
-
const receiverTransferService = new TransferService(
|
|
339
|
-
receiverConfigService,
|
|
340
|
-
receiverConnectionManager,
|
|
341
|
-
receiverSigningService,
|
|
342
|
-
);
|
|
343
|
-
|
|
344
|
-
const leafId = uuidv7();
|
|
345
|
-
const rootNode = await createTree(senderWallet, leafId, faucet, 100_000n);
|
|
346
|
-
|
|
347
|
-
const newLeafDerivationPath: KeyDerivation = {
|
|
348
|
-
type: KeyDerivationType.LEAF,
|
|
349
|
-
path: uuidv7(),
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
const transferNode: LeafKeyTweak = {
|
|
353
|
-
leaf: rootNode,
|
|
354
|
-
keyDerivation: {
|
|
355
|
-
type: KeyDerivationType.LEAF,
|
|
356
|
-
path: leafId,
|
|
357
|
-
},
|
|
358
|
-
newKeyDerivation: newLeafDerivationPath,
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
const senderConfigService = new WalletConfigService(
|
|
362
|
-
options,
|
|
363
|
-
senderWallet.getSigner(),
|
|
364
|
-
);
|
|
365
|
-
const senderConnectionManager = new ConnectionManager(
|
|
366
|
-
senderConfigService,
|
|
367
|
-
);
|
|
368
|
-
const senderSigningService = new SigningService(senderConfigService);
|
|
369
|
-
|
|
370
|
-
const senderTransferService = new TransferService(
|
|
371
|
-
senderConfigService,
|
|
372
|
-
senderConnectionManager,
|
|
373
|
-
senderSigningService,
|
|
374
|
-
);
|
|
375
|
-
|
|
376
|
-
const senderTransfer = await senderTransferService.sendTransferSignRefund(
|
|
377
|
-
[transferNode],
|
|
378
|
-
hexToBytes(receiverPubkey),
|
|
379
|
-
new Date(Date.now() + 10 * 60 * 1000),
|
|
380
|
-
);
|
|
381
|
-
|
|
382
|
-
await senderTransferService.cancelTransfer(
|
|
383
|
-
senderTransfer.transfer,
|
|
384
|
-
senderConfigService.getCoordinatorAddress(),
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
const newSenderTransfer =
|
|
388
|
-
await senderTransferService.sendTransferWithKeyTweaks(
|
|
389
|
-
[transferNode],
|
|
390
|
-
hexToBytes(receiverPubkey),
|
|
391
|
-
);
|
|
392
|
-
|
|
393
|
-
const pendingTransfer = await receiverWallet.queryPendingTransfers();
|
|
394
|
-
expect(pendingTransfer.transfers.length).toBe(1);
|
|
395
|
-
|
|
396
|
-
const receiverTransfer = pendingTransfer.transfers[0];
|
|
397
|
-
expect(receiverTransfer!.id).toBe(newSenderTransfer.id);
|
|
398
|
-
|
|
399
|
-
const leafPubKeyMap = await receiverWallet.verifyPendingTransfer(
|
|
400
|
-
receiverTransfer!,
|
|
401
|
-
);
|
|
402
|
-
|
|
403
|
-
expect(leafPubKeyMap.size).toBe(1);
|
|
404
|
-
|
|
405
|
-
const leafPubKeyMapBytes = leafPubKeyMap.get(rootNode.id);
|
|
406
|
-
expect(leafPubKeyMapBytes).toBeDefined();
|
|
407
|
-
expect(
|
|
408
|
-
equalBytes(
|
|
409
|
-
leafPubKeyMapBytes!,
|
|
410
|
-
await senderWallet
|
|
411
|
-
.getSigner()
|
|
412
|
-
.getPublicKeyFromDerivation(newLeafDerivationPath),
|
|
413
|
-
),
|
|
414
|
-
).toBe(true);
|
|
415
|
-
|
|
416
|
-
const claimingNodes: LeafKeyTweak[] = receiverTransfer!.leaves.map(
|
|
417
|
-
(leaf) => ({
|
|
418
|
-
leaf: receiverTransfer!.leaves[0]!.leaf!,
|
|
419
|
-
keyDerivation: {
|
|
420
|
-
type: KeyDerivationType.ECIES,
|
|
421
|
-
path: leaf.secretCipher,
|
|
422
|
-
},
|
|
423
|
-
newKeyDerivation: {
|
|
424
|
-
type: KeyDerivationType.LEAF,
|
|
425
|
-
path: leaf.leaf!.id,
|
|
426
|
-
},
|
|
427
|
-
}),
|
|
428
|
-
);
|
|
429
|
-
|
|
430
|
-
await receiverTransferService.claimTransfer(
|
|
431
|
-
receiverTransfer!,
|
|
432
|
-
claimingNodes,
|
|
433
|
-
);
|
|
434
|
-
});
|
|
435
|
-
|
|
436
308
|
testLocalOnly(
|
|
437
309
|
`${name} - test that when the receiver has tweaked the key on some SOs, we can still claim the transfer`,
|
|
438
310
|
async () => {
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { describe, expect, it } from "@jest/globals";
|
|
2
|
+
import { schnorr, secp256k1 } from "@noble/curves/secp256k1";
|
|
3
|
+
import { bytesToHex } from "@noble/curves/utils";
|
|
4
|
+
import type { Transaction } from "@scure/btc-signer";
|
|
2
5
|
import { ConfigOptions } from "../../services/wallet-config.js";
|
|
3
|
-
import { NetworkType } from "../../utils/network.js";
|
|
4
|
-
import { walletTypes } from "../test-utils.js";
|
|
5
|
-
import { SparkWalletTesting } from "../utils/spark-testing-wallet.js";
|
|
6
|
-
import { secp256k1, schnorr } from "@noble/curves/secp256k1";
|
|
7
|
-
import { bytesToHex } from "@noble/curves/abstract/utils";
|
|
8
6
|
import type { SparkSigner } from "../../signer/signer.js";
|
|
9
|
-
import type { Transaction } from "@scure/btc-signer";
|
|
10
7
|
import type {
|
|
11
8
|
AggregateFrostParams,
|
|
12
9
|
KeyDerivation,
|
|
13
|
-
SigningCommitmentWithOptionalNonce,
|
|
14
10
|
SignFrostParams,
|
|
11
|
+
SigningCommitmentWithOptionalNonce,
|
|
15
12
|
SplitSecretWithProofsParams,
|
|
16
13
|
} from "../../signer/types.js";
|
|
14
|
+
import { NetworkType } from "../../utils/network.js";
|
|
17
15
|
import type { VerifiableSecretShare } from "../../utils/secret-sharing.js";
|
|
16
|
+
import { walletTypes } from "../test-utils.js";
|
|
17
|
+
import { SparkWalletTesting } from "../utils/spark-testing-wallet.js";
|
|
18
18
|
|
|
19
19
|
describe.each(walletTypes)("wallet", ({ name, Signer }) => {
|
|
20
20
|
it(`${name} - should initialize a wallet`, async () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it, jest } from "@jest/globals";
|
|
2
|
-
import { bytesToHex, hexToBytes } from "@noble/curves/
|
|
2
|
+
import { bytesToHex, hexToBytes } from "@noble/curves/utils";
|
|
3
3
|
import { uuidv7 } from "uuidv7";
|
|
4
4
|
import { KeyDerivation, KeyDerivationType } from "../../index.js";
|
|
5
5
|
import { WalletConfigService } from "../../services/config.js";
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { numberToBytesBE } from "@noble/curves/
|
|
1
|
+
import { numberToBytesBE } from "@noble/curves/utils";
|
|
2
|
+
import { sha256 } from "@noble/hashes/sha2";
|
|
3
|
+
import { Network } from "../proto/spark.js";
|
|
2
4
|
import {
|
|
3
5
|
hashTokenTransactionV0,
|
|
4
6
|
hashTokenTransactionV1,
|
|
5
7
|
hashTokenTransactionV2,
|
|
6
8
|
} from "../utils/token-hashing.js";
|
|
7
|
-
import { Network, OutputWithPreviousTransactionData } from "../proto/spark.js";
|
|
8
|
-
import { TokenTransactionService } from "../services/token-transactions.js";
|
|
9
|
-
import { WalletConfigService } from "../services/config.js";
|
|
10
|
-
import { ConnectionManager } from "../services/connection.js";
|
|
11
|
-
import { sha256 } from "@noble/hashes/sha2";
|
|
12
9
|
|
|
13
10
|
// Test constants for consistent test data across all hash tests
|
|
14
11
|
const TEST_TOKEN_PUBLIC_KEY = new Uint8Array([
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { numberToBytesBE } from "@noble/curves/
|
|
1
|
+
import { numberToBytesBE } from "@noble/curves/utils";
|
|
2
|
+
import { ValidationError } from "../errors/types.js";
|
|
2
3
|
import { OutputWithPreviousTransactionData } from "../proto/spark.js";
|
|
3
|
-
import { TokenTransactionService } from "../services/token-transactions.js";
|
|
4
4
|
import { WalletConfigService } from "../services/config.js";
|
|
5
5
|
import { ConnectionManager } from "../services/connection.js";
|
|
6
|
-
import {
|
|
6
|
+
import { TokenTransactionService } from "../services/token-transactions.js";
|
|
7
7
|
|
|
8
8
|
describe("select token outputs", () => {
|
|
9
9
|
let tokenTransactionService: TokenTransactionService;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { bytesToHex, hexToBytes } from "@noble/curves/abstract/utils";
|
|
2
1
|
import { schnorr, secp256k1 } from "@noble/curves/secp256k1";
|
|
2
|
+
import { bytesToHex, hexToBytes } from "@noble/curves/utils";
|
|
3
3
|
import * as btc from "@scure/btc-signer";
|
|
4
4
|
import { Address, OutScript, SigHash, Transaction } from "@scure/btc-signer";
|
|
5
5
|
import { TransactionInput, TransactionOutput } from "@scure/btc-signer/psbt";
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
getP2TRAddressFromPublicKey,
|
|
10
10
|
getP2TRScriptFromPublicKey,
|
|
11
11
|
} from "../../utils/bitcoin.js";
|
|
12
|
-
import { getNetwork, Network } from "../../utils/network.js";
|
|
13
12
|
import { getFetch } from "../../utils/fetch.js";
|
|
13
|
+
import { getNetwork, Network } from "../../utils/network.js";
|
|
14
14
|
|
|
15
15
|
// Static keys for deterministic testing
|
|
16
16
|
// P2TRAddress: bcrt1p2uy9zw5ltayucsuzl4tet6ckelzawp08qrtunacscsszflye907q62uqhl
|
package/src/types/sdk-types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bytesToHex } from "@noble/curves/
|
|
1
|
+
import { bytesToHex } from "@noble/curves/utils";
|
|
2
2
|
import ClaimStaticDeposit from "../graphql/objects/ClaimStaticDeposit.js";
|
|
3
3
|
import CoopExitRequest from "../graphql/objects/CoopExitRequest.js";
|
|
4
4
|
import LeavesSwapRequest from "../graphql/objects/LeavesSwapRequest.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mod } from "@noble/curves/abstract/modular";
|
|
2
|
-
import { bytesToNumberBE, numberToBytesBE } from "@noble/curves/abstract/utils";
|
|
3
2
|
import { schnorr, secp256k1 } from "@noble/curves/secp256k1";
|
|
3
|
+
import { bytesToNumberBE, numberToBytesBE } from "@noble/curves/utils";
|
|
4
4
|
import { ValidationError } from "../errors/index.js";
|
|
5
5
|
|
|
6
6
|
export function generateSignatureFromExistingAdaptor(
|
package/src/utils/address.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BinaryWriter } from "@bufbuild/protobuf/wire";
|
|
2
|
-
import { bytesToNumberBE } from "@noble/curves/abstract/utils";
|
|
3
2
|
import { schnorr, secp256k1 } from "@noble/curves/secp256k1";
|
|
3
|
+
import { bytesToNumberBE } from "@noble/curves/utils";
|
|
4
4
|
import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
|
|
5
5
|
import { bech32m } from "@scure/base";
|
|
6
6
|
import { UUID } from "uuidv7";
|
package/src/utils/bitcoin.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
bytesToHex,
|
|
3
|
-
bytesToNumberBE,
|
|
4
|
-
hexToBytes,
|
|
5
|
-
} from "@noble/curves/abstract/utils";
|
|
6
1
|
import { schnorr, secp256k1 } from "@noble/curves/secp256k1";
|
|
2
|
+
import { bytesToHex, bytesToNumberBE, hexToBytes } from "@noble/curves/utils";
|
|
7
3
|
|
|
8
4
|
import { sha256 } from "@noble/hashes/sha2";
|
|
9
5
|
import * as btc from "@scure/btc-signer";
|
package/src/utils/keys.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { numberToBytesBE } from "@noble/curves/abstract/utils";
|
|
2
1
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
2
|
+
import { numberToBytesBE } from "@noble/curves/utils";
|
|
3
3
|
import { ValidationError } from "../errors/index.js";
|
|
4
4
|
|
|
5
5
|
export function addPublicKeys(a: Uint8Array, b: Uint8Array): Uint8Array {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { bytesToHex, equalBytes } from "@noble/curves/abstract/utils";
|
|
2
1
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
2
|
+
import { bytesToHex, equalBytes } from "@noble/curves/utils";
|
|
3
3
|
import { ValidationError } from "../errors/index.js";
|
|
4
4
|
import { getCrypto } from "./crypto.js";
|
|
5
5
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { equalBytes } from "@scure/btc-signer/utils";
|
|
1
|
+
import { bytesToNumberBE, equalBytes } from "@noble/curves/utils";
|
|
3
2
|
import { OutputWithPreviousTransactionData } from "../proto/spark.js";
|
|
4
3
|
import { TokenBalanceMap, TokenOutputsMap } from "../spark-wallet/types.js";
|
|
5
4
|
import {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// unilateral-exit.ts
|
|
2
2
|
|
|
3
|
-
import { bytesToHex, hexToBytes } from "@noble/curves/
|
|
3
|
+
import { bytesToHex, hexToBytes } from "@noble/curves/utils";
|
|
4
4
|
import { ripemd160 } from "@noble/hashes/legacy";
|
|
5
5
|
import { sha256 } from "@noble/hashes/sha2";
|
|
6
6
|
import * as btc from "@scure/btc-signer";
|