@buildonspark/spark-sdk 0.2.3 → 0.2.5
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 +17 -0
- package/dist/{chunk-3SEOTO43.js → chunk-3SPMJMUX.js} +3 -2
- package/dist/{chunk-CDLETEDT.js → chunk-CQY5ML2A.js} +16 -3
- package/dist/{chunk-PTRXJS7Q.js → chunk-LQZL2D3Y.js} +1 -1
- package/dist/{chunk-PLLJIZC3.js → chunk-U7LRIWTF.js} +2471 -822
- package/dist/{client-CcYzmpmj.d.cts → client-C88GCTPB.d.cts} +211 -104
- package/dist/{client-CGTRS23n.d.ts → client-Dg6vS_2I.d.ts} +211 -104
- package/dist/debug.cjs +2511 -831
- package/dist/debug.d.cts +19 -6
- package/dist/debug.d.ts +19 -6
- package/dist/debug.js +3 -3
- package/dist/graphql/objects/index.cjs +13 -1
- package/dist/graphql/objects/index.d.cts +6 -51
- package/dist/graphql/objects/index.d.ts +6 -51
- package/dist/graphql/objects/index.js +1 -1
- package/dist/index.cjs +2491 -797
- package/dist/index.d.cts +189 -9
- package/dist/index.d.ts +189 -9
- package/dist/index.js +32 -4
- package/dist/index.node.cjs +2596 -799
- package/dist/index.node.d.cts +9 -190
- package/dist/index.node.d.ts +9 -190
- package/dist/index.node.js +134 -4
- package/dist/native/index.cjs +2491 -797
- package/dist/native/index.d.cts +309 -174
- package/dist/native/index.d.ts +309 -174
- package/dist/native/index.js +2495 -814
- package/dist/proto/lrc20.d.cts +1 -1
- package/dist/proto/lrc20.d.ts +1 -1
- package/dist/proto/spark.d.cts +1 -1
- package/dist/proto/spark.d.ts +1 -1
- package/dist/proto/spark_token.d.cts +1 -1
- package/dist/proto/spark_token.d.ts +1 -1
- package/dist/{spark-B_7nZx6T.d.cts → spark-ESAfZARg.d.cts} +1 -1
- package/dist/{spark-B_7nZx6T.d.ts → spark-ESAfZARg.d.ts} +1 -1
- package/dist/{spark-wallet-CxcGPXRB.d.ts → spark-wallet-B2WwKN8W.d.ts} +57 -35
- package/dist/{spark-wallet-DJJm19BP.d.cts → spark-wallet-Di65w0Us.d.cts} +57 -35
- package/dist/spark-wallet.node-7R0Rxyj9.d.cts +13 -0
- package/dist/spark-wallet.node-CSPWOWRu.d.ts +13 -0
- package/dist/tests/test-utils.cjs +578 -77
- package/dist/tests/test-utils.d.cts +12 -13
- package/dist/tests/test-utils.d.ts +12 -13
- package/dist/tests/test-utils.js +54 -17
- package/dist/types/index.cjs +16 -3
- package/dist/types/index.d.cts +3 -4
- package/dist/types/index.d.ts +3 -4
- package/dist/types/index.js +2 -2
- package/dist/{xchain-address-Bh9w1SeC.d.ts → xchain-address-BsveIy5l.d.ts} +56 -8
- package/dist/{xchain-address-SZ7dkVUE.d.cts → xchain-address-CqRu3F21.d.cts} +56 -8
- package/package.json +1 -1
- package/src/graphql/client.ts +57 -8
- package/src/graphql/mutations/CompleteLeavesSwap.ts +9 -1
- package/src/graphql/mutations/RequestSwapLeaves.ts +4 -0
- package/src/graphql/objects/CompleteLeavesSwapInput.ts +34 -34
- package/src/graphql/objects/LeavesSwapRequest.ts +4 -0
- package/src/graphql/objects/RequestLeavesSwapInput.ts +48 -47
- package/src/graphql/objects/SparkWalletUser.ts +1 -1
- package/src/graphql/objects/SwapLeaf.ts +40 -32
- package/src/graphql/objects/UserLeafInput.ts +24 -0
- package/src/graphql/objects/UserRequest.ts +4 -0
- package/src/graphql/queries/Transfers.ts +15 -0
- package/src/index.node.ts +1 -1
- package/src/native/index.ts +4 -5
- package/src/services/coop-exit.ts +171 -36
- package/src/services/deposit.ts +471 -74
- package/src/services/lightning.ts +18 -5
- package/src/services/signing.ts +162 -50
- package/src/services/transfer.ts +950 -384
- package/src/services/tree-creation.ts +342 -121
- package/src/spark-wallet/spark-wallet.node.ts +71 -66
- package/src/spark-wallet/spark-wallet.ts +561 -192
- package/src/tests/integration/coop-exit.test.ts +3 -8
- package/src/tests/integration/deposit.test.ts +3 -3
- package/src/tests/integration/lightning.test.ts +521 -466
- package/src/tests/integration/ssp/static_deposit.test.ts +83 -1
- package/src/tests/integration/ssp/transfers.test.ts +97 -0
- package/src/tests/integration/swap.test.ts +559 -307
- package/src/tests/integration/transfer.test.ts +625 -623
- package/src/tests/integration/wallet.test.ts +2 -2
- package/src/tests/integration/watchtower.test.ts +211 -0
- package/src/tests/test-utils.ts +63 -14
- package/src/tests/utils/test-faucet.ts +4 -2
- package/src/types/sdk-types.ts +15 -0
- package/src/utils/adaptor-signature.ts +15 -5
- package/src/utils/bitcoin.ts +13 -0
- package/src/utils/fetch.ts +75 -0
- package/src/utils/mempool.ts +9 -4
- package/src/utils/transaction.ts +388 -26
- package/dist/sdk-types-CB9HrW5O.d.cts +0 -44
- package/dist/sdk-types-CkRNraXT.d.ts +0 -44
- package/src/graphql/queries/Transfer.ts +0 -10
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from "@jest/globals";
|
|
2
|
-
import {
|
|
2
|
+
import { hexToBytes } from "@noble/curves/abstract/utils";
|
|
3
3
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
4
4
|
import { uuidv7 } from "uuidv7";
|
|
5
5
|
import { ValidationError } from "../../errors/types.js";
|
|
6
|
-
import {
|
|
6
|
+
import { KeyDerivationType } from "../../index.js";
|
|
7
7
|
import { WalletConfigService } from "../../services/config.js";
|
|
8
8
|
import { ConnectionManager } from "../../services/connection.js";
|
|
9
9
|
import { SigningService } from "../../services/signing.js";
|
|
@@ -12,146 +12,249 @@ import { TransferService } from "../../services/transfer.js";
|
|
|
12
12
|
import {
|
|
13
13
|
applyAdaptorToSignature,
|
|
14
14
|
generateAdaptorFromSignature,
|
|
15
|
+
validateOutboundAdaptorSignature,
|
|
15
16
|
} from "../../utils/adaptor-signature.js";
|
|
16
17
|
import {
|
|
17
18
|
computeTaprootKeyNoScript,
|
|
18
19
|
getSigHashFromTx,
|
|
19
20
|
} from "../../utils/bitcoin.js";
|
|
20
|
-
import {
|
|
21
|
+
import { walletTypes } from "../test-utils.js";
|
|
21
22
|
import { SparkWalletTesting } from "../utils/spark-testing-wallet.js";
|
|
22
23
|
import { BitcoinFaucet } from "../utils/test-faucet.js";
|
|
23
24
|
|
|
24
25
|
const testLocalOnly = process.env.GITHUB_ACTIONS ? it.skip : it;
|
|
25
26
|
|
|
26
|
-
describe.each(
|
|
27
|
+
describe.each(walletTypes)("swap", ({ name, Signer, createTree }) => {
|
|
28
|
+
let aliceWallet: SparkWalletTesting;
|
|
29
|
+
let aliceTransferService: TransferService;
|
|
30
|
+
|
|
31
|
+
let bobWallet: SparkWalletTesting;
|
|
32
|
+
let bobTransferService: TransferService;
|
|
33
|
+
|
|
34
|
+
beforeAll(async () => {
|
|
35
|
+
const { wallet: alice } = await SparkWalletTesting.initialize({
|
|
36
|
+
options: {
|
|
37
|
+
network: "LOCAL",
|
|
38
|
+
},
|
|
39
|
+
signer: new Signer(),
|
|
40
|
+
});
|
|
41
|
+
aliceWallet = alice;
|
|
42
|
+
const aliceConfig = new WalletConfigService(
|
|
43
|
+
{
|
|
44
|
+
network: "LOCAL",
|
|
45
|
+
},
|
|
46
|
+
alice.getSigner(),
|
|
47
|
+
);
|
|
48
|
+
const aliceConnectionManager = new ConnectionManager(aliceConfig);
|
|
49
|
+
const aliceSigningService = new SigningService(aliceConfig);
|
|
50
|
+
aliceTransferService = new TransferService(
|
|
51
|
+
aliceConfig,
|
|
52
|
+
aliceConnectionManager,
|
|
53
|
+
aliceSigningService,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const { wallet: bob } = await SparkWalletTesting.initialize({
|
|
57
|
+
options: {
|
|
58
|
+
network: "LOCAL",
|
|
59
|
+
},
|
|
60
|
+
signer: new Signer(),
|
|
61
|
+
});
|
|
62
|
+
bobWallet = bob;
|
|
63
|
+
const bobConfig = new WalletConfigService(
|
|
64
|
+
{
|
|
65
|
+
network: "LOCAL",
|
|
66
|
+
},
|
|
67
|
+
bobWallet.getSigner(),
|
|
68
|
+
);
|
|
69
|
+
const bobConnectionManager = new ConnectionManager(bobConfig);
|
|
70
|
+
const bobSigningService = new SigningService(bobConfig);
|
|
71
|
+
bobTransferService = new TransferService(
|
|
72
|
+
bobConfig,
|
|
73
|
+
bobConnectionManager,
|
|
74
|
+
bobSigningService,
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
27
78
|
testLocalOnly(
|
|
28
|
-
`${name} - test swap`,
|
|
79
|
+
`${name} - test swap v1`,
|
|
29
80
|
async () => {
|
|
30
81
|
const faucet = BitcoinFaucet.getInstance();
|
|
31
|
-
// Initiate sender
|
|
32
|
-
const { wallet: senderWallet } = await SparkWalletTesting.initialize({
|
|
33
|
-
options: {
|
|
34
|
-
network: "LOCAL",
|
|
35
|
-
},
|
|
36
|
-
signer: new Signer(),
|
|
37
|
-
});
|
|
38
|
-
const senderPubkey = await senderWallet.getIdentityPublicKey();
|
|
39
82
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
network: "LOCAL",
|
|
43
|
-
},
|
|
44
|
-
senderWallet.getSigner(),
|
|
45
|
-
);
|
|
46
|
-
const senderConnectionManager = new ConnectionManager(senderConfig);
|
|
47
|
-
const senderSigningService = new SigningService(senderConfig);
|
|
48
|
-
const senderTransferService = new TransferService(
|
|
49
|
-
senderConfig,
|
|
50
|
-
senderConnectionManager,
|
|
51
|
-
senderSigningService,
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
// Initiate receiver
|
|
55
|
-
const { wallet: receiverWallet } = await SparkWalletTesting.initialize({
|
|
56
|
-
options: {
|
|
57
|
-
network: "LOCAL",
|
|
58
|
-
},
|
|
59
|
-
signer: new Signer(),
|
|
60
|
-
});
|
|
61
|
-
const receiverPubkey = await receiverWallet.getIdentityPublicKey();
|
|
62
|
-
|
|
63
|
-
const receiverConfig = new WalletConfigService(
|
|
64
|
-
{
|
|
65
|
-
network: "LOCAL",
|
|
66
|
-
},
|
|
67
|
-
receiverWallet.getSigner(),
|
|
68
|
-
);
|
|
69
|
-
const receiverConnectionManager = new ConnectionManager(receiverConfig);
|
|
70
|
-
const receiverSigningService = new SigningService(receiverConfig);
|
|
71
|
-
const receiverTransferService = new TransferService(
|
|
72
|
-
receiverConfig,
|
|
73
|
-
receiverConnectionManager,
|
|
74
|
-
receiverSigningService,
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
const senderLeafId = uuidv7();
|
|
78
|
-
const senderRootNode = await createNewTree(
|
|
79
|
-
senderWallet,
|
|
80
|
-
senderLeafId,
|
|
81
|
-
faucet,
|
|
82
|
-
);
|
|
83
|
+
const aliceLeafId = uuidv7();
|
|
84
|
+
const aliceRootNode = await createTree(aliceWallet!, aliceLeafId, faucet);
|
|
83
85
|
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
receiverWallet,
|
|
87
|
-
receiverLeafId,
|
|
88
|
-
faucet,
|
|
89
|
-
);
|
|
86
|
+
const bobLeafId = uuidv7();
|
|
87
|
+
const bobRootNode = await createTree(bobWallet!, bobLeafId, faucet);
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const senderTransferNode: LeafKeyTweak = {
|
|
94
|
-
leaf: senderRootNode,
|
|
89
|
+
const aliceTransferNode: LeafKeyTweak = {
|
|
90
|
+
leaf: aliceRootNode,
|
|
95
91
|
keyDerivation: {
|
|
96
92
|
type: KeyDerivationType.LEAF,
|
|
97
|
-
path:
|
|
93
|
+
path: aliceLeafId,
|
|
98
94
|
},
|
|
99
95
|
newKeyDerivation: {
|
|
100
|
-
type: KeyDerivationType.
|
|
101
|
-
path: senderNewLeafId,
|
|
96
|
+
type: KeyDerivationType.RANDOM,
|
|
102
97
|
},
|
|
103
98
|
};
|
|
104
|
-
const
|
|
99
|
+
const aliceLeavesToTransfer = [aliceTransferNode];
|
|
105
100
|
|
|
106
|
-
// Get signature for refunds (normal flow)
|
|
107
101
|
const {
|
|
108
|
-
transfer:
|
|
109
|
-
signatureMap:
|
|
110
|
-
leafDataMap:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
102
|
+
transfer: aliceTransfer,
|
|
103
|
+
signatureMap: aliceRefundSignatureMap,
|
|
104
|
+
leafDataMap: aliceLeafDataMap,
|
|
105
|
+
directSignatureMap: aliceDirectRefundSignatureMap,
|
|
106
|
+
directFromCpfpSignatureMap: aliceDirectFromCpfpSignatureMap,
|
|
107
|
+
} = await aliceTransferService!.startSwapSignRefund(
|
|
108
|
+
aliceLeavesToTransfer,
|
|
109
|
+
hexToBytes(await bobWallet.getIdentityPublicKey()),
|
|
114
110
|
new Date(Date.now() + 10 * 60 * 1000),
|
|
115
111
|
);
|
|
116
112
|
|
|
117
|
-
expect(
|
|
118
|
-
const
|
|
119
|
-
expect(senderSignature).toBeDefined();
|
|
120
|
-
expect(senderLeafDataMap.size).toBe(1);
|
|
113
|
+
expect(aliceRefundSignatureMap.size).toBe(1);
|
|
114
|
+
const aliceSignature = aliceRefundSignatureMap.get(aliceRootNode.id);
|
|
121
115
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
116
|
+
expect(aliceSignature).toBeDefined();
|
|
117
|
+
expect(aliceDirectRefundSignatureMap.size).toBe(1);
|
|
118
|
+
const aliceDirectSignature = aliceDirectRefundSignatureMap.get(
|
|
119
|
+
aliceRootNode.id,
|
|
120
|
+
);
|
|
121
|
+
expect(aliceDirectSignature).toBeDefined();
|
|
122
|
+
expect(aliceDirectFromCpfpSignatureMap.size).toBe(1);
|
|
123
|
+
const aliceDirectFromCpfpSignature = aliceDirectFromCpfpSignatureMap.get(
|
|
124
|
+
aliceRootNode.id,
|
|
125
|
+
);
|
|
126
|
+
expect(aliceDirectFromCpfpSignature).toBeDefined();
|
|
127
|
+
expect(aliceLeafDataMap.size).toBe(1);
|
|
128
|
+
const aliceLeafData = aliceLeafDataMap.get(aliceRootNode.id);
|
|
129
|
+
expect(aliceLeafData).toBeDefined();
|
|
130
|
+
|
|
131
|
+
const aliceRefundSighash = getSigHashFromTx(
|
|
132
|
+
aliceLeafData!.refundTx!,
|
|
133
|
+
0,
|
|
134
|
+
aliceLeafData!.tx.getOutput(aliceLeafData!.vout),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
let aliceDirectSighash: Uint8Array | undefined;
|
|
138
|
+
let aliceDirectFromCpfpSighash: Uint8Array | undefined;
|
|
139
|
+
if (aliceLeafData!.directRefundTx) {
|
|
140
|
+
aliceDirectSighash = getSigHashFromTx(
|
|
141
|
+
aliceLeafData!.directRefundTx,
|
|
142
|
+
0,
|
|
143
|
+
aliceLeafData!.directTx!.getOutput(aliceLeafData!.vout),
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
if (aliceLeafData!.directFromCpfpRefundTx) {
|
|
147
|
+
aliceDirectFromCpfpSighash = getSigHashFromTx(
|
|
148
|
+
aliceLeafData!.directFromCpfpRefundTx,
|
|
149
|
+
0,
|
|
150
|
+
aliceLeafData!.tx.getOutput(aliceLeafData!.vout),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const {
|
|
155
|
+
adaptorSignature: cpfpAdaptorSignature,
|
|
156
|
+
adaptorPrivateKey: cpfpAdaptorPrivateKey,
|
|
157
|
+
} = generateAdaptorFromSignature(aliceSignature!);
|
|
158
|
+
|
|
159
|
+
let directAdaptorPrivateKey: Uint8Array | undefined;
|
|
160
|
+
let directFromCpfpAdaptorPrivateKey: Uint8Array | undefined;
|
|
161
|
+
let directAdaptorSignature: Uint8Array | undefined;
|
|
162
|
+
let directFromCpfpAdaptorSignature: Uint8Array | undefined;
|
|
163
|
+
if (aliceDirectSignature && aliceDirectSignature.length > 0) {
|
|
164
|
+
const { adaptorSignature, adaptorPrivateKey } =
|
|
165
|
+
generateAdaptorFromSignature(aliceDirectSignature);
|
|
166
|
+
directAdaptorPrivateKey = adaptorPrivateKey;
|
|
167
|
+
directAdaptorSignature = adaptorSignature;
|
|
168
|
+
}
|
|
169
|
+
if (
|
|
170
|
+
aliceDirectFromCpfpSignature &&
|
|
171
|
+
aliceDirectFromCpfpSignature.length > 0
|
|
172
|
+
) {
|
|
173
|
+
const { adaptorSignature, adaptorPrivateKey } =
|
|
174
|
+
generateAdaptorFromSignature(aliceDirectFromCpfpSignature);
|
|
175
|
+
directFromCpfpAdaptorPrivateKey = adaptorPrivateKey;
|
|
176
|
+
directFromCpfpAdaptorSignature = adaptorSignature;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const cpfpAdaptorPubKey = secp256k1.getPublicKey(cpfpAdaptorPrivateKey);
|
|
180
|
+
|
|
181
|
+
let directAdaptorPubKey: Uint8Array | undefined;
|
|
182
|
+
let directFromCpfpAdaptorPubKey: Uint8Array | undefined;
|
|
183
|
+
if (directAdaptorPrivateKey) {
|
|
184
|
+
directAdaptorPubKey = secp256k1.getPublicKey(directAdaptorPrivateKey);
|
|
185
|
+
}
|
|
186
|
+
if (directFromCpfpAdaptorPrivateKey) {
|
|
187
|
+
directFromCpfpAdaptorPubKey = secp256k1.getPublicKey(
|
|
188
|
+
directFromCpfpAdaptorPrivateKey,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const taprootKey = computeTaprootKeyNoScript(
|
|
193
|
+
aliceRootNode.verifyingPublicKey.slice(1, 33),
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
validateOutboundAdaptorSignature(
|
|
197
|
+
taprootKey.slice(1, 33),
|
|
198
|
+
aliceRefundSighash,
|
|
199
|
+
cpfpAdaptorSignature,
|
|
200
|
+
cpfpAdaptorPubKey,
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
if (aliceDirectSighash) {
|
|
204
|
+
validateOutboundAdaptorSignature(
|
|
205
|
+
taprootKey.slice(1, 33),
|
|
206
|
+
aliceDirectSighash,
|
|
207
|
+
directAdaptorSignature!,
|
|
208
|
+
directAdaptorPubKey!,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (aliceDirectFromCpfpSighash) {
|
|
213
|
+
validateOutboundAdaptorSignature(
|
|
214
|
+
taprootKey.slice(1, 33),
|
|
215
|
+
aliceDirectFromCpfpSighash,
|
|
216
|
+
directFromCpfpAdaptorSignature!,
|
|
217
|
+
directFromCpfpAdaptorPubKey!,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
125
220
|
|
|
126
|
-
const receiverNewLeafDerivation: KeyDerivation = {
|
|
127
|
-
type: KeyDerivationType.LEAF,
|
|
128
|
-
path: uuidv7(),
|
|
129
|
-
};
|
|
130
221
|
const receiverTransferNode: LeafKeyTweak = {
|
|
131
|
-
leaf:
|
|
222
|
+
leaf: bobRootNode,
|
|
132
223
|
keyDerivation: {
|
|
133
224
|
type: KeyDerivationType.LEAF,
|
|
134
|
-
path:
|
|
225
|
+
path: bobLeafId,
|
|
226
|
+
},
|
|
227
|
+
newKeyDerivation: {
|
|
228
|
+
type: KeyDerivationType.RANDOM,
|
|
135
229
|
},
|
|
136
|
-
newKeyDerivation: receiverNewLeafDerivation,
|
|
137
230
|
};
|
|
138
231
|
const receiverLeavesToTransfer = [receiverTransferNode];
|
|
139
232
|
|
|
140
233
|
const {
|
|
141
|
-
transfer:
|
|
142
|
-
signatureMap:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
234
|
+
transfer: bobTransfer,
|
|
235
|
+
signatureMap: bobRefundSignatureMap,
|
|
236
|
+
directSignatureMap: bobDirectRefundSignatureMap,
|
|
237
|
+
directFromCpfpSignatureMap: bobDirectFromCpfpSignatureMap,
|
|
238
|
+
leafDataMap: bobLeafDataMap,
|
|
239
|
+
signingResults: bobSigningResults,
|
|
240
|
+
} = await bobTransferService.counterSwapSignRefund(
|
|
146
241
|
receiverLeavesToTransfer,
|
|
147
|
-
hexToBytes(
|
|
242
|
+
hexToBytes(await aliceWallet.getIdentityPublicKey()),
|
|
148
243
|
new Date(Date.now() + 10 * 60 * 1000),
|
|
149
|
-
|
|
244
|
+
cpfpAdaptorPubKey,
|
|
245
|
+
directAdaptorPubKey,
|
|
246
|
+
directFromCpfpAdaptorPubKey,
|
|
150
247
|
);
|
|
151
248
|
|
|
152
249
|
const newReceiverRefundSignatureMap = new Map<string, Uint8Array>();
|
|
153
|
-
|
|
154
|
-
|
|
250
|
+
const newReceiverDirectRefundSignatureMap = new Map<string, Uint8Array>();
|
|
251
|
+
const newReceiverDirectFromCpfpRefundSignatureMap = new Map<
|
|
252
|
+
string,
|
|
253
|
+
Uint8Array
|
|
254
|
+
>();
|
|
255
|
+
|
|
256
|
+
for (const [nodeId, signature] of bobRefundSignatureMap.entries()) {
|
|
257
|
+
const leafData = bobLeafDataMap.get(nodeId);
|
|
155
258
|
if (!leafData?.refundTx) {
|
|
156
259
|
throw new ValidationError("Refund transaction not found", {
|
|
157
260
|
field: "refundTx",
|
|
@@ -164,7 +267,7 @@ describe.each(signerTypes)("swap", ({ name, Signer }) => {
|
|
|
164
267
|
leafData.tx.getOutput(leafData.vout),
|
|
165
268
|
);
|
|
166
269
|
let verifyingPubkey: Uint8Array | undefined;
|
|
167
|
-
for (const signingResult of
|
|
270
|
+
for (const signingResult of bobSigningResults) {
|
|
168
271
|
if (signingResult.leafId === nodeId) {
|
|
169
272
|
verifyingPubkey = signingResult.verifyingKey;
|
|
170
273
|
}
|
|
@@ -177,89 +280,137 @@ describe.each(signerTypes)("swap", ({ name, Signer }) => {
|
|
|
177
280
|
taprootKey.slice(1, 33),
|
|
178
281
|
sighash,
|
|
179
282
|
signature,
|
|
180
|
-
|
|
283
|
+
cpfpAdaptorPrivateKey,
|
|
181
284
|
);
|
|
182
285
|
newReceiverRefundSignatureMap.set(nodeId, adaptorSig);
|
|
183
286
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
287
|
+
|
|
288
|
+
for (const [nodeId, signature] of bobDirectRefundSignatureMap.entries()) {
|
|
289
|
+
const leafData = bobLeafDataMap.get(nodeId);
|
|
290
|
+
if (!leafData?.directRefundTx) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
const sighash = getSigHashFromTx(
|
|
294
|
+
leafData.directRefundTx,
|
|
295
|
+
0,
|
|
296
|
+
leafData.directTx!.getOutput(leafData.vout),
|
|
297
|
+
);
|
|
298
|
+
let verifyingPubkey: Uint8Array | undefined;
|
|
299
|
+
for (const signingResult of bobSigningResults) {
|
|
300
|
+
if (signingResult.leafId === nodeId) {
|
|
301
|
+
verifyingPubkey = signingResult.verifyingKey;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
expect(verifyingPubkey).toBeDefined();
|
|
305
|
+
const taprootKey = computeTaprootKeyNoScript(
|
|
306
|
+
verifyingPubkey!.slice(1, 33),
|
|
307
|
+
);
|
|
308
|
+
const adaptorSig = applyAdaptorToSignature(
|
|
309
|
+
taprootKey.slice(1, 33),
|
|
310
|
+
sighash,
|
|
311
|
+
signature,
|
|
312
|
+
directAdaptorPrivateKey ?? new Uint8Array(),
|
|
189
313
|
);
|
|
314
|
+
newReceiverDirectRefundSignatureMap.set(nodeId, adaptorSig);
|
|
315
|
+
}
|
|
190
316
|
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
317
|
+
for (const [
|
|
318
|
+
nodeId,
|
|
319
|
+
signature,
|
|
320
|
+
] of bobDirectFromCpfpSignatureMap.entries()) {
|
|
321
|
+
const leafData = bobLeafDataMap.get(nodeId);
|
|
322
|
+
if (!leafData?.directFromCpfpRefundTx) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const sighash = getSigHashFromTx(
|
|
326
|
+
leafData.directFromCpfpRefundTx,
|
|
327
|
+
0,
|
|
328
|
+
leafData.tx.getOutput(leafData.vout),
|
|
329
|
+
);
|
|
330
|
+
let verifyingPubkey: Uint8Array | undefined;
|
|
331
|
+
for (const signingResult of bobSigningResults) {
|
|
332
|
+
if (signingResult.leafId === nodeId) {
|
|
333
|
+
verifyingPubkey = signingResult.verifyingKey;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
expect(verifyingPubkey).toBeDefined();
|
|
337
|
+
const taprootKey = computeTaprootKeyNoScript(
|
|
338
|
+
verifyingPubkey!.slice(1, 33),
|
|
339
|
+
);
|
|
340
|
+
const adaptorSig = applyAdaptorToSignature(
|
|
341
|
+
taprootKey.slice(1, 33),
|
|
342
|
+
sighash,
|
|
343
|
+
signature,
|
|
344
|
+
directFromCpfpAdaptorPrivateKey ?? new Uint8Array(),
|
|
345
|
+
);
|
|
346
|
+
newReceiverDirectFromCpfpRefundSignatureMap.set(nodeId, adaptorSig);
|
|
347
|
+
}
|
|
196
348
|
|
|
197
|
-
const
|
|
198
|
-
await
|
|
199
|
-
|
|
349
|
+
const senderTransferTweakKey =
|
|
350
|
+
await aliceTransferService.sendTransferTweakKey(
|
|
351
|
+
aliceTransfer,
|
|
352
|
+
aliceLeavesToTransfer,
|
|
353
|
+
aliceRefundSignatureMap,
|
|
354
|
+
aliceDirectRefundSignatureMap,
|
|
355
|
+
aliceDirectFromCpfpSignatureMap,
|
|
200
356
|
);
|
|
201
357
|
|
|
202
|
-
|
|
203
|
-
expect(
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
358
|
+
const pendingTransfer = await bobTransferService.queryPendingTransfers();
|
|
359
|
+
expect(pendingTransfer.transfers.length).toBe(1);
|
|
360
|
+
const bobPendingTransfer = pendingTransfer.transfers[0];
|
|
361
|
+
expect(bobPendingTransfer!.id).toBe(senderTransferTweakKey.id);
|
|
362
|
+
|
|
363
|
+
const leafPrivKeyMap = await bobTransferService.verifyPendingTransfer(
|
|
364
|
+
bobPendingTransfer!,
|
|
209
365
|
);
|
|
210
|
-
expect(
|
|
211
|
-
expect(
|
|
366
|
+
expect(leafPrivKeyMap.size).toBe(1);
|
|
367
|
+
expect(leafPrivKeyMap.get(aliceRootNode.id)).toBeDefined();
|
|
212
368
|
|
|
213
|
-
const claimingNodes: LeafKeyTweak[] =
|
|
369
|
+
const claimingNodes: LeafKeyTweak[] = bobPendingTransfer!.leaves.map(
|
|
214
370
|
(leaf) => ({
|
|
215
371
|
leaf: leaf.leaf!,
|
|
216
372
|
keyDerivation: {
|
|
217
373
|
type: KeyDerivationType.ECIES,
|
|
218
|
-
path: leaf.secretCipher
|
|
374
|
+
path: leaf.secretCipher!,
|
|
219
375
|
},
|
|
220
376
|
newKeyDerivation: {
|
|
221
377
|
type: KeyDerivationType.LEAF,
|
|
222
|
-
path:
|
|
378
|
+
path: leaf.leaf!.id,
|
|
223
379
|
},
|
|
224
380
|
}),
|
|
225
381
|
);
|
|
226
|
-
|
|
227
|
-
|
|
382
|
+
|
|
383
|
+
await bobTransferService.claimTransfer(
|
|
384
|
+
bobPendingTransfer!,
|
|
228
385
|
claimingNodes,
|
|
229
386
|
);
|
|
230
|
-
await receiverTransferService.sendTransferTweakKey(
|
|
231
|
-
receiverTransfer,
|
|
232
|
-
receiverLeavesToTransfer,
|
|
233
|
-
newReceiverRefundSignatureMap,
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
const sPendingTransfer =
|
|
237
|
-
await senderTransferService.queryPendingTransfers();
|
|
238
|
-
expect(sPendingTransfer.transfers.length).toBe(1);
|
|
239
|
-
const senderPendingTransfer = sPendingTransfer.transfers[0];
|
|
240
|
-
expect(senderPendingTransfer!.id).toBe(receiverTransfer.id);
|
|
241
387
|
|
|
242
|
-
const
|
|
243
|
-
await
|
|
244
|
-
|
|
388
|
+
const senderTransferTweakKey2 =
|
|
389
|
+
await bobTransferService.sendTransferTweakKey(
|
|
390
|
+
bobTransfer,
|
|
391
|
+
receiverLeavesToTransfer,
|
|
392
|
+
newReceiverRefundSignatureMap,
|
|
393
|
+
newReceiverDirectRefundSignatureMap,
|
|
394
|
+
newReceiverDirectFromCpfpRefundSignatureMap,
|
|
245
395
|
);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
396
|
+
|
|
397
|
+
const pendingTransfer2 =
|
|
398
|
+
await aliceTransferService.queryPendingTransfers();
|
|
399
|
+
expect(pendingTransfer2.transfers.length).toBe(1);
|
|
400
|
+
const alicePendingTransfer2 = pendingTransfer2.transfers[0];
|
|
401
|
+
expect(alicePendingTransfer2!.id).toBe(senderTransferTweakKey2.id);
|
|
402
|
+
|
|
403
|
+
const leafPrivKeyMap2 = await aliceTransferService.verifyPendingTransfer(
|
|
404
|
+
alicePendingTransfer2!,
|
|
253
405
|
);
|
|
254
|
-
expect(
|
|
255
|
-
expect(senderPendingTransfer!.leaves[0]!.leaf).toBeDefined();
|
|
406
|
+
expect(leafPrivKeyMap2.size).toBe(1);
|
|
256
407
|
|
|
257
|
-
const
|
|
408
|
+
const claimingNodes2: LeafKeyTweak[] = alicePendingTransfer2!.leaves.map(
|
|
258
409
|
(leaf) => ({
|
|
259
410
|
leaf: leaf.leaf!,
|
|
260
411
|
keyDerivation: {
|
|
261
412
|
type: KeyDerivationType.ECIES,
|
|
262
|
-
path: leaf.secretCipher
|
|
413
|
+
path: leaf.secretCipher!,
|
|
263
414
|
},
|
|
264
415
|
newKeyDerivation: {
|
|
265
416
|
type: KeyDerivationType.LEAF,
|
|
@@ -267,143 +418,196 @@ describe.each(signerTypes)("swap", ({ name, Signer }) => {
|
|
|
267
418
|
},
|
|
268
419
|
}),
|
|
269
420
|
);
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
421
|
+
|
|
422
|
+
await aliceTransferService.claimTransfer(
|
|
423
|
+
alicePendingTransfer2!,
|
|
424
|
+
claimingNodes2,
|
|
273
425
|
);
|
|
274
426
|
},
|
|
275
|
-
|
|
427
|
+
30_000,
|
|
276
428
|
);
|
|
277
429
|
|
|
278
430
|
testLocalOnly(
|
|
279
431
|
`${name} - test swap v2`,
|
|
280
432
|
async () => {
|
|
281
433
|
const faucet = BitcoinFaucet.getInstance();
|
|
282
|
-
// Initiate sender
|
|
283
|
-
const { wallet: senderWallet } = await SparkWalletTesting.initialize({
|
|
284
|
-
options: {
|
|
285
|
-
network: "LOCAL",
|
|
286
|
-
},
|
|
287
|
-
signer: new Signer(),
|
|
288
|
-
});
|
|
289
|
-
const senderPubkey = await senderWallet.getIdentityPublicKey();
|
|
290
434
|
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
network: "LOCAL",
|
|
294
|
-
},
|
|
295
|
-
senderWallet.getSigner(),
|
|
296
|
-
);
|
|
297
|
-
const senderConnectionManager = new ConnectionManager(senderConfig);
|
|
298
|
-
const senderSigningService = new SigningService(senderConfig);
|
|
299
|
-
const senderTransferService = new TransferService(
|
|
300
|
-
senderConfig,
|
|
301
|
-
senderConnectionManager,
|
|
302
|
-
senderSigningService,
|
|
303
|
-
);
|
|
435
|
+
const aliceLeafId = uuidv7();
|
|
436
|
+
const aliceRootNode = await createTree(aliceWallet!, aliceLeafId, faucet);
|
|
304
437
|
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
options: {
|
|
308
|
-
network: "LOCAL",
|
|
309
|
-
},
|
|
310
|
-
signer: new Signer(),
|
|
311
|
-
});
|
|
312
|
-
const receiverPubkey = await receiverWallet.getIdentityPublicKey();
|
|
438
|
+
const bobLeafId = uuidv7();
|
|
439
|
+
const bobRootNode = await createTree(bobWallet!, bobLeafId, faucet);
|
|
313
440
|
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
441
|
+
const aliceTransferNode: LeafKeyTweak = {
|
|
442
|
+
leaf: aliceRootNode,
|
|
443
|
+
keyDerivation: {
|
|
444
|
+
type: KeyDerivationType.LEAF,
|
|
445
|
+
path: aliceLeafId,
|
|
446
|
+
},
|
|
447
|
+
newKeyDerivation: {
|
|
448
|
+
type: KeyDerivationType.RANDOM,
|
|
317
449
|
},
|
|
318
|
-
|
|
450
|
+
};
|
|
451
|
+
const aliceLeavesToTransfer = [aliceTransferNode];
|
|
452
|
+
|
|
453
|
+
const {
|
|
454
|
+
transfer: aliceTransfer,
|
|
455
|
+
signatureMap: aliceRefundSignatureMap,
|
|
456
|
+
directSignatureMap: aliceDirectRefundSignatureMap,
|
|
457
|
+
directFromCpfpSignatureMap: aliceDirectFromCpfpSignatureMap,
|
|
458
|
+
leafDataMap: aliceLeafDataMap,
|
|
459
|
+
} = await aliceTransferService.startSwapSignRefund(
|
|
460
|
+
aliceLeavesToTransfer,
|
|
461
|
+
hexToBytes(await bobWallet.getIdentityPublicKey()),
|
|
462
|
+
new Date(Date.now() + 10 * 60 * 1000),
|
|
319
463
|
);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
464
|
+
|
|
465
|
+
expect(aliceRefundSignatureMap.size).toBe(1);
|
|
466
|
+
const aliceSignature = aliceRefundSignatureMap.get(aliceRootNode.id);
|
|
467
|
+
expect(aliceSignature).toBeDefined();
|
|
468
|
+
|
|
469
|
+
expect(aliceDirectRefundSignatureMap.size).toBe(1);
|
|
470
|
+
const aliceDirectSignature = aliceDirectRefundSignatureMap.get(
|
|
471
|
+
aliceRootNode.id,
|
|
326
472
|
);
|
|
473
|
+
expect(aliceDirectSignature).toBeDefined();
|
|
327
474
|
|
|
328
|
-
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
senderLeafId,
|
|
332
|
-
faucet,
|
|
475
|
+
expect(aliceDirectFromCpfpSignatureMap.size).toBe(1);
|
|
476
|
+
const aliceDirectFromCpfpSignature = aliceDirectFromCpfpSignatureMap.get(
|
|
477
|
+
aliceRootNode.id,
|
|
333
478
|
);
|
|
479
|
+
expect(aliceDirectFromCpfpSignature).toBeDefined();
|
|
334
480
|
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
481
|
+
expect(aliceLeafDataMap.size).toBe(1);
|
|
482
|
+
const aliceLeafData = aliceLeafDataMap.get(aliceRootNode.id);
|
|
483
|
+
expect(aliceLeafData).toBeDefined();
|
|
484
|
+
|
|
485
|
+
const aliceRefundSighash = getSigHashFromTx(
|
|
486
|
+
aliceLeafData!.refundTx!,
|
|
487
|
+
0,
|
|
488
|
+
aliceLeafData!.tx.getOutput(aliceLeafData!.vout),
|
|
340
489
|
);
|
|
341
490
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
491
|
+
let aliceDirectSighash: Uint8Array | undefined;
|
|
492
|
+
let aliceDirectFromCpfpSighash: Uint8Array | undefined;
|
|
493
|
+
if (aliceLeafData!.directRefundTx) {
|
|
494
|
+
aliceDirectSighash = getSigHashFromTx(
|
|
495
|
+
aliceLeafData!.directRefundTx,
|
|
496
|
+
0,
|
|
497
|
+
aliceLeafData!.directTx!.getOutput(aliceLeafData!.vout),
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
if (aliceLeafData!.directFromCpfpRefundTx) {
|
|
501
|
+
aliceDirectFromCpfpSighash = getSigHashFromTx(
|
|
502
|
+
aliceLeafData!.directFromCpfpRefundTx,
|
|
503
|
+
0,
|
|
504
|
+
aliceLeafData!.tx.getOutput(aliceLeafData!.vout),
|
|
505
|
+
);
|
|
506
|
+
}
|
|
356
507
|
|
|
357
|
-
// Get signature for refunds (normal flow)
|
|
358
508
|
const {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
509
|
+
adaptorSignature: cpfpAdaptorSignature,
|
|
510
|
+
adaptorPrivateKey: cpfpAdaptorPrivateKey,
|
|
511
|
+
} = generateAdaptorFromSignature(aliceSignature!);
|
|
512
|
+
|
|
513
|
+
let directAdaptorPrivateKey: Uint8Array | undefined;
|
|
514
|
+
let directFromCpfpAdaptorPrivateKey: Uint8Array | undefined;
|
|
515
|
+
let directAdaptorSignature: Uint8Array | undefined;
|
|
516
|
+
let directFromCpfpAdaptorSignature: Uint8Array | undefined;
|
|
517
|
+
if (aliceDirectSignature && aliceDirectSignature.length > 0) {
|
|
518
|
+
const { adaptorSignature, adaptorPrivateKey } =
|
|
519
|
+
generateAdaptorFromSignature(aliceDirectSignature);
|
|
520
|
+
directAdaptorPrivateKey = adaptorPrivateKey;
|
|
521
|
+
directAdaptorSignature = adaptorSignature;
|
|
522
|
+
}
|
|
523
|
+
if (
|
|
524
|
+
aliceDirectFromCpfpSignature &&
|
|
525
|
+
aliceDirectFromCpfpSignature.length > 0
|
|
526
|
+
) {
|
|
527
|
+
const { adaptorSignature, adaptorPrivateKey } =
|
|
528
|
+
generateAdaptorFromSignature(aliceDirectFromCpfpSignature);
|
|
529
|
+
directFromCpfpAdaptorPrivateKey = adaptorPrivateKey;
|
|
530
|
+
directFromCpfpAdaptorSignature = adaptorSignature;
|
|
531
|
+
}
|
|
367
532
|
|
|
368
|
-
|
|
369
|
-
const senderSignature = senderRefundSignatureMap.get(senderRootNode.id);
|
|
370
|
-
expect(senderSignature).toBeDefined();
|
|
371
|
-
expect(senderLeafDataMap.size).toBe(1);
|
|
533
|
+
const cpfpAdaptorPubKey = secp256k1.getPublicKey(cpfpAdaptorPrivateKey);
|
|
372
534
|
|
|
373
|
-
|
|
374
|
-
|
|
535
|
+
let directAdaptorPubKey: Uint8Array | undefined;
|
|
536
|
+
let directFromCpfpAdaptorPubKey: Uint8Array | undefined;
|
|
537
|
+
if (directAdaptorPrivateKey) {
|
|
538
|
+
directAdaptorPubKey = secp256k1.getPublicKey(directAdaptorPrivateKey);
|
|
539
|
+
}
|
|
540
|
+
if (directFromCpfpAdaptorPrivateKey) {
|
|
541
|
+
directFromCpfpAdaptorPubKey = secp256k1.getPublicKey(
|
|
542
|
+
directFromCpfpAdaptorPrivateKey,
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const taprootKey = computeTaprootKeyNoScript(
|
|
547
|
+
aliceRootNode.verifyingPublicKey.slice(1, 33),
|
|
375
548
|
);
|
|
376
|
-
const adaptorPubKey = secp256k1.getPublicKey(adaptorPrivateKey);
|
|
377
549
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
550
|
+
validateOutboundAdaptorSignature(
|
|
551
|
+
taprootKey.slice(1, 33),
|
|
552
|
+
aliceRefundSighash,
|
|
553
|
+
cpfpAdaptorSignature,
|
|
554
|
+
cpfpAdaptorPubKey,
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
if (aliceDirectSighash) {
|
|
558
|
+
validateOutboundAdaptorSignature(
|
|
559
|
+
taprootKey.slice(1, 33),
|
|
560
|
+
aliceDirectSighash,
|
|
561
|
+
directAdaptorSignature!,
|
|
562
|
+
directAdaptorPubKey!,
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (aliceDirectFromCpfpSighash) {
|
|
567
|
+
validateOutboundAdaptorSignature(
|
|
568
|
+
taprootKey.slice(1, 33),
|
|
569
|
+
aliceDirectFromCpfpSighash,
|
|
570
|
+
directFromCpfpAdaptorSignature!,
|
|
571
|
+
directFromCpfpAdaptorPubKey!,
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
|
|
382
575
|
const receiverTransferNode: LeafKeyTweak = {
|
|
383
|
-
leaf:
|
|
576
|
+
leaf: bobRootNode,
|
|
384
577
|
keyDerivation: {
|
|
385
578
|
type: KeyDerivationType.LEAF,
|
|
386
|
-
path:
|
|
579
|
+
path: bobLeafId,
|
|
580
|
+
},
|
|
581
|
+
newKeyDerivation: {
|
|
582
|
+
type: KeyDerivationType.RANDOM,
|
|
387
583
|
},
|
|
388
|
-
newKeyDerivation: receiverNewLeafDerivation,
|
|
389
584
|
};
|
|
390
585
|
const receiverLeavesToTransfer = [receiverTransferNode];
|
|
391
586
|
|
|
392
587
|
const {
|
|
393
|
-
transfer:
|
|
394
|
-
signatureMap:
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
588
|
+
transfer: bobTransfer,
|
|
589
|
+
signatureMap: bobRefundSignatureMap,
|
|
590
|
+
directSignatureMap: bobDirectRefundSignatureMap,
|
|
591
|
+
directFromCpfpSignatureMap: bobDirectFromCpfpSignatureMap,
|
|
592
|
+
leafDataMap: bobLeafDataMap,
|
|
593
|
+
signingResults: bobSigningResults,
|
|
594
|
+
} = await bobTransferService.counterSwapSignRefund(
|
|
398
595
|
receiverLeavesToTransfer,
|
|
399
|
-
hexToBytes(
|
|
596
|
+
hexToBytes(await aliceWallet.getIdentityPublicKey()),
|
|
400
597
|
new Date(Date.now() + 10 * 60 * 1000),
|
|
401
|
-
|
|
598
|
+
cpfpAdaptorPubKey,
|
|
599
|
+
directAdaptorPubKey,
|
|
600
|
+
directFromCpfpAdaptorPubKey,
|
|
402
601
|
);
|
|
403
602
|
|
|
404
603
|
const newReceiverRefundSignatureMap = new Map<string, Uint8Array>();
|
|
405
|
-
|
|
406
|
-
|
|
604
|
+
const newReceiverDirectRefundSignatureMap = new Map<string, Uint8Array>();
|
|
605
|
+
const newReceiverDirectFromCpfpRefundSignatureMap = new Map<
|
|
606
|
+
string,
|
|
607
|
+
Uint8Array
|
|
608
|
+
>();
|
|
609
|
+
for (const [nodeId, signature] of bobRefundSignatureMap.entries()) {
|
|
610
|
+
const leafData = bobLeafDataMap.get(nodeId);
|
|
407
611
|
if (!leafData?.refundTx) {
|
|
408
612
|
throw new ValidationError("Refund transaction not found", {
|
|
409
613
|
field: "refundTx",
|
|
@@ -416,7 +620,7 @@ describe.each(signerTypes)("swap", ({ name, Signer }) => {
|
|
|
416
620
|
leafData.tx.getOutput(leafData.vout),
|
|
417
621
|
);
|
|
418
622
|
let verifyingPubkey: Uint8Array | undefined;
|
|
419
|
-
for (const signingResult of
|
|
623
|
+
for (const signingResult of bobSigningResults) {
|
|
420
624
|
if (signingResult.leafId === nodeId) {
|
|
421
625
|
verifyingPubkey = signingResult.verifyingKey;
|
|
422
626
|
}
|
|
@@ -429,44 +633,97 @@ describe.each(signerTypes)("swap", ({ name, Signer }) => {
|
|
|
429
633
|
taprootKey.slice(1, 33),
|
|
430
634
|
sighash,
|
|
431
635
|
signature,
|
|
432
|
-
|
|
636
|
+
cpfpAdaptorPrivateKey,
|
|
433
637
|
);
|
|
434
638
|
newReceiverRefundSignatureMap.set(nodeId, adaptorSig);
|
|
435
639
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
640
|
+
|
|
641
|
+
for (const [nodeId, signature] of bobDirectRefundSignatureMap.entries()) {
|
|
642
|
+
const leafData = bobLeafDataMap.get(nodeId);
|
|
643
|
+
if (!leafData?.directRefundTx) {
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
const sighash = getSigHashFromTx(
|
|
647
|
+
leafData.directRefundTx,
|
|
648
|
+
0,
|
|
649
|
+
leafData.directTx!.getOutput(leafData.vout),
|
|
650
|
+
);
|
|
651
|
+
let verifyingPubkey: Uint8Array | undefined;
|
|
652
|
+
for (const signingResult of bobSigningResults) {
|
|
653
|
+
if (signingResult.leafId === nodeId) {
|
|
654
|
+
verifyingPubkey = signingResult.verifyingKey;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
expect(verifyingPubkey).toBeDefined();
|
|
658
|
+
const taprootKey = computeTaprootKeyNoScript(
|
|
659
|
+
verifyingPubkey!.slice(1, 33),
|
|
441
660
|
);
|
|
661
|
+
const adaptorSig = applyAdaptorToSignature(
|
|
662
|
+
taprootKey.slice(1, 33),
|
|
663
|
+
sighash,
|
|
664
|
+
signature,
|
|
665
|
+
directAdaptorPrivateKey ?? new Uint8Array(),
|
|
666
|
+
);
|
|
667
|
+
newReceiverDirectRefundSignatureMap.set(nodeId, adaptorSig);
|
|
668
|
+
}
|
|
442
669
|
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
670
|
+
for (const [
|
|
671
|
+
nodeId,
|
|
672
|
+
signature,
|
|
673
|
+
] of bobDirectFromCpfpSignatureMap.entries()) {
|
|
674
|
+
const leafData = bobLeafDataMap.get(nodeId);
|
|
675
|
+
if (!leafData?.directFromCpfpRefundTx) {
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
const sighash = getSigHashFromTx(
|
|
679
|
+
leafData.directFromCpfpRefundTx,
|
|
680
|
+
0,
|
|
681
|
+
leafData.tx.getOutput(leafData.vout),
|
|
682
|
+
);
|
|
683
|
+
let verifyingPubkey: Uint8Array | undefined;
|
|
684
|
+
for (const signingResult of bobSigningResults) {
|
|
685
|
+
if (signingResult.leafId === nodeId) {
|
|
686
|
+
verifyingPubkey = signingResult.verifyingKey;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
expect(verifyingPubkey).toBeDefined();
|
|
690
|
+
const taprootKey = computeTaprootKeyNoScript(
|
|
691
|
+
verifyingPubkey!.slice(1, 33),
|
|
692
|
+
);
|
|
693
|
+
const adaptorSig = applyAdaptorToSignature(
|
|
694
|
+
taprootKey.slice(1, 33),
|
|
695
|
+
sighash,
|
|
696
|
+
signature,
|
|
697
|
+
directFromCpfpAdaptorPrivateKey ?? new Uint8Array(),
|
|
698
|
+
);
|
|
699
|
+
newReceiverDirectFromCpfpRefundSignatureMap.set(nodeId, adaptorSig);
|
|
700
|
+
}
|
|
448
701
|
|
|
449
|
-
const
|
|
450
|
-
await
|
|
451
|
-
|
|
702
|
+
const senderTransferTweakKey =
|
|
703
|
+
await aliceTransferService.deliverTransferPackage(
|
|
704
|
+
aliceTransfer,
|
|
705
|
+
aliceLeavesToTransfer,
|
|
706
|
+
aliceRefundSignatureMap,
|
|
707
|
+
aliceDirectRefundSignatureMap,
|
|
708
|
+
aliceDirectFromCpfpSignatureMap,
|
|
452
709
|
);
|
|
453
710
|
|
|
454
|
-
|
|
455
|
-
expect(
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
711
|
+
const pendingTransfer = await bobTransferService.queryPendingTransfers();
|
|
712
|
+
expect(pendingTransfer.transfers.length).toBe(1);
|
|
713
|
+
const bobPendingTransfer = pendingTransfer.transfers[0];
|
|
714
|
+
expect(bobPendingTransfer!.id).toBe(senderTransferTweakKey.id);
|
|
715
|
+
|
|
716
|
+
const leafPrivKeyMap = await bobTransferService.verifyPendingTransfer(
|
|
717
|
+
bobPendingTransfer!,
|
|
461
718
|
);
|
|
462
|
-
expect(
|
|
463
|
-
|
|
464
|
-
const claimingNodes: LeafKeyTweak[] =
|
|
719
|
+
expect(leafPrivKeyMap.size).toBe(1);
|
|
720
|
+
|
|
721
|
+
const claimingNodes: LeafKeyTweak[] = bobPendingTransfer!.leaves.map(
|
|
465
722
|
(leaf) => ({
|
|
466
723
|
leaf: leaf.leaf!,
|
|
467
724
|
keyDerivation: {
|
|
468
725
|
type: KeyDerivationType.ECIES,
|
|
469
|
-
path: leaf.secretCipher
|
|
726
|
+
path: leaf.secretCipher!,
|
|
470
727
|
},
|
|
471
728
|
newKeyDerivation: {
|
|
472
729
|
type: KeyDerivationType.LEAF,
|
|
@@ -474,43 +731,37 @@ describe.each(signerTypes)("swap", ({ name, Signer }) => {
|
|
|
474
731
|
},
|
|
475
732
|
}),
|
|
476
733
|
);
|
|
477
|
-
|
|
478
|
-
|
|
734
|
+
|
|
735
|
+
await bobTransferService.claimTransfer(
|
|
736
|
+
bobPendingTransfer!,
|
|
479
737
|
claimingNodes,
|
|
480
738
|
);
|
|
481
|
-
|
|
482
|
-
|
|
739
|
+
|
|
740
|
+
await bobTransferService.deliverTransferPackage(
|
|
741
|
+
bobTransfer,
|
|
483
742
|
receiverLeavesToTransfer,
|
|
484
743
|
newReceiverRefundSignatureMap,
|
|
744
|
+
newReceiverDirectRefundSignatureMap,
|
|
745
|
+
newReceiverDirectFromCpfpRefundSignatureMap,
|
|
485
746
|
);
|
|
486
747
|
|
|
487
|
-
const
|
|
488
|
-
await
|
|
489
|
-
expect(
|
|
490
|
-
const
|
|
491
|
-
expect(
|
|
748
|
+
const pendingTransfer1 =
|
|
749
|
+
await aliceTransferService.queryPendingTransfers();
|
|
750
|
+
expect(pendingTransfer1.transfers.length).toBe(1);
|
|
751
|
+
const alicePendingTransfer = pendingTransfer1.transfers[0];
|
|
752
|
+
expect(alicePendingTransfer!.id).toBe(bobTransfer.id);
|
|
492
753
|
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
senderPendingTransfer!,
|
|
496
|
-
);
|
|
497
|
-
expect(senderLeafPrivKeyMap.size).toBe(1);
|
|
498
|
-
expect(senderLeafPrivKeyMap.get(receiverRootNode.id)).toBeDefined();
|
|
499
|
-
const bytesEqual_1 = equalBytes(
|
|
500
|
-
senderLeafPrivKeyMap.get(receiverRootNode.id)!,
|
|
501
|
-
await receiverWallet
|
|
502
|
-
.getSigner()
|
|
503
|
-
.getPublicKeyFromDerivation(receiverNewLeafDerivation),
|
|
754
|
+
const leafPrivKeyMap1 = await aliceTransferService.verifyPendingTransfer(
|
|
755
|
+
alicePendingTransfer!,
|
|
504
756
|
);
|
|
505
|
-
expect(
|
|
506
|
-
expect(senderPendingTransfer!.leaves[0]!.leaf).toBeDefined();
|
|
757
|
+
expect(leafPrivKeyMap1.size).toBe(1);
|
|
507
758
|
|
|
508
|
-
const
|
|
759
|
+
const claimingNodes1: LeafKeyTweak[] = alicePendingTransfer!.leaves.map(
|
|
509
760
|
(leaf) => ({
|
|
510
761
|
leaf: leaf.leaf!,
|
|
511
762
|
keyDerivation: {
|
|
512
763
|
type: KeyDerivationType.ECIES,
|
|
513
|
-
path: leaf.secretCipher
|
|
764
|
+
path: leaf.secretCipher!,
|
|
514
765
|
},
|
|
515
766
|
newKeyDerivation: {
|
|
516
767
|
type: KeyDerivationType.LEAF,
|
|
@@ -518,11 +769,12 @@ describe.each(signerTypes)("swap", ({ name, Signer }) => {
|
|
|
518
769
|
},
|
|
519
770
|
}),
|
|
520
771
|
);
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
772
|
+
|
|
773
|
+
await aliceTransferService.claimTransfer(
|
|
774
|
+
alicePendingTransfer!,
|
|
775
|
+
claimingNodes1,
|
|
524
776
|
);
|
|
525
777
|
},
|
|
526
|
-
|
|
778
|
+
30_000,
|
|
527
779
|
);
|
|
528
780
|
});
|