@atomicfinance/bitcoin-dlc-provider 3.3.1 → 3.4.0

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.
@@ -8,6 +8,10 @@ import {
8
8
  AddSignatureToFundTransactionResponse,
9
9
  bitcoin,
10
10
  CalculateEcSignatureRequest,
11
+ CreateBatchDlcTransactionsRequest,
12
+ CreateBatchDlcTransactionsResponse,
13
+ CreateBatchFundTransactionRequest,
14
+ CreateBatchFundTransactionResponse,
11
15
  CreateCetAdaptorSignatureRequest,
12
16
  CreateCetAdaptorSignatureResponse,
13
17
  CreateCetAdaptorSignaturesRequest,
@@ -104,6 +108,7 @@ import {
104
108
  asyncForEach,
105
109
  checkTypes,
106
110
  generateSerialId,
111
+ generateSerialIds,
107
112
  outputsToPayouts,
108
113
  } from './utils/Utils';
109
114
 
@@ -244,6 +249,71 @@ export default class BitcoinDlcProvider
244
249
  };
245
250
  }
246
251
 
252
+ private async BatchInitialize(
253
+ collaterals: bigint[],
254
+ feeRatePerVb: bigint,
255
+ fixedInputs: Input[],
256
+ ): Promise<BatchInitializeResponse> {
257
+ const network = await this.getConnectedNetwork();
258
+
259
+ const collateral = collaterals.reduce((a, b) => a + b, BigInt(0));
260
+
261
+ const inputs: Input[] = await this.GetInputsForAmount(
262
+ collateral,
263
+ feeRatePerVb,
264
+ fixedInputs,
265
+ );
266
+
267
+ const fundingInputs: FundingInput[] = await Promise.all(
268
+ inputs.map(async (input) => {
269
+ return this.inputToFundingInput(input);
270
+ }),
271
+ );
272
+
273
+ const initializeResponses: BatchBaseInitializeResponse[] = [];
274
+
275
+ const changeSerialId: bigint = generateSerialId();
276
+
277
+ const changeAddress: Address = await this.client.wallet.getUnusedAddress(
278
+ true,
279
+ );
280
+ const changeSPK: Buffer = address.toOutputScript(
281
+ changeAddress.address,
282
+ network,
283
+ );
284
+
285
+ for (let i = 0; i < collaterals.length; i++) {
286
+ const payoutAddress: Address = await this.client.wallet.getUnusedAddress(
287
+ false,
288
+ );
289
+ const payoutSPK: Buffer = address.toOutputScript(
290
+ payoutAddress.address,
291
+ network,
292
+ );
293
+
294
+ const fundingAddress: Address = await this.client.wallet.getUnusedAddress(
295
+ false,
296
+ );
297
+ const fundingPubKey: Buffer = Buffer.from(
298
+ fundingAddress.publicKey,
299
+ 'hex',
300
+ );
301
+
302
+ if (fundingAddress.address === payoutAddress.address)
303
+ throw Error('Address reuse');
304
+
305
+ const payoutSerialId: bigint = generateSerialId();
306
+
307
+ initializeResponses.push({
308
+ fundingPubKey,
309
+ payoutSPK,
310
+ payoutSerialId,
311
+ });
312
+ }
313
+
314
+ return { fundingInputs, initializeResponses, changeSerialId, changeSPK };
315
+ }
316
+
247
317
  /**
248
318
  * TODO: Add GetPayoutFromOutcomes
249
319
  *
@@ -563,6 +633,150 @@ export default class BitcoinDlcProvider
563
633
  return { dlcTransactions, messagesList };
564
634
  }
565
635
 
636
+ public async createBatchDlcTxs(
637
+ _dlcOffers: DlcOffer[],
638
+ _dlcAccepts: DlcAccept[],
639
+ ): Promise<CreateBatchDlcTxsResponse> {
640
+ const dlcOffers = _dlcOffers.map((dlcOffer) => {
641
+ return checkTypes({ _dlcOffer: dlcOffer }).dlcOffer;
642
+ });
643
+ const dlcAccepts = _dlcAccepts.map((dlcAccept) => {
644
+ return checkTypes({ _dlcAccept: dlcAccept }).dlcAccept;
645
+ });
646
+
647
+ const localFundPubkeys = dlcOffers.map((dlcOffer) =>
648
+ dlcOffer.fundingPubKey.toString('hex'),
649
+ );
650
+ const remoteFundPubkeys = dlcAccepts.map((dlcAccept) =>
651
+ dlcAccept.fundingPubKey.toString('hex'),
652
+ );
653
+ const localFinalScriptPubkeys = dlcOffers.map((dlcOffer) =>
654
+ dlcOffer.payoutSPK.toString('hex'),
655
+ );
656
+ const remoteFinalScriptPubkeys = dlcAccepts.map((dlcAccept) =>
657
+ dlcAccept.payoutSPK.toString('hex'),
658
+ );
659
+ const localChangeScriptPubkey = dlcOffers[0].changeSPK.toString('hex');
660
+ const remoteChangeScriptPubkey = dlcAccepts[0].changeSPK.toString('hex');
661
+
662
+ const localInputs: Utxo[] = await Promise.all(
663
+ dlcOffers[0].fundingInputs.map(async (fundingInput) => {
664
+ const input = await this.fundingInputToInput(fundingInput, false);
665
+ return input.toUtxo();
666
+ }),
667
+ );
668
+
669
+ const remoteInputs: Utxo[] = await Promise.all(
670
+ dlcAccepts[0].fundingInputs.map(async (fundingInput) => {
671
+ const input = await this.fundingInputToInput(fundingInput, false);
672
+ return input.toUtxo();
673
+ }),
674
+ );
675
+
676
+ const localInputAmount = localInputs.reduce<number>(
677
+ (prev, cur) => prev + cur.amount.GetSatoshiAmount(),
678
+ 0,
679
+ );
680
+
681
+ const remoteInputAmount = remoteInputs.reduce<number>(
682
+ (prev, cur) => prev + cur.amount.GetSatoshiAmount(),
683
+ 0,
684
+ );
685
+
686
+ const localPayouts: (bigint | number)[] = [];
687
+ const remotePayouts: (bigint | number)[] = [];
688
+ const numPayouts: (bigint | number)[] = [];
689
+
690
+ const nestedMessagesList: Messages[][] = [];
691
+
692
+ // loop through all dlc offers, get payouts, and add to localPayouts and remotePayouts
693
+ for (const dlcOffer of dlcOffers) {
694
+ const payoutResponses = this.GetPayouts(dlcOffer);
695
+ const { payouts, messagesList } = this.FlattenPayouts(payoutResponses);
696
+ const tempLocalPayouts = payouts.map((payout) => payout.local);
697
+ const tempRemotePayouts = payouts.map((payout) => payout.remote);
698
+ localPayouts.push(...tempLocalPayouts);
699
+ remotePayouts.push(...tempRemotePayouts);
700
+ numPayouts.push(tempLocalPayouts.length);
701
+ nestedMessagesList.push(messagesList);
702
+ }
703
+
704
+ const batchDlcTxRequest: CreateBatchDlcTransactionsRequest = {
705
+ localPayouts,
706
+ remotePayouts,
707
+ numPayouts,
708
+ localFundPubkeys,
709
+ localFinalScriptPubkeys,
710
+ remoteFundPubkeys,
711
+ remoteFinalScriptPubkeys,
712
+ localInputAmount,
713
+ localCollateralAmounts: dlcOffers.map(
714
+ (dlcOffer) => dlcOffer.offerCollateralSatoshis,
715
+ ),
716
+ localPayoutSerialIds: dlcOffers.map(
717
+ (dlcOffer) => dlcOffer.payoutSerialId,
718
+ ),
719
+ localChangeSerialId: dlcOffers[0].changeSerialId,
720
+ remoteInputAmount,
721
+ remoteCollateralAmounts: dlcAccepts.map(
722
+ (dlcAccept) => dlcAccept.acceptCollateralSatoshis,
723
+ ),
724
+ remotePayoutSerialIds: dlcAccepts.map(
725
+ (dlcAccept) => dlcAccept.payoutSerialId,
726
+ ),
727
+ remoteChangeSerialId: dlcAccepts[0].changeSerialId,
728
+ refundLocktimes: dlcOffers.map((dlcOffer) => dlcOffer.refundLocktime),
729
+ localInputs,
730
+ remoteInputs,
731
+ localChangeScriptPubkey,
732
+ remoteChangeScriptPubkey,
733
+ feeRate: Number(dlcOffers[0].feeRatePerVb),
734
+ cetLockTime: dlcOffers[0].cetLocktime,
735
+ fundOutputSerialIds: dlcOffers.map(
736
+ (dlcOffer) => dlcOffer.fundOutputSerialId,
737
+ ),
738
+ };
739
+
740
+ const dlcTxs = await this.CreateBatchDlcTransactions(batchDlcTxRequest);
741
+
742
+ const dlcTransactionsList: DlcTransactionsV0[] = [];
743
+
744
+ let start = 0;
745
+ for (let i = 0; i < dlcTxs.refundTxHexList.length; i++) {
746
+ const dlcTransactions = new DlcTransactionsV0();
747
+
748
+ dlcTransactions.fundTx = Tx.decode(
749
+ StreamReader.fromHex(dlcTxs.fundTxHex),
750
+ );
751
+
752
+ dlcTransactions.fundTxVout = [
753
+ BigInt(dlcOffers[i].changeSerialId),
754
+ BigInt(dlcAccepts[i].changeSerialId),
755
+ ...dlcOffers.map((dlcOffer) => dlcOffer.fundOutputSerialId),
756
+ ]
757
+ .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
758
+ .findIndex(
759
+ (j) => BigInt(j) === BigInt(dlcOffers[i].fundOutputSerialId),
760
+ );
761
+
762
+ dlcTransactions.refundTx = Tx.decode(
763
+ StreamReader.fromHex(dlcTxs.refundTxHexList[i]),
764
+ );
765
+
766
+ // slice cetsHexList based on numPayouts
767
+ const end = start + Number(numPayouts[i]);
768
+ const cetsHexList = dlcTxs.cetsHexList.slice(start, end);
769
+ start = end;
770
+ dlcTransactions.cets = cetsHexList.map((cetHex) => {
771
+ return Tx.decode(StreamReader.fromHex(cetHex));
772
+ });
773
+
774
+ dlcTransactionsList.push(dlcTransactions);
775
+ }
776
+
777
+ return { dlcTransactionsList, nestedMessagesList };
778
+ }
779
+
566
780
  private GenerateEnumMessages(oracleEvent: OracleEventV0): Messages[] {
567
781
  throw Error('Only DigitDecomposition Oracle Events supported');
568
782
  }
@@ -1873,6 +2087,109 @@ Payout Group found but incorrect group index',
1873
2087
  return dlcOffer;
1874
2088
  }
1875
2089
 
2090
+ async batchCreateDlcOffer(
2091
+ contractInfos: ContractInfo[],
2092
+ offerCollaterals: bigint[],
2093
+ feeRatePerVb: bigint,
2094
+ cetLocktime: number,
2095
+ refundLocktimes: number[],
2096
+ fixedInputs?: Input[],
2097
+ ): Promise<DlcOffer[]> {
2098
+ if (
2099
+ contractInfos.length !== offerCollaterals.length ||
2100
+ contractInfos.length !== refundLocktimes.length
2101
+ ) {
2102
+ throw new Error(
2103
+ 'The number of contractInfos, offerCollateralSatoshis, and refundLocktimes must be the same',
2104
+ );
2105
+ }
2106
+
2107
+ const dlcOffers: DlcOfferV0[] = [];
2108
+
2109
+ for (let i = 0; i < contractInfos.length; i++) {
2110
+ contractInfos[i].validate();
2111
+ }
2112
+
2113
+ const network = await this.getConnectedNetwork();
2114
+
2115
+ const {
2116
+ fundingInputs: _fundingInputs,
2117
+ changeSPK,
2118
+ changeSerialId,
2119
+ initializeResponses,
2120
+ } = await this.BatchInitialize(offerCollaterals, feeRatePerVb, fixedInputs);
2121
+
2122
+ _fundingInputs.forEach((input) =>
2123
+ assert(
2124
+ input.type === MessageType.FundingInputV0,
2125
+ 'FundingInput must be V0',
2126
+ ),
2127
+ );
2128
+
2129
+ const fundingInputs: FundingInputV0[] = _fundingInputs.map(
2130
+ (input) => input as FundingInputV0,
2131
+ );
2132
+
2133
+ fundingInputs.sort(
2134
+ (a, b) => Number(a.inputSerialId) - Number(b.inputSerialId),
2135
+ );
2136
+
2137
+ const fundOutputsSerialIds = generateSerialIds(contractInfos.length);
2138
+
2139
+ for (let i = 0; i < contractInfos.length; i++) {
2140
+ const contractInfo = contractInfos[i];
2141
+ const offerCollateralSatoshis = offerCollaterals[i];
2142
+ const fundOutputSerialId = fundOutputsSerialIds[i];
2143
+ const { fundingPubKey, payoutSPK, payoutSerialId } = initializeResponses[
2144
+ i
2145
+ ];
2146
+ const refundLocktime = refundLocktimes[i];
2147
+
2148
+ const dlcOffer = new DlcOfferV0();
2149
+
2150
+ dlcOffer.contractFlags = Buffer.from('00', 'hex');
2151
+ dlcOffer.chainHash = chainHashFromNetwork(network);
2152
+ dlcOffer.contractInfo = contractInfo;
2153
+ dlcOffer.fundingPubKey = fundingPubKey;
2154
+ dlcOffer.payoutSPK = payoutSPK;
2155
+ dlcOffer.payoutSerialId = payoutSerialId;
2156
+ dlcOffer.offerCollateralSatoshis = offerCollateralSatoshis;
2157
+ dlcOffer.fundingInputs = fundingInputs;
2158
+ dlcOffer.changeSPK = changeSPK;
2159
+ dlcOffer.changeSerialId = changeSerialId;
2160
+ dlcOffer.fundOutputSerialId = fundOutputSerialId;
2161
+ dlcOffer.feeRatePerVb = feeRatePerVb;
2162
+ dlcOffer.cetLocktime = cetLocktime;
2163
+ dlcOffer.refundLocktime = refundLocktime;
2164
+
2165
+ assert(
2166
+ (() => {
2167
+ const finalizer = new DualFundingTxFinalizer(
2168
+ dlcOffer.fundingInputs,
2169
+ dlcOffer.payoutSPK,
2170
+ dlcOffer.changeSPK,
2171
+ null,
2172
+ null,
2173
+ null,
2174
+ dlcOffer.feeRatePerVb,
2175
+ );
2176
+ const funding = fundingInputs.reduce((total, input) => {
2177
+ return total + input.prevTx.outputs[input.prevTxVout].value.sats;
2178
+ }, BigInt(0));
2179
+
2180
+ return funding >= offerCollateralSatoshis + finalizer.offerFees;
2181
+ })(),
2182
+ 'fundingInputs for dlcOffer must be greater than offerCollateralSatoshis plus offerFees',
2183
+ );
2184
+
2185
+ dlcOffer.validate();
2186
+
2187
+ dlcOffers.push(dlcOffer);
2188
+ }
2189
+
2190
+ return dlcOffers;
2191
+ }
2192
+
1876
2193
  /**
1877
2194
  * Accept DLC Offer
1878
2195
  * @param _dlcOffer Dlc Offer Message
@@ -2019,6 +2336,168 @@ Payout Group found but incorrect group index',
2019
2336
  return { dlcAccept, dlcTransactions: _dlcTransactions };
2020
2337
  }
2021
2338
 
2339
+ async batchAcceptDlcOffer(
2340
+ _dlcOffers: DlcOffer[],
2341
+ fixedInputs?: Input[],
2342
+ ): Promise<BatchAcceptDlcOfferResponse> {
2343
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
2344
+ const { dlcOffer } = checkTypes({ _dlcOffer });
2345
+ dlcOffer.validate();
2346
+ return dlcOffer;
2347
+ });
2348
+
2349
+ const acceptCollaterals = dlcOffers.map(
2350
+ (dlcOffer) =>
2351
+ dlcOffer.contractInfo.totalCollateral -
2352
+ dlcOffer.offerCollateralSatoshis,
2353
+ );
2354
+
2355
+ const {
2356
+ fundingInputs: _fundingInputs,
2357
+ changeSPK,
2358
+ changeSerialId,
2359
+ initializeResponses,
2360
+ } = await this.BatchInitialize(
2361
+ acceptCollaterals,
2362
+ dlcOffers[0].feeRatePerVb,
2363
+ fixedInputs,
2364
+ );
2365
+
2366
+ // Check that none of the funding pubkeys are the same between the
2367
+ // dlcOffers and the dlcAccepts (from initializeResponses)
2368
+ dlcOffers.forEach((dlcOffer) => {
2369
+ initializeResponses.forEach((initializeResponse) => {
2370
+ assert(
2371
+ Buffer.compare(
2372
+ dlcOffer.fundingPubKey,
2373
+ initializeResponse.fundingPubKey,
2374
+ ) !== 0,
2375
+ 'DlcOffer and DlcAccept FundingPubKey cannot be the same',
2376
+ );
2377
+ });
2378
+ });
2379
+
2380
+ _fundingInputs.forEach((input) =>
2381
+ assert(
2382
+ input.type === MessageType.FundingInputV0,
2383
+ 'FundingInput must be V0',
2384
+ ),
2385
+ );
2386
+
2387
+ const fundingInputs: FundingInputV0[] = _fundingInputs.map(
2388
+ (input) => input as FundingInputV0,
2389
+ );
2390
+
2391
+ fundingInputs.sort(
2392
+ (a, b) => Number(a.inputSerialId) - Number(b.inputSerialId),
2393
+ );
2394
+
2395
+ const dlcAccepts: DlcAcceptV0[] = [];
2396
+
2397
+ initializeResponses.forEach((initializeResponse, i) => {
2398
+ const dlcOffer = dlcOffers[i];
2399
+ const dlcAccept = new DlcAcceptV0();
2400
+
2401
+ const { fundingPubKey, payoutSPK, payoutSerialId } = initializeResponse;
2402
+
2403
+ dlcAccept.tempContractId = sha256(dlcOffers[i].serialize());
2404
+ dlcAccept.acceptCollateralSatoshis = acceptCollaterals[i];
2405
+ dlcAccept.fundingPubKey = fundingPubKey;
2406
+ dlcAccept.payoutSPK = payoutSPK;
2407
+ dlcAccept.payoutSerialId = payoutSerialId;
2408
+ dlcAccept.fundingInputs = fundingInputs;
2409
+ dlcAccept.changeSPK = changeSPK;
2410
+ dlcAccept.changeSerialId = changeSerialId;
2411
+
2412
+ assert(
2413
+ dlcAccept.changeSerialId !== dlcOffer.fundOutputSerialId,
2414
+ 'changeSerialId cannot equal the fundOutputSerialId',
2415
+ );
2416
+
2417
+ assert(
2418
+ dlcOffer.payoutSerialId !== dlcAccept.payoutSerialId,
2419
+ 'offer.payoutSerialId cannot equal accept.payoutSerialId',
2420
+ );
2421
+
2422
+ assert(
2423
+ (() => {
2424
+ const ids = [
2425
+ dlcOffer.changeSerialId,
2426
+ dlcAccept.changeSerialId,
2427
+ dlcOffer.fundOutputSerialId,
2428
+ ];
2429
+ return new Set(ids).size === ids.length;
2430
+ })(),
2431
+ 'offer.changeSerialID, accept.changeSerialId and fundOutputSerialId must be unique',
2432
+ );
2433
+
2434
+ dlcAccept.validate();
2435
+
2436
+ assert(
2437
+ (() => {
2438
+ const finalizer = new DualFundingTxFinalizer(
2439
+ dlcOffer.fundingInputs,
2440
+ dlcOffer.payoutSPK,
2441
+ dlcOffer.changeSPK,
2442
+ dlcAccept.fundingInputs,
2443
+ dlcAccept.payoutSPK,
2444
+ dlcAccept.changeSPK,
2445
+ dlcOffer.feeRatePerVb,
2446
+ );
2447
+ const funding = fundingInputs.reduce((total, input) => {
2448
+ return total + input.prevTx.outputs[input.prevTxVout].value.sats;
2449
+ }, BigInt(0));
2450
+
2451
+ return funding >= acceptCollaterals[i] + finalizer.acceptFees;
2452
+ })(),
2453
+ 'fundingInputs for dlcAccept must be greater than acceptCollateralSatoshis plus acceptFees',
2454
+ );
2455
+
2456
+ dlcAccepts.push(dlcAccept);
2457
+ });
2458
+
2459
+ const {
2460
+ dlcTransactionsList,
2461
+ nestedMessagesList,
2462
+ } = await this.createBatchDlcTxs(dlcOffers, dlcAccepts);
2463
+
2464
+ for (let i = 0; i < dlcAccepts.length; i++) {
2465
+ const dlcOffer = dlcOffers[i];
2466
+ const dlcAccept = dlcAccepts[i];
2467
+ const dlcTransactions = dlcTransactionsList[i];
2468
+ const messagesList = nestedMessagesList[i];
2469
+
2470
+ const {
2471
+ cetSignatures,
2472
+ refundSignature,
2473
+ } = await this.CreateCetAdaptorAndRefundSigs(
2474
+ dlcOffer,
2475
+ dlcAccept,
2476
+ dlcTransactions,
2477
+ messagesList,
2478
+ false,
2479
+ );
2480
+
2481
+ assert(
2482
+ dlcTransactions.type === MessageType.DlcTransactionsV0,
2483
+ 'DlcTransactions must be V0',
2484
+ );
2485
+ const _dlcTransactions = dlcTransactions as DlcTransactionsV0;
2486
+
2487
+ const contractId = xor(
2488
+ _dlcTransactions.fundTx.txId.serialize(),
2489
+ dlcAccept.tempContractId,
2490
+ );
2491
+ _dlcTransactions.contractId = contractId;
2492
+
2493
+ dlcAccepts[i].cetSignatures = cetSignatures;
2494
+ dlcAccepts[i].refundSignature = refundSignature;
2495
+ dlcAccepts[i].negotiationFields = new NegotiationFieldsV0();
2496
+ }
2497
+
2498
+ return { dlcAccepts, dlcTransactionsList };
2499
+ }
2500
+
2022
2501
  /**
2023
2502
  * Sign Dlc Accept Message
2024
2503
  * @param _dlcOffer Dlc Offer Message
@@ -2100,6 +2579,84 @@ Payout Group found but incorrect group index',
2100
2579
  return { dlcSign, dlcTransactions: dlcTxs };
2101
2580
  }
2102
2581
 
2582
+ async batchSignDlcAccept(
2583
+ _dlcOffers: DlcOffer[],
2584
+ _dlcAccepts: DlcAccept[],
2585
+ ): Promise<BatchSignDlcAcceptResponse> {
2586
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
2587
+ const { dlcOffer } = checkTypes({ _dlcOffer });
2588
+ dlcOffer.validate();
2589
+ return dlcOffer;
2590
+ });
2591
+
2592
+ const dlcAccepts = _dlcAccepts.map((_dlcAccept) => {
2593
+ const { dlcAccept } = checkTypes({ _dlcAccept });
2594
+ dlcAccept.validate();
2595
+ return dlcAccept;
2596
+ });
2597
+
2598
+ const {
2599
+ dlcTransactionsList,
2600
+ nestedMessagesList,
2601
+ } = await this.createBatchDlcTxs(dlcOffers, dlcAccepts);
2602
+
2603
+ const dlcSigns: DlcSignV0[] = [];
2604
+
2605
+ const fundingSignatures = await this.CreateFundingSigs(
2606
+ dlcOffers[0],
2607
+ dlcAccepts[0],
2608
+ dlcTransactionsList[0],
2609
+ true,
2610
+ );
2611
+
2612
+ for (let i = 0; i < dlcAccepts.length; i++) {
2613
+ const dlcOffer = dlcOffers[i];
2614
+ const dlcAccept = dlcAccepts[i];
2615
+ const dlcTransactions = dlcTransactionsList[i];
2616
+ const messagesList = nestedMessagesList[i];
2617
+
2618
+ const dlcSign = new DlcSignV0();
2619
+
2620
+ await this.VerifyCetAdaptorAndRefundSigs(
2621
+ dlcOffer,
2622
+ dlcAccept,
2623
+ dlcSign,
2624
+ dlcTransactions,
2625
+ messagesList,
2626
+ true,
2627
+ );
2628
+
2629
+ const {
2630
+ cetSignatures,
2631
+ refundSignature,
2632
+ } = await this.CreateCetAdaptorAndRefundSigs(
2633
+ dlcOffer,
2634
+ dlcAccept,
2635
+ dlcTransactions,
2636
+ messagesList,
2637
+ true,
2638
+ );
2639
+
2640
+ const dlcTxs = dlcTransactions as DlcTransactionsV0;
2641
+
2642
+ const contractId = xor(
2643
+ dlcTxs.fundTx.txId.serialize(),
2644
+ dlcAccept.tempContractId,
2645
+ );
2646
+
2647
+ dlcTxs.contractId = contractId;
2648
+
2649
+ dlcSign.contractId = contractId;
2650
+ dlcSign.cetSignatures = cetSignatures;
2651
+ dlcSign.refundSignature = refundSignature;
2652
+ dlcSign.fundingSignatures = fundingSignatures;
2653
+
2654
+ dlcSigns.push(dlcSign);
2655
+ }
2656
+
2657
+ return { dlcSigns, dlcTransactionsList };
2658
+ }
2659
+
2103
2660
  /**
2104
2661
  * Finalize Dlc Sign
2105
2662
  * @param _dlcOffer Dlc Offer Message
@@ -2153,6 +2710,79 @@ Payout Group found but incorrect group index',
2153
2710
  return fundTx;
2154
2711
  }
2155
2712
 
2713
+ async batchFinalizeDlcSign(
2714
+ _dlcOffers: DlcOffer[],
2715
+ _dlcAccepts: DlcAccept[],
2716
+ _dlcSigns: DlcSign[],
2717
+ _dlcTxsList: DlcTransactions[],
2718
+ ): Promise<Tx> {
2719
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
2720
+ const { dlcOffer } = checkTypes({ _dlcOffer });
2721
+ dlcOffer.validate();
2722
+ return dlcOffer;
2723
+ });
2724
+
2725
+ const dlcAccepts = _dlcAccepts.map((_dlcAccept) => {
2726
+ const { dlcAccept } = checkTypes({ _dlcAccept });
2727
+ dlcAccept.validate();
2728
+ return dlcAccept;
2729
+ });
2730
+
2731
+ const dlcSigns = _dlcSigns.map((_dlcSign) => {
2732
+ const { dlcSign } = checkTypes({ _dlcSign });
2733
+ return dlcSign;
2734
+ });
2735
+
2736
+ const dlcTxsList = _dlcTxsList.map((_dlcTxs) => {
2737
+ const { dlcTxs } = checkTypes({ _dlcTxs });
2738
+ return dlcTxs;
2739
+ });
2740
+
2741
+ await this.VerifyFundingSigs(
2742
+ dlcOffers[0],
2743
+ dlcAccepts[0],
2744
+ dlcSigns[0],
2745
+ dlcTxsList[0],
2746
+ false,
2747
+ );
2748
+
2749
+ for (let i = 0; i < dlcOffers.length; i++) {
2750
+ const dlcOffer = dlcOffers[i];
2751
+ const dlcAccept = dlcAccepts[i];
2752
+ const dlcSign = dlcSigns[i];
2753
+ const dlcTxs = dlcTxsList[i];
2754
+
2755
+ const payoutResponses = this.GetPayouts(dlcOffer);
2756
+ const { messagesList } = this.FlattenPayouts(payoutResponses);
2757
+
2758
+ await this.VerifyCetAdaptorAndRefundSigs(
2759
+ dlcOffer,
2760
+ dlcAccept,
2761
+ dlcSign,
2762
+ dlcTxs,
2763
+ messagesList,
2764
+ false,
2765
+ );
2766
+ }
2767
+
2768
+ const fundingSignatures = await this.CreateFundingSigs(
2769
+ dlcOffers[0],
2770
+ dlcAccepts[0],
2771
+ dlcTxsList[0],
2772
+ false,
2773
+ );
2774
+
2775
+ const fundTx = await this.CreateFundingTx(
2776
+ dlcOffers[0],
2777
+ dlcAccepts[0],
2778
+ dlcSigns[0],
2779
+ dlcTxsList[0],
2780
+ fundingSignatures,
2781
+ );
2782
+
2783
+ return fundTx;
2784
+ }
2785
+
2156
2786
  /**
2157
2787
  * Execute DLC
2158
2788
  * @param _dlcOffer Dlc Offer Message
@@ -2890,6 +3520,14 @@ Payout Group found but incorrect group index',
2890
3520
  return this._cfdDlcJs.CreateDlcTransactions(jsonObject);
2891
3521
  }
2892
3522
 
3523
+ async CreateBatchDlcTransactions(
3524
+ jsonObject: CreateBatchDlcTransactionsRequest,
3525
+ ): Promise<CreateBatchDlcTransactionsResponse> {
3526
+ await this.CfdLoaded();
3527
+
3528
+ return this._cfdDlcJs.CreateBatchDlcTransactions(jsonObject);
3529
+ }
3530
+
2893
3531
  async CreateFundTransaction(
2894
3532
  jsonObject: CreateFundTransactionRequest,
2895
3533
  ): Promise<CreateFundTransactionResponse> {
@@ -2898,6 +3536,14 @@ Payout Group found but incorrect group index',
2898
3536
  return this._cfdDlcJs.CreateFundTransaction(jsonObject);
2899
3537
  }
2900
3538
 
3539
+ async CreateBatchFundTransaction(
3540
+ jsonObject: CreateBatchFundTransactionRequest,
3541
+ ): Promise<CreateBatchFundTransactionResponse> {
3542
+ await this.CfdLoaded();
3543
+
3544
+ return this._cfdDlcJs.CreateBatchFundTransaction(jsonObject);
3545
+ }
3546
+
2901
3547
  async CreateRefundTransaction(
2902
3548
  jsonObject: CreateRefundTransactionRequest,
2903
3549
  ): Promise<CreateRefundTransactionResponse> {
@@ -3050,10 +3696,26 @@ Payout Group found but incorrect group index',
3050
3696
  }
3051
3697
  }
3052
3698
 
3053
- export interface InitializeResponse {
3699
+ export interface BasicInitializeResponse {
3054
3700
  fundingPubKey: Buffer;
3055
3701
  payoutSPK: Buffer;
3056
3702
  payoutSerialId: bigint;
3703
+ changeSPK: Buffer;
3704
+ changeSerialId: bigint;
3705
+ }
3706
+
3707
+ export interface InitializeResponse extends BasicInitializeResponse {
3708
+ fundingInputs: FundingInput[];
3709
+ }
3710
+
3711
+ export interface BatchBaseInitializeResponse {
3712
+ fundingPubKey: Buffer;
3713
+ payoutSPK: Buffer;
3714
+ payoutSerialId: bigint;
3715
+ }
3716
+
3717
+ export interface BatchInitializeResponse {
3718
+ initializeResponses: BatchBaseInitializeResponse[];
3057
3719
  fundingInputs: FundingInput[];
3058
3720
  changeSPK: Buffer;
3059
3721
  changeSerialId: bigint;
@@ -3064,11 +3726,21 @@ export interface AcceptDlcOfferResponse {
3064
3726
  dlcTransactions: DlcTransactions;
3065
3727
  }
3066
3728
 
3729
+ export interface BatchAcceptDlcOfferResponse {
3730
+ dlcAccepts: DlcAccept[];
3731
+ dlcTransactionsList: DlcTransactions[];
3732
+ }
3733
+
3067
3734
  export interface SignDlcAcceptResponse {
3068
3735
  dlcSign: DlcSign;
3069
3736
  dlcTransactions: DlcTransactions;
3070
3737
  }
3071
3738
 
3739
+ export interface BatchSignDlcAcceptResponse {
3740
+ dlcSigns: DlcSign[];
3741
+ dlcTransactionsList: DlcTransactions[];
3742
+ }
3743
+
3072
3744
  export interface GetPayoutsResponse {
3073
3745
  payouts: PayoutRequest[];
3074
3746
  payoutGroups: PayoutGroup[];
@@ -3080,6 +3752,11 @@ export interface CreateDlcTxsResponse {
3080
3752
  messagesList: Messages[];
3081
3753
  }
3082
3754
 
3755
+ export interface CreateBatchDlcTxsResponse {
3756
+ dlcTransactionsList: DlcTransactions[];
3757
+ nestedMessagesList: Messages[][];
3758
+ }
3759
+
3083
3760
  interface ISig {
3084
3761
  encryptedSig: Buffer;
3085
3762
  dleqProof: Buffer;