@atomicfinance/bitcoin-dlc-provider 3.5.0 → 3.5.1

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.
@@ -0,0 +1,2027 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const provider_1 = __importDefault(require("@atomicfinance/provider"));
7
+ const types_1 = require("@atomicfinance/types");
8
+ const utils_1 = require("@atomicfinance/utils");
9
+ const core_1 = require("@node-dlc/core");
10
+ const messaging_1 = require("@node-dlc/messaging");
11
+ const bitcoin_1 = require("@node-lightning/bitcoin");
12
+ const bufio_1 = require("@node-lightning/bufio");
13
+ const crypto_1 = require("@node-lightning/crypto");
14
+ const assert_1 = __importDefault(require("assert"));
15
+ const bignumber_js_1 = __importDefault(require("bignumber.js"));
16
+ const bitcoin_networks_1 = require("bitcoin-networks");
17
+ const bitcoinjs_lib_1 = require("bitcoinjs-lib");
18
+ const Utils_1 = require("./utils/Utils");
19
+ class BitcoinDlcProvider extends provider_1.default {
20
+ constructor(network, cfdDlcJs) {
21
+ super();
22
+ this._network = network;
23
+ this._cfdDlcJs = cfdDlcJs;
24
+ }
25
+ async CfdLoaded() {
26
+ while (!this._cfdDlcJs) {
27
+ await (0, utils_1.sleep)(10);
28
+ }
29
+ }
30
+ async GetPrivKeysForInputs(inputs) {
31
+ const privKeys = [];
32
+ for (let i = 0; i < inputs.length; i++) {
33
+ const input = inputs[i];
34
+ let derivationPath = input.derivationPath;
35
+ if (!derivationPath) {
36
+ derivationPath = (await this.getMethod('getWalletAddress')(input.address)).derivationPath;
37
+ }
38
+ const keyPair = await this.getMethod('keyPair')(derivationPath);
39
+ const privKey = Buffer.from(keyPair.__D).toString('hex');
40
+ privKeys.push(privKey);
41
+ }
42
+ return privKeys;
43
+ }
44
+ async GetCfdNetwork() {
45
+ const network = await this.getConnectedNetwork();
46
+ switch (network.name) {
47
+ case 'bitcoin_testnet':
48
+ return 'testnet';
49
+ case 'bitcoin_regtest':
50
+ return 'regtest';
51
+ default:
52
+ return 'bitcoin';
53
+ }
54
+ }
55
+ async GetInputsForAmount(amounts, feeRatePerVb, fixedInputs = []) {
56
+ if (amounts.length === 0)
57
+ return [];
58
+ const fixedUtxos = fixedInputs.map((input) => input.toUtxo());
59
+ let inputs;
60
+ try {
61
+ const inputsForAmount = await this.getMethod('getInputsForDualFunding')(amounts, feeRatePerVb, fixedUtxos);
62
+ inputs = inputsForAmount.inputs;
63
+ }
64
+ catch (e) {
65
+ const errorMessage = e instanceof Error ? e.message : 'Unknown error';
66
+ if (fixedInputs.length === 0) {
67
+ throw Error(`Not enough balance getInputsForAmount. Error: ${errorMessage}`);
68
+ }
69
+ else {
70
+ inputs = fixedInputs;
71
+ }
72
+ }
73
+ return inputs;
74
+ }
75
+ async Initialize(collateral, feeRatePerVb, fixedInputs) {
76
+ const network = await this.getConnectedNetwork();
77
+ const payoutAddress = await this.client.wallet.getUnusedAddress(false);
78
+ const payoutSPK = bitcoinjs_lib_1.address.toOutputScript(payoutAddress.address, network);
79
+ const changeAddress = await this.client.wallet.getUnusedAddress(true);
80
+ const changeSPK = bitcoinjs_lib_1.address.toOutputScript(changeAddress.address, network);
81
+ const fundingAddress = await this.client.wallet.getUnusedAddress(false);
82
+ const fundingPubKey = Buffer.from(fundingAddress.publicKey, 'hex');
83
+ if (fundingAddress.address === payoutAddress.address)
84
+ throw Error('Address reuse');
85
+ const inputs = await this.GetInputsForAmount([collateral], feeRatePerVb, fixedInputs);
86
+ const fundingInputs = await Promise.all(inputs.map(async (input) => {
87
+ return this.inputToFundingInput(input);
88
+ }));
89
+ const payoutSerialId = (0, Utils_1.generateSerialId)();
90
+ const changeSerialId = (0, Utils_1.generateSerialId)();
91
+ return {
92
+ fundingPubKey,
93
+ payoutSPK,
94
+ payoutSerialId,
95
+ fundingInputs,
96
+ changeSPK,
97
+ changeSerialId,
98
+ };
99
+ }
100
+ async BatchInitialize(collaterals, feeRatePerVb, fixedInputs) {
101
+ const network = await this.getConnectedNetwork();
102
+ const inputs = await this.GetInputsForAmount(collaterals, feeRatePerVb, fixedInputs);
103
+ const fundingInputs = await Promise.all(inputs.map(async (input) => {
104
+ return this.inputToFundingInput(input);
105
+ }));
106
+ const initializeResponses = [];
107
+ const changeSerialId = (0, Utils_1.generateSerialId)();
108
+ const changeAddress = await this.client.wallet.getUnusedAddress(true);
109
+ const changeSPK = bitcoinjs_lib_1.address.toOutputScript(changeAddress.address, network);
110
+ for (let i = 0; i < collaterals.length; i++) {
111
+ const payoutAddress = await this.client.wallet.getUnusedAddress(false);
112
+ const payoutSPK = bitcoinjs_lib_1.address.toOutputScript(payoutAddress.address, network);
113
+ const fundingAddress = await this.client.wallet.getUnusedAddress(false);
114
+ const fundingPubKey = Buffer.from(fundingAddress.publicKey, 'hex');
115
+ if (fundingAddress.address === payoutAddress.address)
116
+ throw Error('Address reuse');
117
+ const payoutSerialId = (0, Utils_1.generateSerialId)();
118
+ initializeResponses.push({
119
+ fundingPubKey,
120
+ payoutSPK,
121
+ payoutSerialId,
122
+ });
123
+ }
124
+ return { fundingInputs, initializeResponses, changeSerialId, changeSPK };
125
+ }
126
+ /**
127
+ * TODO: Add GetPayoutFromOutcomes
128
+ *
129
+ * private GetPayoutsFromOutcomes(
130
+ * contractDescriptor: ContractDescriptorV0,
131
+ * totalCollateral: bigint,
132
+ * ): PayoutRequest[] {}
133
+ */
134
+ GetPayoutsFromPayoutFunction(_dlcOffer, contractDescriptor, oracleInfo, totalCollateral) {
135
+ if (_dlcOffer.type !== messaging_1.MessageType.DlcOfferV0)
136
+ throw Error('DlcOffer must be V0');
137
+ const dlcOffer = _dlcOffer;
138
+ if (contractDescriptor.payoutFunction.type !== messaging_1.MessageType.PayoutFunctionV0)
139
+ throw Error('PayoutFunction must be V0');
140
+ const payoutFunction = contractDescriptor.payoutFunction;
141
+ if (payoutFunction.pieces.length === 0)
142
+ throw Error('PayoutFunction must have at least once PayoutCurvePiece');
143
+ if (payoutFunction.pieces.length > 1)
144
+ throw Error('More than one PayoutCurvePiece not supported');
145
+ const payoutCurvePiece = payoutFunction.pieces[0]
146
+ .payoutCurvePiece;
147
+ if (payoutCurvePiece.type !== messaging_1.MessageType.HyperbolaPayoutCurvePiece &&
148
+ payoutCurvePiece.type !== messaging_1.MessageType.OldHyperbolaPayoutCurvePiece)
149
+ throw Error('Must be HyperbolaPayoutCurvePiece');
150
+ if (payoutCurvePiece.b !== BigInt(0) || payoutCurvePiece.c !== BigInt(0))
151
+ throw Error('b and c HyperbolaPayoutCurvePiece values must be 0');
152
+ const eventDescriptor = oracleInfo.announcement.oracleEvent
153
+ .eventDescriptor;
154
+ if (eventDescriptor.type !== messaging_1.MessageType.DigitDecompositionEventDescriptorV0)
155
+ throw Error('Only DigitDecomposition Oracle Events supported');
156
+ const roundingIntervals = contractDescriptor.roundingIntervals;
157
+ const cetPayouts = core_1.HyperbolaPayoutCurve.computePayouts(payoutFunction, totalCollateral, roundingIntervals);
158
+ const payoutGroups = [];
159
+ cetPayouts.forEach((p) => {
160
+ payoutGroups.push({
161
+ payout: p.payout,
162
+ groups: (0, core_1.groupByIgnoringDigits)(p.indexFrom, p.indexTo, eventDescriptor.base, contractDescriptor.numDigits),
163
+ });
164
+ });
165
+ const rValuesMessagesList = this.GenerateMessages(oracleInfo);
166
+ const { payouts, messagesList } = (0, Utils_1.outputsToPayouts)(payoutGroups, rValuesMessagesList, dlcOffer.offerCollateralSatoshis, dlcOffer.contractInfo.totalCollateral - dlcOffer.offerCollateralSatoshis, true);
167
+ return { payouts, payoutGroups, messagesList };
168
+ }
169
+ GetPayoutsFromPolynomialPayoutFunction(_dlcOffer, contractDescriptor, oracleInfo, totalCollateral) {
170
+ if (_dlcOffer.type !== messaging_1.MessageType.DlcOfferV0)
171
+ throw Error('DlcOffer must be V0');
172
+ const dlcOffer = _dlcOffer;
173
+ if (contractDescriptor.payoutFunction.type !== messaging_1.MessageType.PayoutFunctionV0)
174
+ throw Error('PayoutFunction must be V0');
175
+ const payoutFunction = contractDescriptor.payoutFunction;
176
+ if (payoutFunction.pieces.length === 0)
177
+ throw Error('PayoutFunction must have at least once PayoutCurvePiece');
178
+ for (const piece of payoutFunction.pieces) {
179
+ if (piece.payoutCurvePiece.type !== messaging_1.MessageType.PolynomialPayoutCurvePiece)
180
+ throw Error('Must be PolynomialPayoutCurvePiece');
181
+ }
182
+ const eventDescriptor = oracleInfo.announcement.oracleEvent
183
+ .eventDescriptor;
184
+ if (eventDescriptor.type !== messaging_1.MessageType.DigitDecompositionEventDescriptorV0)
185
+ throw Error('Only DigitDecomposition Oracle Events supported');
186
+ const roundingIntervals = contractDescriptor.roundingIntervals;
187
+ const cetPayouts = core_1.PolynomialPayoutCurve.computePayouts(payoutFunction, totalCollateral, roundingIntervals);
188
+ const payoutGroups = [];
189
+ cetPayouts.forEach((p) => {
190
+ payoutGroups.push({
191
+ payout: p.payout,
192
+ groups: (0, core_1.groupByIgnoringDigits)(p.indexFrom, p.indexTo, eventDescriptor.base, contractDescriptor.numDigits),
193
+ });
194
+ });
195
+ const rValuesMessagesList = this.GenerateMessages(oracleInfo);
196
+ const { payouts, messagesList } = (0, Utils_1.outputsToPayouts)(payoutGroups, rValuesMessagesList, dlcOffer.offerCollateralSatoshis, dlcOffer.contractInfo.totalCollateral - dlcOffer.offerCollateralSatoshis, true);
197
+ return { payouts, payoutGroups, messagesList };
198
+ }
199
+ GetPayouts(_dlcOffer) {
200
+ const { dlcOffer } = (0, Utils_1.checkTypes)({ _dlcOffer });
201
+ const contractInfo = dlcOffer.contractInfo;
202
+ const totalCollateral = contractInfo.totalCollateral;
203
+ const contractOraclePairs = this.GetContractOraclePairs(contractInfo);
204
+ const payoutResponses = contractOraclePairs.map(({ contractDescriptor, oracleInfo }) => this.GetPayoutsFromContractDescriptor(dlcOffer, contractDescriptor, oracleInfo, totalCollateral));
205
+ return payoutResponses;
206
+ }
207
+ FlattenPayouts(payoutResponses) {
208
+ return payoutResponses.reduce((acc, { payouts, payoutGroups, messagesList }) => {
209
+ return {
210
+ payouts: acc.payouts.concat(payouts),
211
+ payoutGroups: acc.payoutGroups.concat(payoutGroups),
212
+ messagesList: acc.messagesList.concat(messagesList),
213
+ };
214
+ });
215
+ }
216
+ GetIndicesFromPayouts(payoutResponses) {
217
+ return payoutResponses.reduce((prev, acc) => {
218
+ return prev.concat({
219
+ startingMessagesIndex: prev[prev.length - 1].startingMessagesIndex +
220
+ acc.messagesList.length,
221
+ startingPayoutGroupsIndex: prev[prev.length - 1].startingPayoutGroupsIndex +
222
+ acc.payoutGroups.length,
223
+ });
224
+ }, [{ startingMessagesIndex: 0, startingPayoutGroupsIndex: 0 }]);
225
+ }
226
+ GetPayoutsFromContractDescriptor(dlcOffer, contractDescriptor, oracleInfo, totalCollateral) {
227
+ switch (contractDescriptor.type) {
228
+ case messaging_1.MessageType.ContractDescriptorV0: {
229
+ throw Error('ContractDescriptorV0 not yet supported');
230
+ }
231
+ case messaging_1.MessageType.ContractDescriptorV1:
232
+ {
233
+ const contractDescriptorV1 = contractDescriptor;
234
+ const payoutFunction = contractDescriptorV1.payoutFunction;
235
+ // TODO: add a better check for this
236
+ const payoutCurvePiece = payoutFunction.pieces[0].payoutCurvePiece;
237
+ switch (payoutCurvePiece.type) {
238
+ case messaging_1.MessageType.HyperbolaPayoutCurvePiece:
239
+ return this.GetPayoutsFromPayoutFunction(dlcOffer, contractDescriptor, oracleInfo, totalCollateral);
240
+ case messaging_1.MessageType.OldHyperbolaPayoutCurvePiece:
241
+ return this.GetPayoutsFromPayoutFunction(dlcOffer, contractDescriptor, oracleInfo, totalCollateral);
242
+ case messaging_1.MessageType.PolynomialPayoutCurvePiece:
243
+ return this.GetPayoutsFromPolynomialPayoutFunction(dlcOffer, contractDescriptor, oracleInfo, totalCollateral);
244
+ }
245
+ }
246
+ break;
247
+ default: {
248
+ throw Error('ContractDescriptor must be V0 or V1');
249
+ }
250
+ }
251
+ }
252
+ async createDlcTxs(_dlcOffer, _dlcAccept) {
253
+ const { dlcOffer, dlcAccept } = (0, Utils_1.checkTypes)({
254
+ _dlcOffer,
255
+ _dlcAccept,
256
+ });
257
+ const localFundPubkey = dlcOffer.fundingPubKey.toString('hex');
258
+ const remoteFundPubkey = dlcAccept.fundingPubKey.toString('hex');
259
+ const localFinalScriptPubkey = dlcOffer.payoutSPK.toString('hex');
260
+ const remoteFinalScriptPubkey = dlcAccept.payoutSPK.toString('hex');
261
+ const localChangeScriptPubkey = dlcOffer.changeSPK.toString('hex');
262
+ const remoteChangeScriptPubkey = dlcAccept.changeSPK.toString('hex');
263
+ const localInputs = await Promise.all(dlcOffer.fundingInputs.map(async (fundingInput) => {
264
+ const input = await this.fundingInputToInput(fundingInput, false);
265
+ return input.toUtxo();
266
+ }));
267
+ const remoteInputs = await Promise.all(dlcAccept.fundingInputs.map(async (fundingInput) => {
268
+ const input = await this.fundingInputToInput(fundingInput, false);
269
+ return input.toUtxo();
270
+ }));
271
+ const localInputAmount = localInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
272
+ const remoteInputAmount = remoteInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
273
+ const payoutResponses = this.GetPayouts(dlcOffer);
274
+ const { payouts, messagesList } = this.FlattenPayouts(payoutResponses);
275
+ const dlcTxRequest = {
276
+ payouts,
277
+ localFundPubkey,
278
+ localFinalScriptPubkey,
279
+ remoteFundPubkey,
280
+ remoteFinalScriptPubkey,
281
+ localInputAmount,
282
+ localCollateralAmount: dlcOffer.offerCollateralSatoshis,
283
+ localPayoutSerialId: dlcOffer.payoutSerialId,
284
+ localChangeSerialId: dlcOffer.changeSerialId,
285
+ remoteInputAmount,
286
+ remoteCollateralAmount: dlcAccept.acceptCollateralSatoshis,
287
+ remotePayoutSerialId: dlcAccept.payoutSerialId,
288
+ remoteChangeSerialId: dlcAccept.changeSerialId,
289
+ refundLocktime: dlcOffer.refundLocktime,
290
+ localInputs,
291
+ remoteInputs,
292
+ localChangeScriptPubkey,
293
+ remoteChangeScriptPubkey,
294
+ feeRate: Number(dlcOffer.feeRatePerVb),
295
+ cetLockTime: dlcOffer.cetLocktime,
296
+ fundOutputSerialId: dlcOffer.fundOutputSerialId,
297
+ };
298
+ const dlcTxs = await this.CreateDlcTransactions(dlcTxRequest);
299
+ const dlcTransactions = new messaging_1.DlcTransactionsV0();
300
+ dlcTransactions.fundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(dlcTxs.fundTxHex));
301
+ dlcTransactions.fundTxVout = [
302
+ BigInt(dlcOffer.changeSerialId),
303
+ BigInt(dlcAccept.changeSerialId),
304
+ BigInt(dlcTxRequest.fundOutputSerialId),
305
+ ]
306
+ .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
307
+ .findIndex((i) => BigInt(i) === BigInt(dlcTxRequest.fundOutputSerialId));
308
+ dlcTransactions.refundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(dlcTxs.refundTxHex));
309
+ dlcTransactions.cets = dlcTxs.cetsHex.map((cetHex) => {
310
+ return bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(cetHex));
311
+ });
312
+ return { dlcTransactions, messagesList };
313
+ }
314
+ async createBatchDlcTxs(_dlcOffers, _dlcAccepts) {
315
+ const dlcOffers = _dlcOffers.map((dlcOffer) => {
316
+ return (0, Utils_1.checkTypes)({ _dlcOffer: dlcOffer }).dlcOffer;
317
+ });
318
+ const dlcAccepts = _dlcAccepts.map((dlcAccept) => {
319
+ return (0, Utils_1.checkTypes)({ _dlcAccept: dlcAccept }).dlcAccept;
320
+ });
321
+ const localFundPubkeys = dlcOffers.map((dlcOffer) => dlcOffer.fundingPubKey.toString('hex'));
322
+ const remoteFundPubkeys = dlcAccepts.map((dlcAccept) => dlcAccept.fundingPubKey.toString('hex'));
323
+ const localFinalScriptPubkeys = dlcOffers.map((dlcOffer) => dlcOffer.payoutSPK.toString('hex'));
324
+ const remoteFinalScriptPubkeys = dlcAccepts.map((dlcAccept) => dlcAccept.payoutSPK.toString('hex'));
325
+ const localChangeScriptPubkey = dlcOffers[0].changeSPK.toString('hex');
326
+ const remoteChangeScriptPubkey = dlcAccepts[0].changeSPK.toString('hex');
327
+ const localInputs = await Promise.all(dlcOffers[0].fundingInputs.map(async (fundingInput) => {
328
+ const input = await this.fundingInputToInput(fundingInput, false);
329
+ return input.toUtxo();
330
+ }));
331
+ const remoteInputs = await Promise.all(dlcAccepts[0].fundingInputs.map(async (fundingInput) => {
332
+ const input = await this.fundingInputToInput(fundingInput, false);
333
+ return input.toUtxo();
334
+ }));
335
+ const localInputAmount = localInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
336
+ const remoteInputAmount = remoteInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
337
+ const localPayouts = [];
338
+ const remotePayouts = [];
339
+ const numPayouts = [];
340
+ const nestedMessagesList = [];
341
+ // loop through all dlc offers, get payouts, and add to localPayouts and remotePayouts
342
+ for (const dlcOffer of dlcOffers) {
343
+ const payoutResponses = this.GetPayouts(dlcOffer);
344
+ const { payouts, messagesList } = this.FlattenPayouts(payoutResponses);
345
+ const tempLocalPayouts = payouts.map((payout) => payout.local);
346
+ const tempRemotePayouts = payouts.map((payout) => payout.remote);
347
+ localPayouts.push(...tempLocalPayouts);
348
+ remotePayouts.push(...tempRemotePayouts);
349
+ numPayouts.push(tempLocalPayouts.length);
350
+ nestedMessagesList.push(messagesList);
351
+ }
352
+ const batchDlcTxRequest = {
353
+ localPayouts,
354
+ remotePayouts,
355
+ numPayouts,
356
+ localFundPubkeys,
357
+ localFinalScriptPubkeys,
358
+ remoteFundPubkeys,
359
+ remoteFinalScriptPubkeys,
360
+ localInputAmount,
361
+ localCollateralAmounts: dlcOffers.map((dlcOffer) => dlcOffer.offerCollateralSatoshis),
362
+ localPayoutSerialIds: dlcOffers.map((dlcOffer) => dlcOffer.payoutSerialId),
363
+ localChangeSerialId: dlcOffers[0].changeSerialId,
364
+ remoteInputAmount,
365
+ remoteCollateralAmounts: dlcAccepts.map((dlcAccept) => dlcAccept.acceptCollateralSatoshis),
366
+ remotePayoutSerialIds: dlcAccepts.map((dlcAccept) => dlcAccept.payoutSerialId),
367
+ remoteChangeSerialId: dlcAccepts[0].changeSerialId,
368
+ refundLocktimes: dlcOffers.map((dlcOffer) => dlcOffer.refundLocktime),
369
+ localInputs,
370
+ remoteInputs,
371
+ localChangeScriptPubkey,
372
+ remoteChangeScriptPubkey,
373
+ feeRate: Number(dlcOffers[0].feeRatePerVb),
374
+ cetLockTime: dlcOffers[0].cetLocktime,
375
+ fundOutputSerialIds: dlcOffers.map((dlcOffer) => dlcOffer.fundOutputSerialId),
376
+ };
377
+ const dlcTxs = await this.CreateBatchDlcTransactions(batchDlcTxRequest);
378
+ const dlcTransactionsList = [];
379
+ let start = 0;
380
+ for (let i = 0; i < dlcTxs.refundTxHexList.length; i++) {
381
+ const dlcTransactions = new messaging_1.DlcTransactionsV0();
382
+ dlcTransactions.fundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(dlcTxs.fundTxHex));
383
+ dlcTransactions.fundTxVout = [
384
+ BigInt(dlcOffers[i].changeSerialId),
385
+ BigInt(dlcAccepts[i].changeSerialId),
386
+ ...dlcOffers.map((dlcOffer) => dlcOffer.fundOutputSerialId),
387
+ ]
388
+ .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
389
+ .findIndex((j) => BigInt(j) === BigInt(dlcOffers[i].fundOutputSerialId));
390
+ dlcTransactions.refundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(dlcTxs.refundTxHexList[i]));
391
+ // slice cetsHexList based on numPayouts
392
+ const end = start + Number(numPayouts[i]);
393
+ const cetsHexList = dlcTxs.cetsHexList.slice(start, end);
394
+ start = end;
395
+ dlcTransactions.cets = cetsHexList.map((cetHex) => {
396
+ return bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(cetHex));
397
+ });
398
+ dlcTransactionsList.push(dlcTransactions);
399
+ }
400
+ return { dlcTransactionsList, nestedMessagesList };
401
+ }
402
+ GenerateEnumMessages(oracleEvent) {
403
+ throw Error('Only DigitDecomposition Oracle Events supported');
404
+ }
405
+ GenerateDigitDecompositionMessages(oracleEvent) {
406
+ const oracleNonces = oracleEvent.oracleNonces;
407
+ const eventDescriptor = oracleEvent.eventDescriptor;
408
+ const messagesList = [];
409
+ oracleNonces.forEach(() => {
410
+ const messages = [];
411
+ for (let i = 0; i < eventDescriptor.base; i++) {
412
+ const m = i.toString();
413
+ messages.push(m);
414
+ }
415
+ messagesList.push({ messages });
416
+ });
417
+ return messagesList;
418
+ }
419
+ GenerateMessages(oracleInfo) {
420
+ const oracleEvent = oracleInfo.announcement.oracleEvent;
421
+ switch (oracleEvent.eventDescriptor.type) {
422
+ case messaging_1.MessageType.EnumEventDescriptorV0:
423
+ return this.GenerateEnumMessages(oracleEvent);
424
+ case messaging_1.MessageType.DigitDecompositionEventDescriptorV0:
425
+ return this.GenerateDigitDecompositionMessages(oracleEvent);
426
+ default:
427
+ throw Error('EventDescriptor must be Enum or DigitDecomposition');
428
+ }
429
+ }
430
+ GetContractOraclePairs(_contractInfo) {
431
+ switch (_contractInfo.type) {
432
+ case messaging_1.MessageType.ContractInfoV0: {
433
+ const contractInfo = _contractInfo;
434
+ return [
435
+ {
436
+ contractDescriptor: contractInfo.contractDescriptor,
437
+ oracleInfo: contractInfo.oracleInfo,
438
+ },
439
+ ];
440
+ }
441
+ case messaging_1.MessageType.ContractInfoV1: {
442
+ return _contractInfo.contractOraclePairs;
443
+ }
444
+ default:
445
+ throw Error('ContractInfo must be V0 or V1');
446
+ }
447
+ }
448
+ async CreateCetAdaptorAndRefundSigs(_dlcOffer, _dlcAccept, _dlcTxs, messagesList, isOfferer) {
449
+ const { dlcOffer, dlcAccept, dlcTxs } = (0, Utils_1.checkTypes)({
450
+ _dlcOffer,
451
+ _dlcAccept,
452
+ _dlcTxs,
453
+ });
454
+ const network = await this.getConnectedNetwork();
455
+ const cetsHex = dlcTxs.cets.map((cet) => cet.serialize().toString('hex'));
456
+ const fundingSPK = bitcoin_1.Script.p2wpkhLock((0, crypto_1.hash160)(isOfferer ? dlcOffer.fundingPubKey : dlcAccept.fundingPubKey))
457
+ .serialize()
458
+ .slice(1);
459
+ const fundingAddress = bitcoinjs_lib_1.address.fromOutputScript(fundingSPK, network);
460
+ const { derivationPath } = await this.client.wallet.findAddress([
461
+ fundingAddress,
462
+ ]);
463
+ const fundPrivateKeyPair = await this.getMethod('keyPair')(derivationPath);
464
+ const fundPrivateKey = Buffer.from(fundPrivateKeyPair.__D).toString('hex');
465
+ const contractOraclePairs = this.GetContractOraclePairs(dlcOffer.contractInfo);
466
+ const indices = this.GetIndicesFromPayouts(this.GetPayouts(_dlcOffer));
467
+ const sigs = [];
468
+ for (const [index, { oracleInfo }] of contractOraclePairs.entries()) {
469
+ const oracleAnnouncement = oracleInfo.announcement;
470
+ const startingIndex = indices[index].startingMessagesIndex, endingIndex = indices[index + 1].startingMessagesIndex;
471
+ const oracleEventMessagesList = messagesList.slice(startingIndex, endingIndex);
472
+ const oracleEventCetsHex = cetsHex.slice(startingIndex, endingIndex);
473
+ const chunk = 100;
474
+ const adaptorSigRequestPromises = [];
475
+ for (let i = 0, j = oracleEventMessagesList.length; i < j; i += chunk) {
476
+ const tempMessagesList = oracleEventMessagesList.slice(i, i + chunk);
477
+ const tempCetsHex = oracleEventCetsHex.slice(i, i + chunk);
478
+ const cetSignRequest = {
479
+ messagesList: tempMessagesList,
480
+ cetsHex: tempCetsHex,
481
+ privkey: fundPrivateKey,
482
+ fundTxId: dlcTxs.fundTx.txId.toString(),
483
+ fundVout: dlcTxs.fundTxVout,
484
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
485
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
486
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
487
+ oraclePubkey: oracleAnnouncement.oraclePubkey.toString('hex'),
488
+ oracleRValues: oracleAnnouncement.oracleEvent.oracleNonces.map((nonce) => nonce.toString('hex')),
489
+ };
490
+ adaptorSigRequestPromises.push((async () => {
491
+ const response = await this.CreateCetAdaptorSignatures(cetSignRequest);
492
+ return response.adaptorPairs;
493
+ })());
494
+ }
495
+ const adaptorPairs = (await Promise.all(adaptorSigRequestPromises)).flat();
496
+ sigs.push(adaptorPairs.map((adaptorPair) => {
497
+ return {
498
+ encryptedSig: Buffer.from(adaptorPair.signature, 'hex'),
499
+ dleqProof: Buffer.from(adaptorPair.proof, 'hex'),
500
+ };
501
+ }));
502
+ }
503
+ const refundSignRequest = {
504
+ refundTxHex: dlcTxs.refundTx.serialize().toString('hex'),
505
+ privkey: fundPrivateKey,
506
+ fundTxId: dlcTxs.fundTx.txId.toString(),
507
+ fundVout: dlcTxs.fundTxVout,
508
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
509
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
510
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
511
+ };
512
+ const refundSignature = Buffer.from((await this.GetRawRefundTxSignature(refundSignRequest)).hex, 'hex');
513
+ const cetSignatures = new messaging_1.CetAdaptorSignaturesV0();
514
+ cetSignatures.sigs = sigs.flat();
515
+ return { cetSignatures, refundSignature };
516
+ }
517
+ async VerifyCetAdaptorAndRefundSigs(_dlcOffer, _dlcAccept, _dlcSign, _dlcTxs, messagesList, isOfferer) {
518
+ const { dlcOffer, dlcAccept, dlcSign, dlcTxs } = (0, Utils_1.checkTypes)({
519
+ _dlcOffer,
520
+ _dlcAccept,
521
+ _dlcSign,
522
+ _dlcTxs,
523
+ });
524
+ const cetsHex = dlcTxs.cets.map((cet) => cet.serialize().toString('hex'));
525
+ const chunk = 100;
526
+ const contractOraclePairs = this.GetContractOraclePairs(dlcOffer.contractInfo);
527
+ const indices = this.GetIndicesFromPayouts(this.GetPayouts(_dlcOffer));
528
+ for (const [index, { oracleInfo }] of contractOraclePairs.entries()) {
529
+ const oracleAnnouncement = oracleInfo.announcement;
530
+ const startingIndex = indices[index].startingMessagesIndex, endingIndex = indices[index + 1].startingMessagesIndex;
531
+ const oracleEventMessagesList = messagesList.slice(startingIndex, endingIndex);
532
+ const oracleEventCetsHex = cetsHex.slice(startingIndex, endingIndex);
533
+ const oracleEventSigs = (isOfferer
534
+ ? dlcAccept.cetSignatures.sigs
535
+ : dlcSign.cetSignatures.sigs).slice(startingIndex, endingIndex);
536
+ const sigsValidity = [];
537
+ for (let i = 0, j = oracleEventMessagesList.length; i < j; i += chunk) {
538
+ const tempMessagesList = oracleEventMessagesList.slice(i, i + chunk);
539
+ const tempCetsHex = oracleEventCetsHex.slice(i, i + chunk);
540
+ const tempSigs = oracleEventSigs.slice(i, i + chunk);
541
+ const tempAdaptorPairs = tempSigs.map((sig) => {
542
+ return {
543
+ signature: sig.encryptedSig.toString('hex'),
544
+ proof: sig.dleqProof.toString('hex'),
545
+ };
546
+ });
547
+ const verifyCetAdaptorSignaturesRequest = {
548
+ cetsHex: tempCetsHex,
549
+ messagesList: tempMessagesList,
550
+ oraclePubkey: oracleAnnouncement.oraclePubkey.toString('hex'),
551
+ oracleRValues: oracleAnnouncement.oracleEvent.oracleNonces.map((nonce) => nonce.toString('hex')),
552
+ adaptorPairs: tempAdaptorPairs,
553
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
554
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
555
+ fundTxId: dlcTxs.fundTx.txId.toString(),
556
+ fundVout: dlcTxs.fundTxVout,
557
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
558
+ verifyRemote: isOfferer,
559
+ };
560
+ sigsValidity.push((async () => {
561
+ const response = await this.VerifyCetAdaptorSignatures(verifyCetAdaptorSignaturesRequest);
562
+ return response.valid;
563
+ })());
564
+ }
565
+ let areSigsValid = (await Promise.all(sigsValidity)).every((b) => b);
566
+ const verifyRefundSigRequest = {
567
+ refundTxHex: dlcTxs.refundTx.serialize().toString('hex'),
568
+ signature: isOfferer
569
+ ? dlcAccept.refundSignature.toString('hex')
570
+ : dlcSign.refundSignature.toString('hex'),
571
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
572
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
573
+ fundTxId: dlcTxs.fundTx.txId.toString(),
574
+ fundVout: dlcTxs.fundTxVout,
575
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
576
+ verifyRemote: isOfferer,
577
+ };
578
+ areSigsValid =
579
+ areSigsValid &&
580
+ (await this.VerifyRefundTxSignature(verifyRefundSigRequest)).valid;
581
+ if (!areSigsValid) {
582
+ throw new Error('Invalid signatures received');
583
+ }
584
+ }
585
+ }
586
+ async CreateFundingSigs(_dlcOffer, _dlcAccept, _dlcTxs, isOfferer) {
587
+ const { dlcOffer, dlcAccept, dlcTxs } = (0, Utils_1.checkTypes)({
588
+ _dlcOffer,
589
+ _dlcAccept,
590
+ _dlcTxs,
591
+ });
592
+ const fundingInputs = isOfferer
593
+ ? dlcOffer.fundingInputs
594
+ : dlcAccept.fundingInputs;
595
+ const inputs = await Promise.all(fundingInputs.map(async (fundingInput) => {
596
+ return this.fundingInputToInput(fundingInput);
597
+ }));
598
+ const inputPrivKeys = await this.GetPrivKeysForInputs(inputs);
599
+ const fundTxSigs = await Promise.all(inputs.map(async (input, index) => {
600
+ const fundTxSignRequest = {
601
+ fundTxHex: dlcTxs.fundTx.serialize().toString('hex'),
602
+ privkey: inputPrivKeys[index],
603
+ prevTxId: input.txid,
604
+ prevVout: input.vout,
605
+ amount: input.value,
606
+ };
607
+ return (await this.GetRawFundTxSignature(fundTxSignRequest)).hex;
608
+ }));
609
+ const inputPubKeys = await Promise.all(inputPrivKeys.map(async (privkey) => {
610
+ const reqPrivKey = {
611
+ privkey,
612
+ isCompressed: true,
613
+ };
614
+ return (await this.getMethod('GetPubkeyFromPrivkey')(reqPrivKey))
615
+ .pubkey;
616
+ }));
617
+ const witnessElements = [];
618
+ for (let i = 0; i < fundTxSigs.length; i++) {
619
+ const sigWitness = new messaging_1.ScriptWitnessV0();
620
+ sigWitness.witness = Buffer.from(fundTxSigs[i], 'hex');
621
+ const pubKeyWitness = new messaging_1.ScriptWitnessV0();
622
+ pubKeyWitness.witness = Buffer.from(inputPubKeys[i], 'hex');
623
+ witnessElements.push([sigWitness, pubKeyWitness]);
624
+ }
625
+ const fundingSignatures = new messaging_1.FundingSignaturesV0();
626
+ fundingSignatures.witnessElements = witnessElements;
627
+ return fundingSignatures;
628
+ }
629
+ async VerifyFundingSigs(_dlcOffer, _dlcAccept, _dlcSign, _dlcTxs, isOfferer) {
630
+ const { dlcOffer, dlcAccept, dlcSign, dlcTxs } = (0, Utils_1.checkTypes)({
631
+ _dlcOffer,
632
+ _dlcAccept,
633
+ _dlcSign,
634
+ _dlcTxs,
635
+ });
636
+ const sigsValidity = [];
637
+ for (let i = 0; i < dlcSign.fundingSignatures.witnessElements.length; i++) {
638
+ const witnessElement = dlcSign.fundingSignatures.witnessElements[i];
639
+ const signature = witnessElement[0].witness.toString('hex');
640
+ const pubkey = witnessElement[1].witness.toString('hex');
641
+ const fundingInput = isOfferer
642
+ ? dlcAccept.fundingInputs[i]
643
+ : dlcOffer.fundingInputs[i];
644
+ const verifyFundSigRequest = {
645
+ fundTxHex: dlcTxs.fundTx.serialize().toString('hex'),
646
+ signature,
647
+ pubkey,
648
+ prevTxId: fundingInput.prevTx.txId.toString(),
649
+ prevVout: fundingInput.prevTxVout,
650
+ fundInputAmount: fundingInput.prevTx.outputs[fundingInput.prevTxVout].value.sats,
651
+ };
652
+ sigsValidity.push((async () => {
653
+ const response = await this.VerifyFundTxSignature(verifyFundSigRequest);
654
+ return response.valid;
655
+ })());
656
+ }
657
+ const areSigsValid = (await Promise.all(sigsValidity)).every((b) => b);
658
+ if (!areSigsValid) {
659
+ throw new Error('Invalid signatures received');
660
+ }
661
+ }
662
+ async CreateFundingTx(_dlcOffer, _dlcAccept, _dlcSign, _dlcTxs, fundingSignatures) {
663
+ const { dlcOffer, dlcAccept, dlcSign, dlcTxs } = (0, Utils_1.checkTypes)({
664
+ _dlcOffer,
665
+ _dlcAccept,
666
+ _dlcSign,
667
+ _dlcTxs,
668
+ });
669
+ const witnessElements = [
670
+ ...dlcSign.fundingSignatures.witnessElements,
671
+ ...fundingSignatures.witnessElements,
672
+ ];
673
+ const fundingInputs = [
674
+ ...dlcOffer.fundingInputs,
675
+ ...dlcAccept.fundingInputs,
676
+ ];
677
+ let fundTxHex = dlcTxs.fundTx.serialize().toString('hex');
678
+ await (0, Utils_1.asyncForEach)(witnessElements, async (witnessElement, i) => {
679
+ const signature = witnessElement[0].witness.toString('hex');
680
+ const pubkey = witnessElement[1].witness.toString('hex');
681
+ const fundingInput = fundingInputs[i];
682
+ const addSignRequest = {
683
+ fundTxHex,
684
+ signature,
685
+ prevTxId: fundingInput.prevTx.txId.toString(),
686
+ prevVout: fundingInput.prevTxVout,
687
+ pubkey,
688
+ };
689
+ fundTxHex = (await this.AddSignatureToFundTransaction(addSignRequest))
690
+ .hex;
691
+ });
692
+ const fundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(fundTxHex));
693
+ return fundTx;
694
+ }
695
+ async FindOutcomeIndexFromPolynomialPayoutCurvePiece(_dlcOffer, contractDescriptor, contractOraclePairIndex, polynomialPayoutCurvePiece, oracleAttestation, outcome) {
696
+ const { dlcOffer } = (0, Utils_1.checkTypes)({ _dlcOffer });
697
+ const polynomialCurve = core_1.PolynomialPayoutCurve.fromPayoutCurvePiece(polynomialPayoutCurvePiece);
698
+ const payouts = polynomialPayoutCurvePiece.points.map((point) => Number(point.outcomePayout));
699
+ const minPayout = Math.min(...payouts);
700
+ const maxPayout = Math.max(...payouts);
701
+ const clampBN = (val) => bignumber_js_1.default.max(minPayout, bignumber_js_1.default.min(val, maxPayout));
702
+ const payout = clampBN(polynomialCurve.getPayout(outcome));
703
+ const payoutResponses = this.GetPayouts(dlcOffer);
704
+ const payoutIndexOffset = this.GetIndicesFromPayouts(payoutResponses)[contractOraclePairIndex].startingMessagesIndex;
705
+ const { payoutGroups } = payoutResponses[contractOraclePairIndex];
706
+ const intervalsSorted = [
707
+ ...contractDescriptor.roundingIntervals.intervals,
708
+ ].sort((a, b) => Number(b.beginInterval) - Number(a.beginInterval));
709
+ const interval = intervalsSorted.find((interval) => Number(outcome) >= Number(interval.beginInterval));
710
+ const roundedPayout = BigInt(clampBN(new bignumber_js_1.default((0, core_1.roundPayout)(payout, interval.roundingMod).toString())).toString());
711
+ const outcomesFormatted = oracleAttestation.outcomes.map((outcome) => parseInt(outcome));
712
+ let index = 0;
713
+ let groupIndex = -1;
714
+ let groupLength = 0;
715
+ for (const payoutGroup of payoutGroups) {
716
+ if (payoutGroup.payout === roundedPayout) {
717
+ groupIndex = payoutGroup.groups.findIndex((group) => {
718
+ return group.every((msg, i) => msg === outcomesFormatted[i]);
719
+ });
720
+ if (groupIndex === -1)
721
+ throw Error('Failed to Find OutcomeIndex From PolynomialPayoutCurvePiece. \
722
+ Payout Group found but incorrect group index');
723
+ index += groupIndex;
724
+ groupLength = payoutGroup.groups[groupIndex].length;
725
+ break;
726
+ }
727
+ else {
728
+ index += payoutGroup.groups.length;
729
+ }
730
+ }
731
+ if (groupIndex === -1)
732
+ throw Error('Failed to Find OutcomeIndex From PolynomialPayoutCurvePiece. \
733
+ Payout Group not found');
734
+ return { index: payoutIndexOffset + index, groupLength };
735
+ }
736
+ async FindOutcomeIndexFromHyperbolaPayoutCurvePiece(_dlcOffer, contractDescriptor, contractOraclePairIndex, hyperbolaPayoutCurvePiece, oracleAttestation, outcome) {
737
+ const { dlcOffer } = (0, Utils_1.checkTypes)({ _dlcOffer });
738
+ const hyperbolaCurve = core_1.HyperbolaPayoutCurve.fromPayoutCurvePiece(hyperbolaPayoutCurvePiece);
739
+ const clampBN = (val) => bignumber_js_1.default.max(0, bignumber_js_1.default.min(val, dlcOffer.contractInfo.totalCollateral.toString()));
740
+ const payout = clampBN(hyperbolaCurve.getPayout(outcome));
741
+ const payoutResponses = this.GetPayouts(dlcOffer);
742
+ const payoutIndexOffset = this.GetIndicesFromPayouts(payoutResponses)[contractOraclePairIndex].startingMessagesIndex;
743
+ const { payoutGroups } = payoutResponses[contractOraclePairIndex];
744
+ const intervalsSorted = [
745
+ ...contractDescriptor.roundingIntervals.intervals,
746
+ ].sort((a, b) => Number(b.beginInterval) - Number(a.beginInterval));
747
+ const interval = intervalsSorted.find((interval) => Number(outcome) >= Number(interval.beginInterval));
748
+ const roundedPayout = BigInt(clampBN(new bignumber_js_1.default((0, core_1.roundPayout)(payout, interval.roundingMod).toString())).toString());
749
+ const outcomesFormatted = oracleAttestation.outcomes.map((outcome) => parseInt(outcome));
750
+ let index = 0;
751
+ let groupIndex = -1;
752
+ let groupLength = 0;
753
+ for (const [i, payoutGroup] of payoutGroups.entries()) {
754
+ if (payoutGroup.payout === roundedPayout) {
755
+ groupIndex = payoutGroup.groups.findIndex((group) => {
756
+ return group.every((msg, i) => msg === outcomesFormatted[i]);
757
+ });
758
+ if (groupIndex !== -1) {
759
+ index += groupIndex;
760
+ groupLength = payoutGroup.groups[groupIndex].length;
761
+ break;
762
+ }
763
+ }
764
+ else if (payoutGroup.payout === BigInt(Math.round(Number(payout.toString()))) &&
765
+ i !== 0) {
766
+ // Edge case to account for case where payout is maximum payout for DLC
767
+ // But rounded payout does not round down
768
+ if (payoutGroups[i - 1].payout === roundedPayout) {
769
+ // Ensure that the previous payout group causes index to be incremented
770
+ index += payoutGroups[i - 1].groups.length;
771
+ }
772
+ groupIndex = payoutGroup.groups.findIndex((group) => {
773
+ return group.every((msg, i) => msg === outcomesFormatted[i]);
774
+ });
775
+ if (groupIndex !== -1) {
776
+ index += groupIndex;
777
+ groupLength = payoutGroup.groups[groupIndex].length;
778
+ break;
779
+ }
780
+ }
781
+ else {
782
+ index += payoutGroup.groups.length;
783
+ }
784
+ }
785
+ if (groupIndex === -1) {
786
+ throw Error('Failed to Find OutcomeIndex From HyperbolaPayoutCurvePiece. \
787
+ Payout Group not found');
788
+ }
789
+ return { index: payoutIndexOffset + index, groupLength };
790
+ }
791
+ async FindOutcomeIndex(_dlcOffer, oracleAttestation) {
792
+ const { dlcOffer } = (0, Utils_1.checkTypes)({ _dlcOffer });
793
+ const contractOraclePairs = this.GetContractOraclePairs(dlcOffer.contractInfo);
794
+ const contractOraclePairIndex = contractOraclePairs.findIndex(({ oracleInfo }) => oracleInfo.announcement.oracleEvent.eventId ===
795
+ oracleAttestation.eventId);
796
+ (0, assert_1.default)(contractOraclePairIndex !== -1, 'OracleAttestation must be for an existing OracleEvent');
797
+ const contractOraclePair = contractOraclePairs[contractOraclePairIndex];
798
+ const { contractDescriptor: _contractDescriptor, oracleInfo, } = contractOraclePair;
799
+ (0, assert_1.default)(_contractDescriptor.type === messaging_1.MessageType.ContractDescriptorV1, 'ContractDescriptor must be V1');
800
+ const contractDescriptor = _contractDescriptor;
801
+ const _payoutFunction = contractDescriptor.payoutFunction;
802
+ (0, assert_1.default)(_payoutFunction.type === messaging_1.MessageType.PayoutFunctionV0, 'PayoutFunction must be V0');
803
+ const eventDescriptor = oracleInfo.announcement.oracleEvent
804
+ .eventDescriptor;
805
+ const payoutFunction = _payoutFunction;
806
+ const base = eventDescriptor.base;
807
+ const outcome = [...oracleAttestation.outcomes]
808
+ .reverse()
809
+ .reduce((acc, val, i) => acc + Number(val) * base ** i, 0);
810
+ const piecesSorted = payoutFunction.pieces.sort((a, b) => Number(a.endpoint) - Number(b.endpoint));
811
+ const piece = piecesSorted.find((piece) => outcome < piece.endpoint);
812
+ switch (piece.payoutCurvePiece.type) {
813
+ case messaging_1.MessageType.PolynomialPayoutCurvePiece:
814
+ return this.FindOutcomeIndexFromPolynomialPayoutCurvePiece(dlcOffer, contractDescriptor, contractOraclePairIndex, piece.payoutCurvePiece, oracleAttestation, BigInt(outcome));
815
+ case messaging_1.MessageType.HyperbolaPayoutCurvePiece:
816
+ return this.FindOutcomeIndexFromHyperbolaPayoutCurvePiece(dlcOffer, contractDescriptor, contractOraclePairIndex, piece.payoutCurvePiece, oracleAttestation, BigInt(outcome));
817
+ case messaging_1.MessageType.OldHyperbolaPayoutCurvePiece:
818
+ return this.FindOutcomeIndexFromHyperbolaPayoutCurvePiece(dlcOffer, contractDescriptor, contractOraclePairIndex, piece.payoutCurvePiece, oracleAttestation, BigInt(outcome));
819
+ default:
820
+ throw Error('Must be Hyperbola or Polynomial curve piece');
821
+ }
822
+ }
823
+ ValidateEvent(_dlcOffer, oracleAttestation) {
824
+ const { dlcOffer } = (0, Utils_1.checkTypes)({
825
+ _dlcOffer,
826
+ });
827
+ switch (dlcOffer.contractInfo.type) {
828
+ case messaging_1.MessageType.ContractInfoV0: {
829
+ const contractInfo = dlcOffer.contractInfo;
830
+ switch (contractInfo.contractDescriptor.type) {
831
+ case messaging_1.MessageType.ContractDescriptorV0:
832
+ throw Error('ContractDescriptorV0 not yet supported');
833
+ case messaging_1.MessageType.ContractDescriptorV1: {
834
+ const oracleInfo = contractInfo.oracleInfo;
835
+ if (oracleInfo.announcement.oracleEvent.eventId !==
836
+ oracleAttestation.eventId)
837
+ throw Error('Incorrect Oracle Attestation. Event Id must match.');
838
+ break;
839
+ }
840
+ default:
841
+ throw Error('ConractDescriptor must be V0 or V1');
842
+ }
843
+ break;
844
+ }
845
+ case messaging_1.MessageType.ContractInfoV1: {
846
+ const contractInfo = dlcOffer.contractInfo;
847
+ const attestedOracleEvent = contractInfo.contractOraclePairs.find(({ oracleInfo }) => oracleInfo.announcement.oracleEvent.eventId ===
848
+ oracleAttestation.eventId);
849
+ if (!attestedOracleEvent)
850
+ throw Error('Oracle event of attestation not found.');
851
+ break;
852
+ }
853
+ default:
854
+ throw Error('ContractInfo must be V0 or V1');
855
+ }
856
+ }
857
+ async FindAndSignCet(_dlcOffer, _dlcAccept, _dlcSign, _dlcTxs, oracleAttestation, isOfferer) {
858
+ const { dlcOffer, dlcAccept, dlcSign, dlcTxs } = (0, Utils_1.checkTypes)({
859
+ _dlcOffer,
860
+ _dlcAccept,
861
+ _dlcSign,
862
+ _dlcTxs,
863
+ });
864
+ if (isOfferer === undefined)
865
+ isOfferer = await this.isOfferer(dlcOffer, dlcAccept);
866
+ const { index: outcomeIndex, groupLength } = await this.FindOutcomeIndex(dlcOffer, oracleAttestation);
867
+ const fundPrivateKey = await this.GetFundPrivateKey(dlcOffer, dlcAccept, isOfferer);
868
+ const sliceIndex = -(oracleAttestation.signatures.length - groupLength);
869
+ const oracleSignatures = sliceIndex === 0
870
+ ? oracleAttestation.signatures
871
+ : oracleAttestation.signatures.slice(0, sliceIndex);
872
+ const signCetRequest = {
873
+ cetHex: dlcTxs.cets[outcomeIndex].serialize().toString('hex'),
874
+ fundPrivkey: fundPrivateKey,
875
+ fundTxId: dlcTxs.fundTx.txId.toString(),
876
+ fundVout: dlcTxs.fundTxVout,
877
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
878
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
879
+ oracleSignatures: oracleSignatures.map((sig) => sig.toString('hex')),
880
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
881
+ adaptorSignature: isOfferer
882
+ ? dlcAccept.cetSignatures.sigs[outcomeIndex].encryptedSig.toString('hex')
883
+ : dlcSign.cetSignatures.sigs[outcomeIndex].encryptedSig.toString('hex'),
884
+ };
885
+ const finalCet = (await this.SignCet(signCetRequest)).hex;
886
+ return bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(finalCet));
887
+ }
888
+ async GetFundAddress(dlcOffer, dlcAccept, isOfferer) {
889
+ const network = await this.getConnectedNetwork();
890
+ const fundingSPK = bitcoin_1.Script.p2wpkhLock((0, crypto_1.hash160)(isOfferer ? dlcOffer.fundingPubKey : dlcAccept.fundingPubKey))
891
+ .serialize()
892
+ .slice(1);
893
+ const fundingAddress = bitcoinjs_lib_1.address.fromOutputScript(fundingSPK, network);
894
+ return fundingAddress;
895
+ }
896
+ async GetFundKeyPair(dlcOffer, dlcAccept, isOfferer) {
897
+ const fundingAddress = await this.GetFundAddress(dlcOffer, dlcAccept, isOfferer);
898
+ const { derivationPath } = await this.getMethod('getWalletAddress')(fundingAddress);
899
+ const keyPair = await this.getMethod('keyPair')(derivationPath);
900
+ return keyPair;
901
+ }
902
+ async GetFundPrivateKey(dlcOffer, dlcAccept, isOfferer) {
903
+ const fundPrivateKeyPair = await this.GetFundKeyPair(dlcOffer, dlcAccept, isOfferer);
904
+ return Buffer.from(fundPrivateKeyPair.privateKey).toString('hex');
905
+ }
906
+ async CreateCloseRawTxs(_dlcOffer, _dlcAccept, _dlcTxs, closeInputAmount, isOfferer, _dlcCloses = [], fundingInputs, initiatorPayouts) {
907
+ const { dlcOffer, dlcAccept, dlcTxs } = (0, Utils_1.checkTypes)({
908
+ _dlcOffer,
909
+ _dlcAccept,
910
+ _dlcTxs,
911
+ });
912
+ const network = await this.getConnectedNetwork();
913
+ let finalizer;
914
+ if (_dlcCloses.length === 0) {
915
+ finalizer = new core_1.DualClosingTxFinalizer(fundingInputs, dlcOffer.payoutSPK, dlcAccept.payoutSPK, dlcOffer.feeRatePerVb);
916
+ }
917
+ const rawTransactionRequestPromises = [];
918
+ const rawCloseTxs = [];
919
+ const numPayouts = _dlcCloses.length === 0 ? initiatorPayouts.length : _dlcCloses.length;
920
+ for (let i = 0; i < numPayouts; i++) {
921
+ let offerPayoutValue = BigInt(0);
922
+ let acceptPayoutValue = BigInt(0);
923
+ if (_dlcCloses.length === 0) {
924
+ const payout = initiatorPayouts[i];
925
+ const payoutMinusOfferFees = finalizer.offerInitiatorFees > payout
926
+ ? BigInt(0)
927
+ : payout - finalizer.offerInitiatorFees;
928
+ const collateralMinusPayout = payout > dlcOffer.contractInfo.totalCollateral
929
+ ? BigInt(0)
930
+ : dlcOffer.contractInfo.totalCollateral - payout;
931
+ offerPayoutValue = isOfferer
932
+ ? closeInputAmount + payoutMinusOfferFees
933
+ : collateralMinusPayout;
934
+ acceptPayoutValue = isOfferer
935
+ ? collateralMinusPayout
936
+ : closeInputAmount + payoutMinusOfferFees;
937
+ }
938
+ else {
939
+ const dlcClose = (0, Utils_1.checkTypes)({ _dlcClose: _dlcCloses[i] }).dlcClose;
940
+ offerPayoutValue = dlcClose.offerPayoutSatoshis;
941
+ acceptPayoutValue = dlcClose.acceptPayoutSatoshis;
942
+ }
943
+ const txOuts = [];
944
+ if (Number(offerPayoutValue) > 0) {
945
+ txOuts.push({
946
+ address: bitcoinjs_lib_1.address.fromOutputScript(dlcOffer.payoutSPK, network),
947
+ amount: Number(offerPayoutValue),
948
+ });
949
+ }
950
+ if (Number(acceptPayoutValue) > 0) {
951
+ txOuts.push({
952
+ address: bitcoinjs_lib_1.address.fromOutputScript(dlcAccept.payoutSPK, network),
953
+ amount: Number(acceptPayoutValue),
954
+ });
955
+ }
956
+ if (dlcOffer.payoutSerialId > dlcAccept.payoutSerialId)
957
+ txOuts.reverse();
958
+ const rawTransactionRequest = {
959
+ version: 2,
960
+ locktime: 0,
961
+ txins: [
962
+ {
963
+ txid: dlcTxs.fundTx.txId.serialize().reverse().toString('hex'),
964
+ vout: dlcTxs.fundTxVout,
965
+ sequence: 0,
966
+ },
967
+ ],
968
+ txouts: txOuts,
969
+ };
970
+ rawTransactionRequestPromises.push((async () => {
971
+ const response = await this.getMethod('CreateRawTransaction')(rawTransactionRequest);
972
+ return response.hex;
973
+ })());
974
+ }
975
+ const hexs = await Promise.all(rawTransactionRequestPromises);
976
+ rawCloseTxs.push(hexs);
977
+ return rawCloseTxs.flat();
978
+ }
979
+ async CreateSignatureHashes(_dlcOffer, _dlcAccept, _dlcTxs, rawCloseTxs) {
980
+ const { dlcOffer, dlcAccept, dlcTxs } = (0, Utils_1.checkTypes)({
981
+ _dlcOffer,
982
+ _dlcAccept,
983
+ _dlcTxs,
984
+ });
985
+ const network = await this.getConnectedNetwork();
986
+ const fundingPubKeys = Buffer.compare(dlcOffer.fundingPubKey, dlcAccept.fundingPubKey) === -1
987
+ ? [dlcOffer.fundingPubKey, dlcAccept.fundingPubKey]
988
+ : [dlcAccept.fundingPubKey, dlcOffer.fundingPubKey];
989
+ const p2ms = bitcoinjs_lib_1.payments.p2ms({
990
+ m: 2,
991
+ pubkeys: fundingPubKeys,
992
+ network,
993
+ });
994
+ const paymentVariant = bitcoinjs_lib_1.payments.p2wsh({
995
+ redeem: p2ms,
996
+ network,
997
+ });
998
+ const sigHashRequestPromises = [];
999
+ const sigHashes = [];
1000
+ for (let i = 0; i < rawCloseTxs.length; i++) {
1001
+ const rawTx = rawCloseTxs[i];
1002
+ const sigHashRequest = {
1003
+ tx: rawTx,
1004
+ txin: {
1005
+ txid: dlcTxs.fundTx.txId.serialize().reverse().toString('hex'),
1006
+ vout: dlcTxs.fundTxVout,
1007
+ keyData: {
1008
+ hex: paymentVariant.redeem.output.toString('hex'),
1009
+ type: 'redeem_script',
1010
+ },
1011
+ amount: Number(dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats),
1012
+ hashType: 'p2wsh',
1013
+ sighashType: 'all',
1014
+ sighashAnyoneCanPay: false,
1015
+ },
1016
+ };
1017
+ sigHashRequestPromises.push((async () => {
1018
+ const response = await this.getMethod('CreateSignatureHash')(sigHashRequest);
1019
+ return response.sighash;
1020
+ })());
1021
+ }
1022
+ const sighashes = await Promise.all(sigHashRequestPromises);
1023
+ sigHashes.push(sighashes);
1024
+ return sigHashes.flat();
1025
+ }
1026
+ async CalculateEcSignatureHashes(sigHashes, privKey) {
1027
+ const cfdNetwork = await this.GetCfdNetwork();
1028
+ const sigsRequestPromises = [];
1029
+ for (let i = 0; i < sigHashes.length; i++) {
1030
+ const sigHash = sigHashes[i];
1031
+ const calculateEcSignatureRequest = {
1032
+ sighash: sigHash,
1033
+ privkeyData: {
1034
+ privkey: privKey,
1035
+ wif: false,
1036
+ network: cfdNetwork,
1037
+ },
1038
+ isGrindR: true,
1039
+ };
1040
+ sigsRequestPromises.push((async () => {
1041
+ const response = await this.getMethod('CalculateEcSignature')(calculateEcSignatureRequest);
1042
+ return response.signature;
1043
+ })());
1044
+ }
1045
+ const sigs = await Promise.all(sigsRequestPromises);
1046
+ return sigs.flat();
1047
+ }
1048
+ async VerifySignatures(_dlcOffer, _dlcAccept, _dlcTxs, _dlcCloses, rawCloseTxs, isOfferer) {
1049
+ const { dlcOffer, dlcAccept, dlcTxs } = (0, Utils_1.checkTypes)({
1050
+ _dlcOffer,
1051
+ _dlcAccept,
1052
+ _dlcTxs,
1053
+ });
1054
+ const dlcCloses = _dlcCloses.map((_dlcClose) => (0, Utils_1.checkTypes)({ _dlcClose }).dlcClose);
1055
+ const network = await this.getConnectedNetwork();
1056
+ const fundingPubKeys = Buffer.compare(dlcOffer.fundingPubKey, dlcAccept.fundingPubKey) === -1
1057
+ ? [dlcOffer.fundingPubKey, dlcAccept.fundingPubKey]
1058
+ : [dlcAccept.fundingPubKey, dlcOffer.fundingPubKey];
1059
+ const p2ms = bitcoinjs_lib_1.payments.p2ms({
1060
+ m: 2,
1061
+ pubkeys: fundingPubKeys,
1062
+ network,
1063
+ });
1064
+ const paymentVariant = bitcoinjs_lib_1.payments.p2wsh({
1065
+ redeem: p2ms,
1066
+ network,
1067
+ });
1068
+ const pubkey = isOfferer ? dlcAccept.fundingPubKey : dlcOffer.fundingPubKey;
1069
+ const sigsValidity = [];
1070
+ for (let i = 0; i < rawCloseTxs.length; i++) {
1071
+ const rawTx = rawCloseTxs[i];
1072
+ const dlcClose = dlcCloses[i];
1073
+ const verifySignatureRequest = {
1074
+ tx: rawTx,
1075
+ txin: {
1076
+ txid: dlcTxs.fundTx.txId.serialize().reverse().toString('hex'),
1077
+ vout: dlcTxs.fundTxVout,
1078
+ signature: dlcClose.closeSignature.toString('hex'),
1079
+ pubkey: pubkey.toString('hex'),
1080
+ redeemScript: paymentVariant.redeem.output.toString('hex'),
1081
+ hashType: 'p2wsh',
1082
+ sighashType: 'all',
1083
+ sighashAnyoneCanPay: false,
1084
+ amount: Number(dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats),
1085
+ },
1086
+ };
1087
+ sigsValidity.push((async () => {
1088
+ const response = await this.getMethod('VerifySignature')(verifySignatureRequest);
1089
+ return response.success;
1090
+ })());
1091
+ }
1092
+ const areSigsValid = (await Promise.all(sigsValidity)).every((b) => b);
1093
+ return areSigsValid;
1094
+ }
1095
+ /**
1096
+ * Check whether wallet is offerer of DlcOffer or DlcAccept
1097
+ * @param dlcOffer Dlc Offer Message
1098
+ * @param dlcAccept Dlc Accept Message
1099
+ * @returns {Promise<boolean>}
1100
+ */
1101
+ async isOfferer(_dlcOffer, _dlcAccept) {
1102
+ const { dlcOffer, dlcAccept } = (0, Utils_1.checkTypes)({
1103
+ _dlcOffer,
1104
+ _dlcAccept,
1105
+ });
1106
+ const network = await this.getConnectedNetwork();
1107
+ const offerFundingSPK = bitcoin_1.Script.p2wpkhLock((0, crypto_1.hash160)(dlcOffer.fundingPubKey))
1108
+ .serialize()
1109
+ .slice(1);
1110
+ const acceptFundingSPK = bitcoin_1.Script.p2wpkhLock((0, crypto_1.hash160)(dlcAccept.fundingPubKey))
1111
+ .serialize()
1112
+ .slice(1);
1113
+ const offerFundingAddress = bitcoinjs_lib_1.address.fromOutputScript(offerFundingSPK, network);
1114
+ const acceptFundingAddress = bitcoinjs_lib_1.address.fromOutputScript(acceptFundingSPK, network);
1115
+ let walletAddress = await this.client.wallet.findAddress([
1116
+ offerFundingAddress,
1117
+ ]);
1118
+ if (walletAddress)
1119
+ return true;
1120
+ walletAddress = await this.client.wallet.findAddress([
1121
+ acceptFundingAddress,
1122
+ ]);
1123
+ if (walletAddress)
1124
+ return false;
1125
+ throw Error('Wallet Address not found for DlcOffer or DlcAccept');
1126
+ }
1127
+ /**
1128
+ * Create DLC Offer Message
1129
+ * @param contractInfo ContractInfo TLV (V0 or V1)
1130
+ * @param offerCollateralSatoshis Amount DLC Initiator is putting into the contract
1131
+ * @param feeRatePerVb Fee rate in satoshi per virtual byte that both sides use to compute fees in funding tx
1132
+ * @param cetLocktime The nLockTime to be put on CETs
1133
+ * @param refundLocktime The nLockTime to be put on the refund transaction
1134
+ * @returns {Promise<DlcOffer>}
1135
+ */
1136
+ async createDlcOffer(contractInfo, offerCollateralSatoshis, feeRatePerVb, cetLocktime, refundLocktime, fixedInputs) {
1137
+ contractInfo.validate();
1138
+ const network = await this.getConnectedNetwork();
1139
+ const dlcOffer = new messaging_1.DlcOfferV0();
1140
+ const { fundingPubKey, payoutSPK, payoutSerialId, fundingInputs: _fundingInputs, changeSPK, changeSerialId, } = await this.Initialize(offerCollateralSatoshis, feeRatePerVb, fixedInputs);
1141
+ _fundingInputs.forEach((input) => (0, assert_1.default)(input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0'));
1142
+ const fundingInputs = _fundingInputs.map((input) => input);
1143
+ fundingInputs.sort((a, b) => Number(a.inputSerialId) - Number(b.inputSerialId));
1144
+ const fundOutputSerialId = (0, Utils_1.generateSerialId)();
1145
+ (0, assert_1.default)(changeSerialId !== fundOutputSerialId, 'changeSerialId cannot equal the fundOutputSerialId');
1146
+ dlcOffer.contractFlags = Buffer.from('00', 'hex');
1147
+ dlcOffer.chainHash = (0, bitcoin_networks_1.chainHashFromNetwork)(network);
1148
+ dlcOffer.contractInfo = contractInfo;
1149
+ dlcOffer.fundingPubKey = fundingPubKey;
1150
+ dlcOffer.payoutSPK = payoutSPK;
1151
+ dlcOffer.payoutSerialId = payoutSerialId;
1152
+ dlcOffer.offerCollateralSatoshis = offerCollateralSatoshis;
1153
+ dlcOffer.fundingInputs = fundingInputs;
1154
+ dlcOffer.changeSPK = changeSPK;
1155
+ dlcOffer.changeSerialId = changeSerialId;
1156
+ dlcOffer.fundOutputSerialId = dlcOffer.fundOutputSerialId = fundOutputSerialId;
1157
+ dlcOffer.feeRatePerVb = feeRatePerVb;
1158
+ dlcOffer.cetLocktime = cetLocktime;
1159
+ dlcOffer.refundLocktime = refundLocktime;
1160
+ (0, assert_1.default)((() => {
1161
+ const finalizer = new core_1.DualFundingTxFinalizer(dlcOffer.fundingInputs, dlcOffer.payoutSPK, dlcOffer.changeSPK, null, null, null, dlcOffer.feeRatePerVb);
1162
+ const funding = fundingInputs.reduce((total, input) => {
1163
+ return total + input.prevTx.outputs[input.prevTxVout].value.sats;
1164
+ }, BigInt(0));
1165
+ return funding >= offerCollateralSatoshis + finalizer.offerFees;
1166
+ })(), 'fundingInputs for dlcOffer must be greater than offerCollateralSatoshis plus offerFees');
1167
+ dlcOffer.validate();
1168
+ return dlcOffer;
1169
+ }
1170
+ async batchCreateDlcOffer(contractInfos, offerCollaterals, feeRatePerVb, cetLocktime, refundLocktimes, fixedInputs) {
1171
+ if (contractInfos.length !== offerCollaterals.length ||
1172
+ contractInfos.length !== refundLocktimes.length) {
1173
+ throw new Error('The number of contractInfos, offerCollateralSatoshis, and refundLocktimes must be the same');
1174
+ }
1175
+ const dlcOffers = [];
1176
+ for (let i = 0; i < contractInfos.length; i++) {
1177
+ contractInfos[i].validate();
1178
+ }
1179
+ const network = await this.getConnectedNetwork();
1180
+ const { fundingInputs: _fundingInputs, changeSPK, changeSerialId, initializeResponses, } = await this.BatchInitialize(offerCollaterals, feeRatePerVb, fixedInputs);
1181
+ _fundingInputs.forEach((input) => (0, assert_1.default)(input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0'));
1182
+ const fundingInputs = _fundingInputs.map((input) => input);
1183
+ fundingInputs.sort((a, b) => Number(a.inputSerialId) - Number(b.inputSerialId));
1184
+ const fundOutputsSerialIds = (0, Utils_1.generateSerialIds)(contractInfos.length);
1185
+ for (let i = 0; i < contractInfos.length; i++) {
1186
+ const contractInfo = contractInfos[i];
1187
+ const offerCollateralSatoshis = offerCollaterals[i];
1188
+ const fundOutputSerialId = fundOutputsSerialIds[i];
1189
+ const { fundingPubKey, payoutSPK, payoutSerialId } = initializeResponses[i];
1190
+ const refundLocktime = refundLocktimes[i];
1191
+ const dlcOffer = new messaging_1.DlcOfferV0();
1192
+ dlcOffer.contractFlags = Buffer.from('00', 'hex');
1193
+ dlcOffer.chainHash = (0, bitcoin_networks_1.chainHashFromNetwork)(network);
1194
+ dlcOffer.contractInfo = contractInfo;
1195
+ dlcOffer.fundingPubKey = fundingPubKey;
1196
+ dlcOffer.payoutSPK = payoutSPK;
1197
+ dlcOffer.payoutSerialId = payoutSerialId;
1198
+ dlcOffer.offerCollateralSatoshis = offerCollateralSatoshis;
1199
+ dlcOffer.fundingInputs = fundingInputs;
1200
+ dlcOffer.changeSPK = changeSPK;
1201
+ dlcOffer.changeSerialId = changeSerialId;
1202
+ dlcOffer.fundOutputSerialId = fundOutputSerialId;
1203
+ dlcOffer.feeRatePerVb = feeRatePerVb;
1204
+ dlcOffer.cetLocktime = cetLocktime;
1205
+ dlcOffer.refundLocktime = refundLocktime;
1206
+ (0, assert_1.default)((() => {
1207
+ const finalizer = new core_1.DualFundingTxFinalizer(dlcOffer.fundingInputs, dlcOffer.payoutSPK, dlcOffer.changeSPK, null, null, null, dlcOffer.feeRatePerVb);
1208
+ const funding = fundingInputs.reduce((total, input) => {
1209
+ return total + input.prevTx.outputs[input.prevTxVout].value.sats;
1210
+ }, BigInt(0));
1211
+ return funding >= offerCollateralSatoshis + finalizer.offerFees;
1212
+ })(), 'fundingInputs for dlcOffer must be greater than offerCollateralSatoshis plus offerFees');
1213
+ dlcOffer.validate();
1214
+ dlcOffers.push(dlcOffer);
1215
+ }
1216
+ return dlcOffers;
1217
+ }
1218
+ /**
1219
+ * Accept DLC Offer
1220
+ * @param _dlcOffer Dlc Offer Message
1221
+ * @param fixedInputs Optional inputs to use for Funding Inputs
1222
+ * @returns {Promise<AcceptDlcOfferResponse}
1223
+ */
1224
+ async acceptDlcOffer(_dlcOffer, fixedInputs) {
1225
+ const { dlcOffer } = (0, Utils_1.checkTypes)({ _dlcOffer });
1226
+ dlcOffer.validate();
1227
+ const acceptCollateralSatoshis = dlcOffer.contractInfo.totalCollateral - dlcOffer.offerCollateralSatoshis;
1228
+ (0, assert_1.default)(acceptCollateralSatoshis ===
1229
+ dlcOffer.contractInfo.totalCollateral -
1230
+ dlcOffer.offerCollateralSatoshis, 'acceptCollaterialSatoshis should equal totalCollateral - offerCollateralSatoshis');
1231
+ const { fundingPubKey, payoutSPK, payoutSerialId, fundingInputs: _fundingInputs, changeSPK, changeSerialId, } = await this.Initialize(acceptCollateralSatoshis, dlcOffer.feeRatePerVb, fixedInputs);
1232
+ (0, assert_1.default)(Buffer.compare(dlcOffer.fundingPubKey, fundingPubKey) !== 0, 'DlcOffer and DlcAccept FundingPubKey cannot be the same');
1233
+ _fundingInputs.forEach((input) => (0, assert_1.default)(input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0'));
1234
+ const fundingInputs = _fundingInputs.map((input) => input);
1235
+ fundingInputs.sort((a, b) => Number(a.inputSerialId) - Number(b.inputSerialId));
1236
+ const dlcAccept = new messaging_1.DlcAcceptV0();
1237
+ dlcAccept.tempContractId = (0, crypto_1.sha256)(dlcOffer.serialize());
1238
+ dlcAccept.acceptCollateralSatoshis = acceptCollateralSatoshis;
1239
+ dlcAccept.fundingPubKey = fundingPubKey;
1240
+ dlcAccept.payoutSPK = payoutSPK;
1241
+ dlcAccept.payoutSerialId = dlcAccept.payoutSerialId = payoutSerialId;
1242
+ dlcAccept.fundingInputs = fundingInputs;
1243
+ dlcAccept.changeSPK = changeSPK;
1244
+ dlcAccept.changeSerialId = dlcAccept.changeSerialId = changeSerialId;
1245
+ (0, assert_1.default)(dlcAccept.changeSerialId !== dlcOffer.fundOutputSerialId, 'changeSerialId cannot equal the fundOutputSerialId');
1246
+ (0, assert_1.default)(dlcOffer.payoutSerialId !== dlcAccept.payoutSerialId, 'offer.payoutSerialId cannot equal accept.payoutSerialId');
1247
+ (0, assert_1.default)((() => {
1248
+ const ids = [
1249
+ dlcOffer.changeSerialId,
1250
+ dlcAccept.changeSerialId,
1251
+ dlcOffer.fundOutputSerialId,
1252
+ ];
1253
+ return new Set(ids).size === ids.length;
1254
+ })(), 'offer.changeSerialID, accept.changeSerialId and fundOutputSerialId must be unique');
1255
+ dlcAccept.validate();
1256
+ (0, assert_1.default)((() => {
1257
+ const finalizer = new core_1.DualFundingTxFinalizer(dlcOffer.fundingInputs, dlcOffer.payoutSPK, dlcOffer.changeSPK, dlcAccept.fundingInputs, dlcAccept.payoutSPK, dlcAccept.changeSPK, dlcOffer.feeRatePerVb);
1258
+ const funding = fundingInputs.reduce((total, input) => {
1259
+ return total + input.prevTx.outputs[input.prevTxVout].value.sats;
1260
+ }, BigInt(0));
1261
+ return funding >= acceptCollateralSatoshis + finalizer.acceptFees;
1262
+ })(), 'fundingInputs for dlcAccept must be greater than acceptCollateralSatoshis plus acceptFees');
1263
+ const { dlcTransactions, messagesList } = await this.createDlcTxs(dlcOffer, dlcAccept);
1264
+ const { cetSignatures, refundSignature, } = await this.CreateCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcTransactions, messagesList, false);
1265
+ (0, assert_1.default)(dlcTransactions.type === messaging_1.MessageType.DlcTransactionsV0, 'DlcTransactions must be V0');
1266
+ const _dlcTransactions = dlcTransactions;
1267
+ const contractId = (0, crypto_1.xor)(_dlcTransactions.fundTx.txId.serialize(), dlcAccept.tempContractId);
1268
+ _dlcTransactions.contractId = contractId;
1269
+ dlcAccept.cetSignatures = cetSignatures;
1270
+ dlcAccept.refundSignature = refundSignature;
1271
+ dlcAccept.negotiationFields = new messaging_1.NegotiationFieldsV0();
1272
+ return { dlcAccept, dlcTransactions: _dlcTransactions };
1273
+ }
1274
+ async batchAcceptDlcOffer(_dlcOffers, fixedInputs) {
1275
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
1276
+ const { dlcOffer } = (0, Utils_1.checkTypes)({ _dlcOffer });
1277
+ dlcOffer.validate();
1278
+ return dlcOffer;
1279
+ });
1280
+ const acceptCollaterals = dlcOffers.map((dlcOffer) => dlcOffer.contractInfo.totalCollateral -
1281
+ dlcOffer.offerCollateralSatoshis);
1282
+ const { fundingInputs: _fundingInputs, changeSPK, changeSerialId, initializeResponses, } = await this.BatchInitialize(acceptCollaterals, dlcOffers[0].feeRatePerVb, fixedInputs);
1283
+ // Check that none of the funding pubkeys are the same between the
1284
+ // dlcOffers and the dlcAccepts (from initializeResponses)
1285
+ dlcOffers.forEach((dlcOffer) => {
1286
+ initializeResponses.forEach((initializeResponse) => {
1287
+ (0, assert_1.default)(Buffer.compare(dlcOffer.fundingPubKey, initializeResponse.fundingPubKey) !== 0, 'DlcOffer and DlcAccept FundingPubKey cannot be the same');
1288
+ });
1289
+ });
1290
+ _fundingInputs.forEach((input) => (0, assert_1.default)(input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0'));
1291
+ const fundingInputs = _fundingInputs.map((input) => input);
1292
+ fundingInputs.sort((a, b) => Number(a.inputSerialId) - Number(b.inputSerialId));
1293
+ const dlcAccepts = [];
1294
+ initializeResponses.forEach((initializeResponse, i) => {
1295
+ const dlcOffer = dlcOffers[i];
1296
+ const dlcAccept = new messaging_1.DlcAcceptV0();
1297
+ const { fundingPubKey, payoutSPK, payoutSerialId } = initializeResponse;
1298
+ dlcAccept.tempContractId = (0, crypto_1.sha256)(dlcOffers[i].serialize());
1299
+ dlcAccept.acceptCollateralSatoshis = acceptCollaterals[i];
1300
+ dlcAccept.fundingPubKey = fundingPubKey;
1301
+ dlcAccept.payoutSPK = payoutSPK;
1302
+ dlcAccept.payoutSerialId = payoutSerialId;
1303
+ dlcAccept.fundingInputs = fundingInputs;
1304
+ dlcAccept.changeSPK = changeSPK;
1305
+ dlcAccept.changeSerialId = changeSerialId;
1306
+ (0, assert_1.default)(dlcAccept.changeSerialId !== dlcOffer.fundOutputSerialId, 'changeSerialId cannot equal the fundOutputSerialId');
1307
+ (0, assert_1.default)(dlcOffer.payoutSerialId !== dlcAccept.payoutSerialId, 'offer.payoutSerialId cannot equal accept.payoutSerialId');
1308
+ (0, assert_1.default)((() => {
1309
+ const ids = [
1310
+ dlcOffer.changeSerialId,
1311
+ dlcAccept.changeSerialId,
1312
+ dlcOffer.fundOutputSerialId,
1313
+ ];
1314
+ return new Set(ids).size === ids.length;
1315
+ })(), 'offer.changeSerialID, accept.changeSerialId and fundOutputSerialId must be unique');
1316
+ dlcAccept.validate();
1317
+ (0, assert_1.default)((() => {
1318
+ const finalizer = new core_1.DualFundingTxFinalizer(dlcOffer.fundingInputs, dlcOffer.payoutSPK, dlcOffer.changeSPK, dlcAccept.fundingInputs, dlcAccept.payoutSPK, dlcAccept.changeSPK, dlcOffer.feeRatePerVb);
1319
+ const funding = fundingInputs.reduce((total, input) => {
1320
+ return total + input.prevTx.outputs[input.prevTxVout].value.sats;
1321
+ }, BigInt(0));
1322
+ return funding >= acceptCollaterals[i] + finalizer.acceptFees;
1323
+ })(), 'fundingInputs for dlcAccept must be greater than acceptCollateralSatoshis plus acceptFees');
1324
+ dlcAccepts.push(dlcAccept);
1325
+ });
1326
+ const { dlcTransactionsList, nestedMessagesList, } = await this.createBatchDlcTxs(dlcOffers, dlcAccepts);
1327
+ for (let i = 0; i < dlcAccepts.length; i++) {
1328
+ const dlcOffer = dlcOffers[i];
1329
+ const dlcAccept = dlcAccepts[i];
1330
+ const dlcTransactions = dlcTransactionsList[i];
1331
+ const messagesList = nestedMessagesList[i];
1332
+ const { cetSignatures, refundSignature, } = await this.CreateCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcTransactions, messagesList, false);
1333
+ (0, assert_1.default)(dlcTransactions.type === messaging_1.MessageType.DlcTransactionsV0, 'DlcTransactions must be V0');
1334
+ const _dlcTransactions = dlcTransactions;
1335
+ const contractId = (0, crypto_1.xor)(_dlcTransactions.fundTx.txId.serialize(), dlcAccept.tempContractId);
1336
+ _dlcTransactions.contractId = contractId;
1337
+ dlcAccepts[i].cetSignatures = cetSignatures;
1338
+ dlcAccepts[i].refundSignature = refundSignature;
1339
+ dlcAccepts[i].negotiationFields = new messaging_1.NegotiationFieldsV0();
1340
+ }
1341
+ return { dlcAccepts, dlcTransactionsList };
1342
+ }
1343
+ /**
1344
+ * Sign Dlc Accept Message
1345
+ * @param _dlcOffer Dlc Offer Message
1346
+ * @param _dlcAccept Dlc Accept Message
1347
+ * @returns {Promise<SignDlcAcceptResponse}
1348
+ */
1349
+ async signDlcAccept(_dlcOffer, _dlcAccept) {
1350
+ const { dlcOffer, dlcAccept } = (0, Utils_1.checkTypes)({
1351
+ _dlcOffer,
1352
+ _dlcAccept,
1353
+ });
1354
+ dlcOffer.validate();
1355
+ dlcAccept.validate();
1356
+ (0, assert_1.default)(Buffer.compare(dlcOffer.fundingPubKey, dlcAccept.fundingPubKey) !== 0, 'DlcOffer and DlcAccept FundingPubKey cannot be the same');
1357
+ const dlcSign = new messaging_1.DlcSignV0();
1358
+ const { dlcTransactions, messagesList } = await this.createDlcTxs(dlcOffer, dlcAccept);
1359
+ await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTransactions, messagesList, true);
1360
+ const { cetSignatures, refundSignature, } = await this.CreateCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcTransactions, messagesList, true);
1361
+ const fundingSignatures = await this.CreateFundingSigs(dlcOffer, dlcAccept, dlcTransactions, true);
1362
+ const dlcTxs = dlcTransactions;
1363
+ const contractId = (0, crypto_1.xor)(dlcTxs.fundTx.txId.serialize(), dlcAccept.tempContractId);
1364
+ (0, assert_1.default)(Buffer.compare(contractId, (0, crypto_1.xor)(dlcTxs.fundTx.txId.serialize(), dlcAccept.tempContractId)) === 0, 'contractId must be the xor of funding txid, fundingOutputIndex and the tempContractId');
1365
+ dlcTxs.contractId = contractId;
1366
+ dlcSign.contractId = contractId;
1367
+ dlcSign.cetSignatures = cetSignatures;
1368
+ dlcSign.refundSignature = refundSignature;
1369
+ dlcSign.fundingSignatures = fundingSignatures;
1370
+ return { dlcSign, dlcTransactions: dlcTxs };
1371
+ }
1372
+ async batchSignDlcAccept(_dlcOffers, _dlcAccepts) {
1373
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
1374
+ const { dlcOffer } = (0, Utils_1.checkTypes)({ _dlcOffer });
1375
+ dlcOffer.validate();
1376
+ return dlcOffer;
1377
+ });
1378
+ const dlcAccepts = _dlcAccepts.map((_dlcAccept) => {
1379
+ const { dlcAccept } = (0, Utils_1.checkTypes)({ _dlcAccept });
1380
+ dlcAccept.validate();
1381
+ return dlcAccept;
1382
+ });
1383
+ const { dlcTransactionsList, nestedMessagesList, } = await this.createBatchDlcTxs(dlcOffers, dlcAccepts);
1384
+ const dlcSigns = [];
1385
+ const fundingSignatures = await this.CreateFundingSigs(dlcOffers[0], dlcAccepts[0], dlcTransactionsList[0], true);
1386
+ for (let i = 0; i < dlcAccepts.length; i++) {
1387
+ const dlcOffer = dlcOffers[i];
1388
+ const dlcAccept = dlcAccepts[i];
1389
+ const dlcTransactions = dlcTransactionsList[i];
1390
+ const messagesList = nestedMessagesList[i];
1391
+ const dlcSign = new messaging_1.DlcSignV0();
1392
+ await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTransactions, messagesList, true);
1393
+ const { cetSignatures, refundSignature, } = await this.CreateCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcTransactions, messagesList, true);
1394
+ const dlcTxs = dlcTransactions;
1395
+ const contractId = (0, crypto_1.xor)(dlcTxs.fundTx.txId.serialize(), dlcAccept.tempContractId);
1396
+ dlcTxs.contractId = contractId;
1397
+ dlcSign.contractId = contractId;
1398
+ dlcSign.cetSignatures = cetSignatures;
1399
+ dlcSign.refundSignature = refundSignature;
1400
+ dlcSign.fundingSignatures = fundingSignatures;
1401
+ dlcSigns.push(dlcSign);
1402
+ }
1403
+ return { dlcSigns, dlcTransactionsList };
1404
+ }
1405
+ /**
1406
+ * Finalize Dlc Sign
1407
+ * @param _dlcOffer Dlc Offer Message
1408
+ * @param _dlcAccept Dlc Accept Message
1409
+ * @param _dlcSign Dlc Sign Message
1410
+ * @param _dlcTxs Dlc Transactions Message
1411
+ * @returns {Promise<Tx>}
1412
+ */
1413
+ async finalizeDlcSign(_dlcOffer, _dlcAccept, _dlcSign, _dlcTxs) {
1414
+ const { dlcOffer, dlcAccept, dlcSign, dlcTxs } = (0, Utils_1.checkTypes)({
1415
+ _dlcOffer,
1416
+ _dlcAccept,
1417
+ _dlcSign,
1418
+ _dlcTxs,
1419
+ });
1420
+ const payoutResponses = this.GetPayouts(dlcOffer);
1421
+ const { messagesList } = this.FlattenPayouts(payoutResponses);
1422
+ await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTxs, messagesList, false);
1423
+ await this.VerifyFundingSigs(dlcOffer, dlcAccept, dlcSign, dlcTxs, false);
1424
+ const fundingSignatures = await this.CreateFundingSigs(dlcOffer, dlcAccept, dlcTxs, false);
1425
+ const fundTx = await this.CreateFundingTx(dlcOffer, dlcAccept, dlcSign, dlcTxs, fundingSignatures);
1426
+ return fundTx;
1427
+ }
1428
+ async batchFinalizeDlcSign(_dlcOffers, _dlcAccepts, _dlcSigns, _dlcTxsList) {
1429
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
1430
+ const { dlcOffer } = (0, Utils_1.checkTypes)({ _dlcOffer });
1431
+ dlcOffer.validate();
1432
+ return dlcOffer;
1433
+ });
1434
+ const dlcAccepts = _dlcAccepts.map((_dlcAccept) => {
1435
+ const { dlcAccept } = (0, Utils_1.checkTypes)({ _dlcAccept });
1436
+ dlcAccept.validate();
1437
+ return dlcAccept;
1438
+ });
1439
+ const dlcSigns = _dlcSigns.map((_dlcSign) => {
1440
+ const { dlcSign } = (0, Utils_1.checkTypes)({ _dlcSign });
1441
+ return dlcSign;
1442
+ });
1443
+ const dlcTxsList = _dlcTxsList.map((_dlcTxs) => {
1444
+ const { dlcTxs } = (0, Utils_1.checkTypes)({ _dlcTxs });
1445
+ return dlcTxs;
1446
+ });
1447
+ await this.VerifyFundingSigs(dlcOffers[0], dlcAccepts[0], dlcSigns[0], dlcTxsList[0], false);
1448
+ for (let i = 0; i < dlcOffers.length; i++) {
1449
+ const dlcOffer = dlcOffers[i];
1450
+ const dlcAccept = dlcAccepts[i];
1451
+ const dlcSign = dlcSigns[i];
1452
+ const dlcTxs = dlcTxsList[i];
1453
+ const payoutResponses = this.GetPayouts(dlcOffer);
1454
+ const { messagesList } = this.FlattenPayouts(payoutResponses);
1455
+ await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTxs, messagesList, false);
1456
+ }
1457
+ const fundingSignatures = await this.CreateFundingSigs(dlcOffers[0], dlcAccepts[0], dlcTxsList[0], false);
1458
+ const fundTx = await this.CreateFundingTx(dlcOffers[0], dlcAccepts[0], dlcSigns[0], dlcTxsList[0], fundingSignatures);
1459
+ return fundTx;
1460
+ }
1461
+ /**
1462
+ * Execute DLC
1463
+ * @param _dlcOffer Dlc Offer Message
1464
+ * @param _dlcAccept Dlc Accept Message
1465
+ * @param _dlcSign Dlc Sign Message
1466
+ * @param _dlcTxs Dlc Transactions Message
1467
+ * @param oracleAttestation Oracle Attestations TLV (V0)
1468
+ * @param isOfferer Whether party is Dlc Offerer
1469
+ * @returns {Promise<Tx>}
1470
+ */
1471
+ async execute(_dlcOffer, _dlcAccept, _dlcSign, _dlcTxs, oracleAttestation, isOfferer) {
1472
+ const { dlcOffer, dlcAccept, dlcSign, dlcTxs } = (0, Utils_1.checkTypes)({
1473
+ _dlcOffer,
1474
+ _dlcAccept,
1475
+ _dlcSign,
1476
+ _dlcTxs,
1477
+ });
1478
+ if (isOfferer === undefined)
1479
+ isOfferer = await this.isOfferer(dlcOffer, dlcAccept);
1480
+ this.ValidateEvent(dlcOffer, oracleAttestation);
1481
+ return this.FindAndSignCet(dlcOffer, dlcAccept, dlcSign, dlcTxs, oracleAttestation, isOfferer);
1482
+ }
1483
+ /**
1484
+ * Refund DLC
1485
+ * @param _dlcOffer Dlc Offer Message
1486
+ * @param _dlcAccept Dlc Accept Message
1487
+ * @param _dlcSign Dlc Sign Message
1488
+ * @param _dlcTxs Dlc Transactions message
1489
+ * @returns {Promise<Tx>}
1490
+ */
1491
+ async refund(_dlcOffer, _dlcAccept, _dlcSign, _dlcTxs) {
1492
+ const { dlcOffer, dlcAccept, dlcSign, dlcTxs } = (0, Utils_1.checkTypes)({
1493
+ _dlcOffer,
1494
+ _dlcAccept,
1495
+ _dlcSign,
1496
+ _dlcTxs,
1497
+ });
1498
+ const signatures = Buffer.compare(dlcOffer.fundingPubKey, dlcAccept.fundingPubKey) === -1
1499
+ ? [
1500
+ dlcSign.refundSignature.toString('hex'),
1501
+ dlcAccept.refundSignature.toString('hex'),
1502
+ ]
1503
+ : [
1504
+ dlcAccept.refundSignature.toString('hex'),
1505
+ dlcSign.refundSignature.toString('hex'),
1506
+ ];
1507
+ const addSigsToRefundTxRequest = {
1508
+ refundTxHex: dlcTxs.refundTx.serialize().toString('hex'),
1509
+ signatures,
1510
+ fundTxId: dlcTxs.fundTx.txId.toString(),
1511
+ fundVout: dlcTxs.fundTxVout,
1512
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
1513
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
1514
+ };
1515
+ const refundHex = (await this.AddSignaturesToRefundTx(addSigsToRefundTxRequest)).hex;
1516
+ return bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(refundHex));
1517
+ }
1518
+ /**
1519
+ * Goal of createDlcClose is for alice (the initiator) to
1520
+ * 1. take dlcoffer, accept, and sign messages. Create a dlcClose message.
1521
+ * 2. Build a close tx, sign.
1522
+ * 3. return dlcClose message (no psbt)
1523
+ */
1524
+ /**
1525
+ * Generate DlcClose messagetype for closing DLC with Mutual Consent
1526
+ * @param _dlcOffer DlcOffer TLV (V0)
1527
+ * @param _dlcAccept DlcAccept TLV (V0)
1528
+ * @param _dlcTxs DlcTransactions TLV (V0)
1529
+ * @param initiatorPayoutSatoshis Amount initiator expects as a payout
1530
+ * @param isOfferer Whether offerer or not
1531
+ * @param _inputs Optionally specified closing inputs
1532
+ * @returns {Promise<DlcClose>}
1533
+ */
1534
+ async createDlcClose(_dlcOffer, _dlcAccept, _dlcTxs, initiatorPayoutSatoshis, isOfferer, _inputs) {
1535
+ const { dlcOffer, dlcAccept, dlcTxs } = (0, Utils_1.checkTypes)({
1536
+ _dlcOffer,
1537
+ _dlcAccept,
1538
+ _dlcTxs,
1539
+ });
1540
+ if (isOfferer === undefined)
1541
+ isOfferer = await this.isOfferer(dlcOffer, dlcAccept);
1542
+ const network = await this.getConnectedNetwork();
1543
+ const psbt = new bitcoinjs_lib_1.Psbt({ network });
1544
+ const fundingPubKeys = Buffer.compare(dlcOffer.fundingPubKey, dlcAccept.fundingPubKey) === -1
1545
+ ? [dlcOffer.fundingPubKey, dlcAccept.fundingPubKey]
1546
+ : [dlcAccept.fundingPubKey, dlcOffer.fundingPubKey];
1547
+ const p2ms = bitcoinjs_lib_1.payments.p2ms({
1548
+ m: 2,
1549
+ pubkeys: fundingPubKeys,
1550
+ network,
1551
+ });
1552
+ const paymentVariant = bitcoinjs_lib_1.payments.p2wsh({
1553
+ redeem: p2ms,
1554
+ network,
1555
+ });
1556
+ // Initiate and build PSBT
1557
+ let inputs = _inputs;
1558
+ if (!_inputs) {
1559
+ const tempInputs = await this.GetInputsForAmount([BigInt(20000)], dlcOffer.feeRatePerVb, _inputs);
1560
+ _inputs = tempInputs;
1561
+ }
1562
+ inputs = _inputs.map((input) => {
1563
+ return {
1564
+ ...input,
1565
+ inputSerialId: input.inputSerialId || (0, Utils_1.generateSerialId)(),
1566
+ toUtxo: input.toUtxo,
1567
+ };
1568
+ });
1569
+ const pubkeys = await Promise.all(inputs.map(async (input) => {
1570
+ const address = await this.getMethod('getWalletAddress')(input.address);
1571
+ return Buffer.from(address.publicKey, 'hex');
1572
+ }));
1573
+ const fundingInputSerialId = (0, Utils_1.generateSerialId)();
1574
+ // Make temporary array to hold all inputs and then sort them
1575
+ // this method can be improved later
1576
+ const psbtInputs = [];
1577
+ psbtInputs.push({
1578
+ hash: dlcTxs.fundTx.txId.serialize(),
1579
+ index: dlcTxs.fundTxVout,
1580
+ sequence: 0,
1581
+ witnessUtxo: {
1582
+ script: paymentVariant.output,
1583
+ value: Number(dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats),
1584
+ },
1585
+ witnessScript: paymentVariant.redeem.output,
1586
+ inputSerialId: fundingInputSerialId,
1587
+ derivationPath: null,
1588
+ });
1589
+ // add all dlc close inputs
1590
+ inputs.forEach((input, i) => {
1591
+ const paymentVariant = bitcoinjs_lib_1.payments.p2wpkh({ pubkey: pubkeys[i], network });
1592
+ psbtInputs.push({
1593
+ hash: input.txid,
1594
+ index: input.vout,
1595
+ sequence: 0,
1596
+ witnessUtxo: {
1597
+ script: paymentVariant.output,
1598
+ value: input.value,
1599
+ },
1600
+ inputSerialId: input.inputSerialId,
1601
+ derivationPath: input.derivationPath,
1602
+ });
1603
+ });
1604
+ // sort all inputs in ascending order by serial ID
1605
+ // The only reason we are doing this is for privacy. If the fundingInput is
1606
+ // always first, it is very obvious. Hence, a serialId is randomly generated
1607
+ // and the inputs are sorted by that instead.
1608
+ const sortedPsbtInputs = psbtInputs.sort((a, b) => Number(a.inputSerialId - b.inputSerialId));
1609
+ // Get index of fundingInput
1610
+ const fundingInputIndex = sortedPsbtInputs.findIndex((input) => input.inputSerialId === fundingInputSerialId);
1611
+ // add to psbt
1612
+ sortedPsbtInputs.forEach((input, i) => psbt.addInput(input));
1613
+ const fundingInputs = await Promise.all(inputs.map(async (input) => {
1614
+ return this.inputToFundingInput(input);
1615
+ }));
1616
+ const finalizer = new core_1.DualClosingTxFinalizer(fundingInputs, dlcOffer.payoutSPK, dlcAccept.payoutSPK, dlcOffer.feeRatePerVb);
1617
+ const closeInputAmount = BigInt(inputs.reduce((acc, val) => acc + val.value, 0));
1618
+ const offerPayoutValue = isOfferer
1619
+ ? closeInputAmount +
1620
+ initiatorPayoutSatoshis -
1621
+ finalizer.offerInitiatorFees
1622
+ : dlcOffer.contractInfo.totalCollateral - initiatorPayoutSatoshis;
1623
+ const acceptPayoutValue = isOfferer
1624
+ ? dlcOffer.contractInfo.totalCollateral - initiatorPayoutSatoshis
1625
+ : closeInputAmount +
1626
+ initiatorPayoutSatoshis -
1627
+ finalizer.offerInitiatorFees;
1628
+ const offerFirst = dlcOffer.payoutSerialId < dlcAccept.payoutSerialId;
1629
+ psbt.addOutput({
1630
+ value: Number(offerFirst ? offerPayoutValue : acceptPayoutValue),
1631
+ address: bitcoinjs_lib_1.address.fromOutputScript(offerFirst ? dlcOffer.payoutSPK : dlcAccept.payoutSPK, network),
1632
+ });
1633
+ psbt.addOutput({
1634
+ value: Number(offerFirst ? acceptPayoutValue : offerPayoutValue),
1635
+ address: bitcoinjs_lib_1.address.fromOutputScript(offerFirst ? dlcAccept.payoutSPK : dlcOffer.payoutSPK, network),
1636
+ });
1637
+ // Generate keypair to sign inputs
1638
+ const fundPrivateKeyPair = await this.GetFundKeyPair(dlcOffer, dlcAccept, isOfferer);
1639
+ // Sign dlc fundinginput
1640
+ psbt.signInput(fundingInputIndex, fundPrivateKeyPair);
1641
+ // Sign dlcclose inputs
1642
+ await Promise.all(sortedPsbtInputs.map(async (input, i) => {
1643
+ if (i === fundingInputIndex)
1644
+ return;
1645
+ // derive keypair
1646
+ const keyPair = await this.getMethod('keyPair')(input.derivationPath);
1647
+ psbt.signInput(i, keyPair);
1648
+ }));
1649
+ // Validate signatures
1650
+ psbt.validateSignaturesOfAllInputs();
1651
+ // Extract close signature from psbt and decode it to only extract r and s values
1652
+ const closeSignature = await bitcoinjs_lib_1.script.signature.decode(psbt.data.inputs[fundingInputIndex].partialSig[0].signature).signature;
1653
+ // Extract funding signatures from psbt
1654
+ const inputSigs = psbt.data.inputs
1655
+ .filter((input) => input !== fundingInputIndex)
1656
+ .map((input) => input.partialSig[0]);
1657
+ // create fundingSignatures
1658
+ const witnessElements = [];
1659
+ for (let i = 0; i < inputSigs.length; i++) {
1660
+ const sigWitness = new messaging_1.ScriptWitnessV0();
1661
+ sigWitness.witness = inputSigs[i].signature;
1662
+ const pubKeyWitness = new messaging_1.ScriptWitnessV0();
1663
+ pubKeyWitness.witness = inputSigs[i].pubkey;
1664
+ witnessElements.push([sigWitness, pubKeyWitness]);
1665
+ }
1666
+ const fundingSignatures = new messaging_1.FundingSignaturesV0();
1667
+ fundingSignatures.witnessElements = witnessElements;
1668
+ // Create DlcClose
1669
+ const dlcClose = new messaging_1.DlcCloseV0();
1670
+ dlcClose.contractId = dlcTxs.contractId;
1671
+ dlcClose.offerPayoutSatoshis = BigInt(psbt.txOutputs[offerFirst ? 0 : 1].value); // You give collateral back to users
1672
+ dlcClose.acceptPayoutSatoshis = BigInt(psbt.txOutputs[offerFirst ? 1 : 0].value); // give collateral back to users
1673
+ dlcClose.fundInputSerialId = fundingInputSerialId; // randomly generated serial id
1674
+ dlcClose.closeSignature = closeSignature;
1675
+ dlcClose.fundingSignatures = fundingSignatures;
1676
+ dlcClose.fundingInputs = fundingInputs;
1677
+ dlcClose.validate();
1678
+ return dlcClose;
1679
+ }
1680
+ /**
1681
+ * Generate multiple DlcClose messagetypes for closing DLC with Mutual Consent
1682
+ * @param _dlcOffer DlcOffer TLV (V0)
1683
+ * @param _dlcAccept DlcAccept TLV (V0)
1684
+ * @param _dlcTxs DlcTransactions TLV (V0)
1685
+ * @param initiatorPayouts Array of amounts initiator expects as payouts
1686
+ * @param isOfferer Whether offerer or not
1687
+ * @param _inputs Optionally specified closing inputs
1688
+ * @returns {Promise<DlcClose[]>}
1689
+ */
1690
+ async createBatchDlcClose(_dlcOffer, _dlcAccept, _dlcTxs, initiatorPayouts, isOfferer, _inputs) {
1691
+ const { dlcOffer, dlcAccept, dlcTxs } = (0, Utils_1.checkTypes)({
1692
+ _dlcOffer,
1693
+ _dlcAccept,
1694
+ _dlcTxs,
1695
+ });
1696
+ if (isOfferer === undefined)
1697
+ isOfferer = await this.isOfferer(dlcOffer, dlcAccept);
1698
+ if (_inputs && _inputs.length > 0)
1699
+ throw Error('funding inputs not supported on BatchDlcClose'); // TODO support multiple funding inputs
1700
+ const fundingInputSerialId = (0, Utils_1.generateSerialId)();
1701
+ const fundingInputs = []; // TODO: support multiple funding inputs
1702
+ const finalizer = new core_1.DualClosingTxFinalizer(fundingInputs, dlcOffer.payoutSPK, dlcAccept.payoutSPK, dlcOffer.feeRatePerVb);
1703
+ // Generate keypair to sign inputs
1704
+ const fundPrivateKeyPair = await this.GetFundKeyPair(dlcOffer, dlcAccept, isOfferer);
1705
+ const closeInputAmount = BigInt(0); // TODO support multiple funding inputs
1706
+ const privKey = Buffer.from(fundPrivateKeyPair.privateKey).toString('hex');
1707
+ const rawCloseTxs = await this.CreateCloseRawTxs(dlcOffer, dlcAccept, dlcTxs, closeInputAmount, isOfferer, [], fundingInputs, initiatorPayouts);
1708
+ const sigHashes = await this.CreateSignatureHashes(dlcOffer, dlcAccept, dlcTxs, rawCloseTxs);
1709
+ const signatures = await this.CalculateEcSignatureHashes(sigHashes, privKey);
1710
+ const dlcCloses = [];
1711
+ signatures.forEach((sig, i) => {
1712
+ const payout = initiatorPayouts[i];
1713
+ const payoutMinusOfferFees = finalizer.offerInitiatorFees > payout
1714
+ ? BigInt(0)
1715
+ : payout - finalizer.offerInitiatorFees;
1716
+ const collateralMinusPayout = payout > dlcOffer.contractInfo.totalCollateral
1717
+ ? BigInt(0)
1718
+ : dlcOffer.contractInfo.totalCollateral - payout;
1719
+ const offerPayoutValue = isOfferer
1720
+ ? closeInputAmount + payoutMinusOfferFees
1721
+ : collateralMinusPayout;
1722
+ const acceptPayoutValue = isOfferer
1723
+ ? collateralMinusPayout
1724
+ : closeInputAmount + payoutMinusOfferFees;
1725
+ const fundingSignatures = new messaging_1.FundingSignaturesV0();
1726
+ const dlcClose = new messaging_1.DlcCloseV0();
1727
+ dlcClose.contractId = dlcTxs.contractId;
1728
+ dlcClose.offerPayoutSatoshis = offerPayoutValue;
1729
+ dlcClose.acceptPayoutSatoshis = acceptPayoutValue;
1730
+ dlcClose.fundInputSerialId = fundingInputSerialId;
1731
+ dlcClose.closeSignature = Buffer.from(sig, 'hex');
1732
+ dlcClose.fundingSignatures = fundingSignatures;
1733
+ dlcClose.validate();
1734
+ dlcCloses.push(dlcClose);
1735
+ });
1736
+ return dlcCloses;
1737
+ }
1738
+ async verifyBatchDlcCloseUsingMetadata(dlcCloseMetadata, _dlcCloses, isOfferer) {
1739
+ const { dlcOffer, dlcAccept, dlcTxs } = dlcCloseMetadata.toDlcMessages();
1740
+ await this.verifyBatchDlcClose(dlcOffer, dlcAccept, dlcTxs, _dlcCloses, isOfferer);
1741
+ }
1742
+ /**
1743
+ * Verify multiple DlcClose messagetypes for closing DLC with Mutual Consent
1744
+ * @param _dlcOffer DlcOffer TLV (V0)
1745
+ * @param _dlcAccept DlcAccept TLV (V0)
1746
+ * @param _dlcTxs DlcTransactions TLV (V0)
1747
+ * @param _dlcCloses DlcClose[] TLV (V0)
1748
+ * @param isOfferer Whether offerer or not
1749
+ * @returns {Promise<void>}
1750
+ */
1751
+ async verifyBatchDlcClose(_dlcOffer, _dlcAccept, _dlcTxs, _dlcCloses, isOfferer) {
1752
+ const { dlcOffer, dlcAccept, dlcTxs } = (0, Utils_1.checkTypes)({
1753
+ _dlcOffer,
1754
+ _dlcAccept,
1755
+ _dlcTxs,
1756
+ });
1757
+ const dlcCloses = _dlcCloses.map((_dlcClose) => (0, Utils_1.checkTypes)({ _dlcClose }).dlcClose);
1758
+ if (isOfferer === undefined)
1759
+ isOfferer = await this.isOfferer(dlcOffer, dlcAccept);
1760
+ (0, assert_1.default)(dlcCloses.every((dlcClose) => dlcClose.fundingInputs.length === 0), 'funding inputs not supported on verify BatchDlcClose'); // TODO support multiple funding inputs
1761
+ const closeInputAmount = BigInt(0); // TODO support multiple funding inputs
1762
+ const rawCloseTxs = await this.CreateCloseRawTxs(dlcOffer, dlcAccept, dlcTxs, closeInputAmount, isOfferer, dlcCloses);
1763
+ const areSigsValid = await this.VerifySignatures(dlcOffer, dlcAccept, dlcTxs, dlcCloses, rawCloseTxs, isOfferer);
1764
+ (0, assert_1.default)(areSigsValid, 'Signatures invalid in Verify Batch DlcClose');
1765
+ }
1766
+ /**
1767
+ * Goal of finalize Dlc Close is for bob to
1768
+ * 1. take the dlcClose created by alice using createDlcClose,
1769
+ * 2. Build a psbt using Alice's dlcClose message
1770
+ * 3. Sign psbt with bob's privkey
1771
+ * 4. return a tx ready to be broadcast
1772
+ */
1773
+ /**
1774
+ * Finalize Dlc Close
1775
+ * @param _dlcOffer Dlc Offer Message
1776
+ * @param _dlcAccept Dlc Accept Message
1777
+ * @param _dlcClose Dlc Close Message
1778
+ * @param _dlcTxs Dlc Transactions Message
1779
+ * @returns {Promise<Tx>}
1780
+ */
1781
+ async finalizeDlcClose(_dlcOffer, _dlcAccept, _dlcClose, _dlcTxs) {
1782
+ const { dlcOffer, dlcAccept, dlcClose, dlcTxs } = (0, Utils_1.checkTypes)({
1783
+ _dlcOffer,
1784
+ _dlcAccept,
1785
+ _dlcClose,
1786
+ _dlcTxs,
1787
+ });
1788
+ dlcOffer.validate();
1789
+ dlcAccept.validate();
1790
+ dlcClose.validate();
1791
+ const network = await this.getConnectedNetwork();
1792
+ const psbt = new bitcoinjs_lib_1.Psbt({ network });
1793
+ const fundingPubKeys = Buffer.compare(dlcOffer.fundingPubKey, dlcAccept.fundingPubKey) === -1
1794
+ ? [dlcOffer.fundingPubKey, dlcAccept.fundingPubKey]
1795
+ : [dlcAccept.fundingPubKey, dlcOffer.fundingPubKey];
1796
+ const p2ms = bitcoinjs_lib_1.payments.p2ms({
1797
+ m: 2,
1798
+ pubkeys: fundingPubKeys,
1799
+ network,
1800
+ });
1801
+ const paymentVariant = bitcoinjs_lib_1.payments.p2wsh({
1802
+ redeem: p2ms,
1803
+ network,
1804
+ });
1805
+ // Make temporary array to hold all inputs and then sort them
1806
+ // this method can be improved later
1807
+ const psbtInputs = [];
1808
+ psbtInputs.push({
1809
+ hash: dlcTxs.fundTx.txId.serialize(),
1810
+ index: dlcTxs.fundTxVout,
1811
+ sequence: 0,
1812
+ witnessUtxo: {
1813
+ script: paymentVariant.output,
1814
+ value: Number(dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats),
1815
+ },
1816
+ witnessScript: paymentVariant.redeem.output,
1817
+ inputSerialId: dlcClose.fundInputSerialId,
1818
+ });
1819
+ // add all dlc close inputs
1820
+ dlcClose.fundingInputs.forEach((input, i) => {
1821
+ psbtInputs.push({
1822
+ hash: input.prevTx.txId.serialize(),
1823
+ index: input.prevTxVout,
1824
+ sequence: 0,
1825
+ witnessUtxo: {
1826
+ script: input.prevTx.outputs[input.prevTxVout].scriptPubKey
1827
+ .serialize()
1828
+ .slice(1),
1829
+ value: Number(input.prevTx.outputs[input.prevTxVout].value.sats),
1830
+ },
1831
+ inputSerialId: input.inputSerialId,
1832
+ });
1833
+ });
1834
+ // sort all inputs in ascending order by serial ID
1835
+ // The only reason we are doing this is for privacy. If the fundingInput is
1836
+ // always first, it is very obvious. Hence, a serialId is randomly generated
1837
+ // and the inputs are sorted by that instead.
1838
+ const sortedPsbtInputs = psbtInputs.sort((a, b) => Number(a.inputSerialId - b.inputSerialId));
1839
+ // Get index of fundingInput
1840
+ const fundingInputIndex = sortedPsbtInputs.findIndex((input) => input.inputSerialId === dlcClose.fundInputSerialId);
1841
+ const offerFirst = dlcOffer.payoutSerialId < dlcAccept.payoutSerialId;
1842
+ psbt.addOutput({
1843
+ value: Number(offerFirst
1844
+ ? dlcClose.offerPayoutSatoshis
1845
+ : dlcClose.acceptPayoutSatoshis),
1846
+ address: bitcoinjs_lib_1.address.fromOutputScript(offerFirst ? dlcOffer.payoutSPK : dlcAccept.payoutSPK, network),
1847
+ });
1848
+ psbt.addOutput({
1849
+ value: Number(offerFirst
1850
+ ? dlcClose.acceptPayoutSatoshis
1851
+ : dlcClose.offerPayoutSatoshis),
1852
+ address: bitcoinjs_lib_1.address.fromOutputScript(offerFirst ? dlcAccept.payoutSPK : dlcOffer.payoutSPK, network),
1853
+ });
1854
+ // add to psbt
1855
+ sortedPsbtInputs.forEach((input, i) => psbt.addInput(input));
1856
+ const offerer = await this.isOfferer(dlcOffer, dlcAccept);
1857
+ // Generate keypair to sign inputs
1858
+ const fundPrivateKeyPair = await this.GetFundKeyPair(dlcOffer, dlcAccept, offerer);
1859
+ // Sign dlc fundinginput
1860
+ psbt.signInput(fundingInputIndex, fundPrivateKeyPair);
1861
+ const partialSig = [
1862
+ {
1863
+ pubkey: offerer ? dlcAccept.fundingPubKey : dlcOffer.fundingPubKey,
1864
+ signature: await bitcoinjs_lib_1.script.signature.encode(dlcClose.closeSignature, 1), // encode using SIGHASH_ALL
1865
+ },
1866
+ ];
1867
+ psbt.updateInput(fundingInputIndex, { partialSig });
1868
+ for (let i = 0; i < psbt.data.inputs.length; ++i) {
1869
+ if (i === fundingInputIndex)
1870
+ continue;
1871
+ if (!psbt.data.inputs[i].partialSig)
1872
+ psbt.data.inputs[i].partialSig = [];
1873
+ const witnessI = dlcClose.fundingSignatures.witnessElements.findIndex((el) => Buffer.compare(bitcoin_1.Script.p2wpkhLock((0, crypto_1.hash160)(el[1].witness)).serialize().slice(1), psbt.data.inputs[i].witnessUtxo.script) === 0);
1874
+ const partialSig = [
1875
+ {
1876
+ pubkey: dlcClose.fundingSignatures.witnessElements[witnessI][1].witness,
1877
+ signature: dlcClose.fundingSignatures.witnessElements[witnessI][0].witness,
1878
+ },
1879
+ ];
1880
+ psbt.updateInput(i, { partialSig });
1881
+ }
1882
+ psbt.validateSignaturesOfAllInputs();
1883
+ psbt.finalizeAllInputs();
1884
+ return psbt.extractTransaction().toHex();
1885
+ }
1886
+ async AddSignatureToFundTransaction(jsonObject) {
1887
+ await this.CfdLoaded();
1888
+ return this._cfdDlcJs.AddSignatureToFundTransaction(jsonObject);
1889
+ }
1890
+ async CreateCetAdaptorSignature(jsonObject) {
1891
+ await this.CfdLoaded();
1892
+ return this._cfdDlcJs.CreateCetAdaptorSignature(jsonObject);
1893
+ }
1894
+ async CreateCetAdaptorSignatures(jsonObject) {
1895
+ await this.CfdLoaded();
1896
+ return this._cfdDlcJs.CreateCetAdaptorSignatures(jsonObject);
1897
+ }
1898
+ async AddSignaturesToRefundTx(jsonObject) {
1899
+ await this.CfdLoaded();
1900
+ return this._cfdDlcJs.AddSignaturesToRefundTx(jsonObject);
1901
+ }
1902
+ async CreateCet(jsonObject) {
1903
+ await this.CfdLoaded();
1904
+ return this._cfdDlcJs.CreateCet(jsonObject);
1905
+ }
1906
+ async CreateDlcTransactions(jsonObject) {
1907
+ await this.CfdLoaded();
1908
+ return this._cfdDlcJs.CreateDlcTransactions(jsonObject);
1909
+ }
1910
+ async CreateBatchDlcTransactions(jsonObject) {
1911
+ await this.CfdLoaded();
1912
+ return this._cfdDlcJs.CreateBatchDlcTransactions(jsonObject);
1913
+ }
1914
+ async CreateFundTransaction(jsonObject) {
1915
+ await this.CfdLoaded();
1916
+ return this._cfdDlcJs.CreateFundTransaction(jsonObject);
1917
+ }
1918
+ async CreateBatchFundTransaction(jsonObject) {
1919
+ await this.CfdLoaded();
1920
+ return this._cfdDlcJs.CreateBatchFundTransaction(jsonObject);
1921
+ }
1922
+ async CreateRefundTransaction(jsonObject) {
1923
+ await this.CfdLoaded();
1924
+ return this._cfdDlcJs.CreateRefundTransaction(jsonObject);
1925
+ }
1926
+ async GetRawFundTxSignature(jsonObject) {
1927
+ await this.CfdLoaded();
1928
+ return this._cfdDlcJs.GetRawFundTxSignature(jsonObject);
1929
+ }
1930
+ async GetRawRefundTxSignature(jsonObject) {
1931
+ await this.CfdLoaded();
1932
+ return this._cfdDlcJs.GetRawRefundTxSignature(jsonObject);
1933
+ }
1934
+ async SignCet(jsonObject) {
1935
+ await this.CfdLoaded();
1936
+ return this._cfdDlcJs.SignCet(jsonObject);
1937
+ }
1938
+ async VerifyCetAdaptorSignature(jsonObject) {
1939
+ await this.CfdLoaded();
1940
+ return this._cfdDlcJs.VerifyCetAdaptorSignature(jsonObject);
1941
+ }
1942
+ async VerifyCetAdaptorSignatures(jsonObject) {
1943
+ await this.CfdLoaded();
1944
+ return this._cfdDlcJs.VerifyCetAdaptorSignatures(jsonObject);
1945
+ }
1946
+ async SignFundTransaction(jsonObject) {
1947
+ await this.CfdLoaded();
1948
+ return this._cfdDlcJs.SignFundTransaction(jsonObject);
1949
+ }
1950
+ async VerifyFundTxSignature(jsonObject) {
1951
+ await this.CfdLoaded();
1952
+ return this._cfdDlcJs.VerifyFundTxSignature(jsonObject);
1953
+ }
1954
+ async VerifyRefundTxSignature(jsonObject) {
1955
+ await this.CfdLoaded();
1956
+ return this._cfdDlcJs.VerifyRefundTxSignature(jsonObject);
1957
+ }
1958
+ async fundingInputToInput(_input, findDerivationPath = true) {
1959
+ (0, assert_1.default)(_input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0');
1960
+ const network = await this.getConnectedNetwork();
1961
+ const input = _input;
1962
+ const prevTx = input.prevTx;
1963
+ const prevTxOut = prevTx.outputs[input.prevTxVout];
1964
+ const scriptPubKey = prevTxOut.scriptPubKey.serialize().slice(1);
1965
+ const _address = bitcoinjs_lib_1.address.fromOutputScript(scriptPubKey, network);
1966
+ let derivationPath;
1967
+ if (findDerivationPath) {
1968
+ const inputAddress = await this.client.wallet.findAddress([
1969
+ _address,
1970
+ ]);
1971
+ if (inputAddress) {
1972
+ derivationPath = inputAddress.derivationPath;
1973
+ }
1974
+ }
1975
+ return {
1976
+ txid: prevTx.txId.toString(),
1977
+ vout: input.prevTxVout,
1978
+ address: _address,
1979
+ amount: prevTxOut.value.bitcoin,
1980
+ value: Number(prevTxOut.value.sats),
1981
+ derivationPath,
1982
+ maxWitnessLength: input.maxWitnessLen,
1983
+ redeemScript: input.redeemScript
1984
+ ? input.redeemScript.toString('hex')
1985
+ : '',
1986
+ scriptPubKey: scriptPubKey.toString('hex'),
1987
+ inputSerialId: input.inputSerialId,
1988
+ toUtxo: types_1.Input.prototype.toUtxo,
1989
+ };
1990
+ }
1991
+ async inputToFundingInput(input) {
1992
+ const fundingInput = new messaging_1.FundingInputV0();
1993
+ fundingInput.prevTxVout = input.vout;
1994
+ let txRaw = '';
1995
+ try {
1996
+ txRaw = await this.getMethod('getRawTransactionByHash')(input.txid);
1997
+ }
1998
+ catch (e) {
1999
+ try {
2000
+ txRaw = (await this.getMethod('jsonrpc')('gettransaction', input.txid))
2001
+ .hex;
2002
+ }
2003
+ catch (e) {
2004
+ throw Error(`Cannot find tx ${input.txid} in inputToFundingInput using getrawtransactionbyhash or gettransaction`);
2005
+ }
2006
+ }
2007
+ const tx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(txRaw));
2008
+ fundingInput.prevTx = tx;
2009
+ fundingInput.sequence = bitcoin_1.Sequence.default();
2010
+ fundingInput.maxWitnessLen = input.maxWitnessLength
2011
+ ? input.maxWitnessLength
2012
+ : 108;
2013
+ fundingInput.redeemScript = input.redeemScript
2014
+ ? Buffer.from(input.redeemScript, 'hex')
2015
+ : Buffer.from('', 'hex');
2016
+ fundingInput.inputSerialId = input.inputSerialId
2017
+ ? input.inputSerialId
2018
+ : (0, Utils_1.generateSerialId)();
2019
+ return fundingInput;
2020
+ }
2021
+ async getConnectedNetwork() {
2022
+ return this._network;
2023
+ }
2024
+ }
2025
+ exports.default = BitcoinDlcProvider;
2026
+ const BurnAddress = 'bcrt1qxcjufgh2jarkp2qkx68azh08w9v5gah8u6es8s';
2027
+ //# sourceMappingURL=BitcoinDlcProvider.js.map