@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.
@@ -1 +1 @@
1
- @atomicfinance/bitcoin-dlc-provider:build: cache hit, replaying output f3c6e566b0f95482
1
+ @atomicfinance/bitcoin-dlc-provider:build: cache hit, replaying output 871769c390794d48
@@ -1 +1 @@
1
- @atomicfinance/bitcoin-dlc-provider:test: cache hit, replaying output b833939fe3e7bc96
1
+ @atomicfinance/bitcoin-dlc-provider:test: cache hit, replaying output 31067a0dabb09d92
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atomicfinance/bitcoin-dlc-provider
2
2
 
3
+ ## 3.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 314d7d7: Add batch dlc funding transactions
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [314d7d7]
12
+ - @atomicfinance/types@3.4.0
13
+ - @atomicfinance/bitcoin-utils@3.4.0
14
+ - @atomicfinance/provider@3.4.0
15
+ - @atomicfinance/utils@3.4.0
16
+
3
17
  ## 3.3.1
4
18
 
5
19
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import Provider from '@atomicfinance/provider';
3
- import { AddSignaturesToRefundTxRequest, AddSignaturesToRefundTxResponse, AddSignatureToFundTransactionRequest, AddSignatureToFundTransactionResponse, CreateCetAdaptorSignatureRequest, CreateCetAdaptorSignatureResponse, CreateCetAdaptorSignaturesRequest, CreateCetAdaptorSignaturesResponse, CreateCetRequest, CreateCetResponse, CreateDlcTransactionsRequest, CreateDlcTransactionsResponse, CreateFundTransactionRequest, CreateFundTransactionResponse, CreateRefundTransactionRequest, CreateRefundTransactionResponse, DlcProvider, GetRawFundTxSignatureRequest, GetRawFundTxSignatureResponse, GetRawRefundTxSignatureRequest, GetRawRefundTxSignatureResponse, Input, Messages, PayoutRequest, SignCetRequest, SignCetResponse, SignFundTransactionRequest, SignFundTransactionResponse, VerifyCetAdaptorSignatureRequest, VerifyCetAdaptorSignatureResponse, VerifyCetAdaptorSignaturesRequest, VerifyCetAdaptorSignaturesResponse, VerifyFundTxSignatureRequest, VerifyFundTxSignatureResponse, VerifyRefundTxSignatureRequest, VerifyRefundTxSignatureResponse } from '@atomicfinance/types';
3
+ import { AddSignaturesToRefundTxRequest, AddSignaturesToRefundTxResponse, AddSignatureToFundTransactionRequest, AddSignatureToFundTransactionResponse, CreateBatchDlcTransactionsRequest, CreateBatchDlcTransactionsResponse, CreateBatchFundTransactionRequest, CreateBatchFundTransactionResponse, CreateCetAdaptorSignatureRequest, CreateCetAdaptorSignatureResponse, CreateCetAdaptorSignaturesRequest, CreateCetAdaptorSignaturesResponse, CreateCetRequest, CreateCetResponse, CreateDlcTransactionsRequest, CreateDlcTransactionsResponse, CreateFundTransactionRequest, CreateFundTransactionResponse, CreateRefundTransactionRequest, CreateRefundTransactionResponse, DlcProvider, GetRawFundTxSignatureRequest, GetRawFundTxSignatureResponse, GetRawRefundTxSignatureRequest, GetRawRefundTxSignatureResponse, Input, Messages, PayoutRequest, SignCetRequest, SignCetResponse, SignFundTransactionRequest, SignFundTransactionResponse, VerifyCetAdaptorSignatureRequest, VerifyCetAdaptorSignatureResponse, VerifyCetAdaptorSignaturesRequest, VerifyCetAdaptorSignaturesResponse, VerifyFundTxSignatureRequest, VerifyFundTxSignatureResponse, VerifyRefundTxSignatureRequest, VerifyRefundTxSignatureResponse } from '@atomicfinance/types';
4
4
  import { CetAdaptorSignaturesV0, ContractDescriptorV1, ContractInfo, DlcAccept, DlcClose, DlcCloseMetadata, DlcOffer, DlcSign, DlcTransactions, FundingInput, HyperbolaPayoutCurvePiece, OracleAttestationV0, PolynomialPayoutCurvePiece } from '@node-dlc/messaging';
5
5
  import { Tx } from '@node-lightning/bitcoin';
6
6
  import { BitcoinNetwork } from 'bitcoin-networks';
@@ -13,6 +13,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
13
13
  GetCfdNetwork(): Promise<string>;
14
14
  GetInputsForAmount(amount: bigint, feeRatePerVb: bigint, fixedInputs?: Input[]): Promise<Input[]>;
15
15
  private Initialize;
16
+ private BatchInitialize;
16
17
  /**
17
18
  * TODO: Add GetPayoutFromOutcomes
18
19
  *
@@ -28,6 +29,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
28
29
  private GetIndicesFromPayouts;
29
30
  private GetPayoutsFromContractDescriptor;
30
31
  createDlcTxs(_dlcOffer: DlcOffer, _dlcAccept: DlcAccept): Promise<CreateDlcTxsResponse>;
32
+ createBatchDlcTxs(_dlcOffers: DlcOffer[], _dlcAccepts: DlcAccept[]): Promise<CreateBatchDlcTxsResponse>;
31
33
  private GenerateEnumMessages;
32
34
  private GenerateDigitDecompositionMessages;
33
35
  private GenerateMessages;
@@ -66,6 +68,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
66
68
  * @returns {Promise<DlcOffer>}
67
69
  */
68
70
  createDlcOffer(contractInfo: ContractInfo, offerCollateralSatoshis: bigint, feeRatePerVb: bigint, cetLocktime: number, refundLocktime: number, fixedInputs?: Input[]): Promise<DlcOffer>;
71
+ batchCreateDlcOffer(contractInfos: ContractInfo[], offerCollaterals: bigint[], feeRatePerVb: bigint, cetLocktime: number, refundLocktimes: number[], fixedInputs?: Input[]): Promise<DlcOffer[]>;
69
72
  /**
70
73
  * Accept DLC Offer
71
74
  * @param _dlcOffer Dlc Offer Message
@@ -73,6 +76,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
73
76
  * @returns {Promise<AcceptDlcOfferResponse}
74
77
  */
75
78
  acceptDlcOffer(_dlcOffer: DlcOffer, fixedInputs?: Input[]): Promise<AcceptDlcOfferResponse>;
79
+ batchAcceptDlcOffer(_dlcOffers: DlcOffer[], fixedInputs?: Input[]): Promise<BatchAcceptDlcOfferResponse>;
76
80
  /**
77
81
  * Sign Dlc Accept Message
78
82
  * @param _dlcOffer Dlc Offer Message
@@ -80,6 +84,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
80
84
  * @returns {Promise<SignDlcAcceptResponse}
81
85
  */
82
86
  signDlcAccept(_dlcOffer: DlcOffer, _dlcAccept: DlcAccept): Promise<SignDlcAcceptResponse>;
87
+ batchSignDlcAccept(_dlcOffers: DlcOffer[], _dlcAccepts: DlcAccept[]): Promise<BatchSignDlcAcceptResponse>;
83
88
  /**
84
89
  * Finalize Dlc Sign
85
90
  * @param _dlcOffer Dlc Offer Message
@@ -89,6 +94,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
89
94
  * @returns {Promise<Tx>}
90
95
  */
91
96
  finalizeDlcSign(_dlcOffer: DlcOffer, _dlcAccept: DlcAccept, _dlcSign: DlcSign, _dlcTxs: DlcTransactions): Promise<Tx>;
97
+ batchFinalizeDlcSign(_dlcOffers: DlcOffer[], _dlcAccepts: DlcAccept[], _dlcSigns: DlcSign[], _dlcTxsList: DlcTransactions[]): Promise<Tx>;
92
98
  /**
93
99
  * Execute DLC
94
100
  * @param _dlcOffer Dlc Offer Message
@@ -170,7 +176,9 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
170
176
  AddSignaturesToRefundTx(jsonObject: AddSignaturesToRefundTxRequest): Promise<AddSignaturesToRefundTxResponse>;
171
177
  CreateCet(jsonObject: CreateCetRequest): Promise<CreateCetResponse>;
172
178
  CreateDlcTransactions(jsonObject: CreateDlcTransactionsRequest): Promise<CreateDlcTransactionsResponse>;
179
+ CreateBatchDlcTransactions(jsonObject: CreateBatchDlcTransactionsRequest): Promise<CreateBatchDlcTransactionsResponse>;
173
180
  CreateFundTransaction(jsonObject: CreateFundTransactionRequest): Promise<CreateFundTransactionResponse>;
181
+ CreateBatchFundTransaction(jsonObject: CreateBatchFundTransactionRequest): Promise<CreateBatchFundTransactionResponse>;
174
182
  CreateRefundTransaction(jsonObject: CreateRefundTransactionRequest): Promise<CreateRefundTransactionResponse>;
175
183
  GetRawFundTxSignature(jsonObject: GetRawFundTxSignatureRequest): Promise<GetRawFundTxSignatureResponse>;
176
184
  GetRawRefundTxSignature(jsonObject: GetRawRefundTxSignatureRequest): Promise<GetRawRefundTxSignatureResponse>;
@@ -184,10 +192,23 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
184
192
  inputToFundingInput(input: Input): Promise<FundingInput>;
185
193
  getConnectedNetwork(): Promise<BitcoinNetwork>;
186
194
  }
187
- export interface InitializeResponse {
195
+ export interface BasicInitializeResponse {
188
196
  fundingPubKey: Buffer;
189
197
  payoutSPK: Buffer;
190
198
  payoutSerialId: bigint;
199
+ changeSPK: Buffer;
200
+ changeSerialId: bigint;
201
+ }
202
+ export interface InitializeResponse extends BasicInitializeResponse {
203
+ fundingInputs: FundingInput[];
204
+ }
205
+ export interface BatchBaseInitializeResponse {
206
+ fundingPubKey: Buffer;
207
+ payoutSPK: Buffer;
208
+ payoutSerialId: bigint;
209
+ }
210
+ export interface BatchInitializeResponse {
211
+ initializeResponses: BatchBaseInitializeResponse[];
191
212
  fundingInputs: FundingInput[];
192
213
  changeSPK: Buffer;
193
214
  changeSerialId: bigint;
@@ -196,10 +217,18 @@ export interface AcceptDlcOfferResponse {
196
217
  dlcAccept: DlcAccept;
197
218
  dlcTransactions: DlcTransactions;
198
219
  }
220
+ export interface BatchAcceptDlcOfferResponse {
221
+ dlcAccepts: DlcAccept[];
222
+ dlcTransactionsList: DlcTransactions[];
223
+ }
199
224
  export interface SignDlcAcceptResponse {
200
225
  dlcSign: DlcSign;
201
226
  dlcTransactions: DlcTransactions;
202
227
  }
228
+ export interface BatchSignDlcAcceptResponse {
229
+ dlcSigns: DlcSign[];
230
+ dlcTransactionsList: DlcTransactions[];
231
+ }
203
232
  export interface GetPayoutsResponse {
204
233
  payouts: PayoutRequest[];
205
234
  payoutGroups: PayoutGroup[];
@@ -209,6 +238,10 @@ export interface CreateDlcTxsResponse {
209
238
  dlcTransactions: DlcTransactions;
210
239
  messagesList: Messages[];
211
240
  }
241
+ export interface CreateBatchDlcTxsResponse {
242
+ dlcTransactionsList: DlcTransactions[];
243
+ nestedMessagesList: Messages[][];
244
+ }
212
245
  export interface CreateCetAdaptorAndRefundSigsResponse {
213
246
  cetSignatures: CetAdaptorSignaturesV0;
214
247
  refundSignature: Buffer;
@@ -102,6 +102,33 @@ class BitcoinDlcProvider extends provider_1.default {
102
102
  changeSerialId,
103
103
  };
104
104
  }
105
+ async BatchInitialize(collaterals, feeRatePerVb, fixedInputs) {
106
+ const network = await this.getConnectedNetwork();
107
+ const collateral = collaterals.reduce((a, b) => a + b, BigInt(0));
108
+ const inputs = await this.GetInputsForAmount(collateral, feeRatePerVb, fixedInputs);
109
+ const fundingInputs = await Promise.all(inputs.map(async (input) => {
110
+ return this.inputToFundingInput(input);
111
+ }));
112
+ const initializeResponses = [];
113
+ const changeSerialId = Utils_1.generateSerialId();
114
+ const changeAddress = await this.client.wallet.getUnusedAddress(true);
115
+ const changeSPK = bitcoinjs_lib_1.address.toOutputScript(changeAddress.address, network);
116
+ for (let i = 0; i < collaterals.length; i++) {
117
+ const payoutAddress = await this.client.wallet.getUnusedAddress(false);
118
+ const payoutSPK = bitcoinjs_lib_1.address.toOutputScript(payoutAddress.address, network);
119
+ const fundingAddress = await this.client.wallet.getUnusedAddress(false);
120
+ const fundingPubKey = Buffer.from(fundingAddress.publicKey, 'hex');
121
+ if (fundingAddress.address === payoutAddress.address)
122
+ throw Error('Address reuse');
123
+ const payoutSerialId = Utils_1.generateSerialId();
124
+ initializeResponses.push({
125
+ fundingPubKey,
126
+ payoutSPK,
127
+ payoutSerialId,
128
+ });
129
+ }
130
+ return { fundingInputs, initializeResponses, changeSerialId, changeSPK };
131
+ }
105
132
  /**
106
133
  * TODO: Add GetPayoutFromOutcomes
107
134
  *
@@ -290,6 +317,94 @@ class BitcoinDlcProvider extends provider_1.default {
290
317
  });
291
318
  return { dlcTransactions, messagesList };
292
319
  }
320
+ async createBatchDlcTxs(_dlcOffers, _dlcAccepts) {
321
+ const dlcOffers = _dlcOffers.map((dlcOffer) => {
322
+ return Utils_1.checkTypes({ _dlcOffer: dlcOffer }).dlcOffer;
323
+ });
324
+ const dlcAccepts = _dlcAccepts.map((dlcAccept) => {
325
+ return Utils_1.checkTypes({ _dlcAccept: dlcAccept }).dlcAccept;
326
+ });
327
+ const localFundPubkeys = dlcOffers.map((dlcOffer) => dlcOffer.fundingPubKey.toString('hex'));
328
+ const remoteFundPubkeys = dlcAccepts.map((dlcAccept) => dlcAccept.fundingPubKey.toString('hex'));
329
+ const localFinalScriptPubkeys = dlcOffers.map((dlcOffer) => dlcOffer.payoutSPK.toString('hex'));
330
+ const remoteFinalScriptPubkeys = dlcAccepts.map((dlcAccept) => dlcAccept.payoutSPK.toString('hex'));
331
+ const localChangeScriptPubkey = dlcOffers[0].changeSPK.toString('hex');
332
+ const remoteChangeScriptPubkey = dlcAccepts[0].changeSPK.toString('hex');
333
+ const localInputs = await Promise.all(dlcOffers[0].fundingInputs.map(async (fundingInput) => {
334
+ const input = await this.fundingInputToInput(fundingInput, false);
335
+ return input.toUtxo();
336
+ }));
337
+ const remoteInputs = await Promise.all(dlcAccepts[0].fundingInputs.map(async (fundingInput) => {
338
+ const input = await this.fundingInputToInput(fundingInput, false);
339
+ return input.toUtxo();
340
+ }));
341
+ const localInputAmount = localInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
342
+ const remoteInputAmount = remoteInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
343
+ const localPayouts = [];
344
+ const remotePayouts = [];
345
+ const numPayouts = [];
346
+ const nestedMessagesList = [];
347
+ // loop through all dlc offers, get payouts, and add to localPayouts and remotePayouts
348
+ for (const dlcOffer of dlcOffers) {
349
+ const payoutResponses = this.GetPayouts(dlcOffer);
350
+ const { payouts, messagesList } = this.FlattenPayouts(payoutResponses);
351
+ const tempLocalPayouts = payouts.map((payout) => payout.local);
352
+ const tempRemotePayouts = payouts.map((payout) => payout.remote);
353
+ localPayouts.push(...tempLocalPayouts);
354
+ remotePayouts.push(...tempRemotePayouts);
355
+ numPayouts.push(tempLocalPayouts.length);
356
+ nestedMessagesList.push(messagesList);
357
+ }
358
+ const batchDlcTxRequest = {
359
+ localPayouts,
360
+ remotePayouts,
361
+ numPayouts,
362
+ localFundPubkeys,
363
+ localFinalScriptPubkeys,
364
+ remoteFundPubkeys,
365
+ remoteFinalScriptPubkeys,
366
+ localInputAmount,
367
+ localCollateralAmounts: dlcOffers.map((dlcOffer) => dlcOffer.offerCollateralSatoshis),
368
+ localPayoutSerialIds: dlcOffers.map((dlcOffer) => dlcOffer.payoutSerialId),
369
+ localChangeSerialId: dlcOffers[0].changeSerialId,
370
+ remoteInputAmount,
371
+ remoteCollateralAmounts: dlcAccepts.map((dlcAccept) => dlcAccept.acceptCollateralSatoshis),
372
+ remotePayoutSerialIds: dlcAccepts.map((dlcAccept) => dlcAccept.payoutSerialId),
373
+ remoteChangeSerialId: dlcAccepts[0].changeSerialId,
374
+ refundLocktimes: dlcOffers.map((dlcOffer) => dlcOffer.refundLocktime),
375
+ localInputs,
376
+ remoteInputs,
377
+ localChangeScriptPubkey,
378
+ remoteChangeScriptPubkey,
379
+ feeRate: Number(dlcOffers[0].feeRatePerVb),
380
+ cetLockTime: dlcOffers[0].cetLocktime,
381
+ fundOutputSerialIds: dlcOffers.map((dlcOffer) => dlcOffer.fundOutputSerialId),
382
+ };
383
+ const dlcTxs = await this.CreateBatchDlcTransactions(batchDlcTxRequest);
384
+ const dlcTransactionsList = [];
385
+ let start = 0;
386
+ for (let i = 0; i < dlcTxs.refundTxHexList.length; i++) {
387
+ const dlcTransactions = new messaging_1.DlcTransactionsV0();
388
+ dlcTransactions.fundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(dlcTxs.fundTxHex));
389
+ dlcTransactions.fundTxVout = [
390
+ BigInt(dlcOffers[i].changeSerialId),
391
+ BigInt(dlcAccepts[i].changeSerialId),
392
+ ...dlcOffers.map((dlcOffer) => dlcOffer.fundOutputSerialId),
393
+ ]
394
+ .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
395
+ .findIndex((j) => BigInt(j) === BigInt(dlcOffers[i].fundOutputSerialId));
396
+ dlcTransactions.refundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(dlcTxs.refundTxHexList[i]));
397
+ // slice cetsHexList based on numPayouts
398
+ const end = start + Number(numPayouts[i]);
399
+ const cetsHexList = dlcTxs.cetsHexList.slice(start, end);
400
+ start = end;
401
+ dlcTransactions.cets = cetsHexList.map((cetHex) => {
402
+ return bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(cetHex));
403
+ });
404
+ dlcTransactionsList.push(dlcTransactions);
405
+ }
406
+ return { dlcTransactionsList, nestedMessagesList };
407
+ }
293
408
  GenerateEnumMessages(oracleEvent) {
294
409
  throw Error('Only DigitDecomposition Oracle Events supported');
295
410
  }
@@ -1064,6 +1179,54 @@ Payout Group found but incorrect group index');
1064
1179
  dlcOffer.validate();
1065
1180
  return dlcOffer;
1066
1181
  }
1182
+ async batchCreateDlcOffer(contractInfos, offerCollaterals, feeRatePerVb, cetLocktime, refundLocktimes, fixedInputs) {
1183
+ if (contractInfos.length !== offerCollaterals.length ||
1184
+ contractInfos.length !== refundLocktimes.length) {
1185
+ throw new Error('The number of contractInfos, offerCollateralSatoshis, and refundLocktimes must be the same');
1186
+ }
1187
+ const dlcOffers = [];
1188
+ for (let i = 0; i < contractInfos.length; i++) {
1189
+ contractInfos[i].validate();
1190
+ }
1191
+ const network = await this.getConnectedNetwork();
1192
+ const { fundingInputs: _fundingInputs, changeSPK, changeSerialId, initializeResponses, } = await this.BatchInitialize(offerCollaterals, feeRatePerVb, fixedInputs);
1193
+ _fundingInputs.forEach((input) => assert_1.default(input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0'));
1194
+ const fundingInputs = _fundingInputs.map((input) => input);
1195
+ fundingInputs.sort((a, b) => Number(a.inputSerialId) - Number(b.inputSerialId));
1196
+ const fundOutputsSerialIds = Utils_1.generateSerialIds(contractInfos.length);
1197
+ for (let i = 0; i < contractInfos.length; i++) {
1198
+ const contractInfo = contractInfos[i];
1199
+ const offerCollateralSatoshis = offerCollaterals[i];
1200
+ const fundOutputSerialId = fundOutputsSerialIds[i];
1201
+ const { fundingPubKey, payoutSPK, payoutSerialId } = initializeResponses[i];
1202
+ const refundLocktime = refundLocktimes[i];
1203
+ const dlcOffer = new messaging_1.DlcOfferV0();
1204
+ dlcOffer.contractFlags = Buffer.from('00', 'hex');
1205
+ dlcOffer.chainHash = bitcoin_networks_1.chainHashFromNetwork(network);
1206
+ dlcOffer.contractInfo = contractInfo;
1207
+ dlcOffer.fundingPubKey = fundingPubKey;
1208
+ dlcOffer.payoutSPK = payoutSPK;
1209
+ dlcOffer.payoutSerialId = payoutSerialId;
1210
+ dlcOffer.offerCollateralSatoshis = offerCollateralSatoshis;
1211
+ dlcOffer.fundingInputs = fundingInputs;
1212
+ dlcOffer.changeSPK = changeSPK;
1213
+ dlcOffer.changeSerialId = changeSerialId;
1214
+ dlcOffer.fundOutputSerialId = fundOutputSerialId;
1215
+ dlcOffer.feeRatePerVb = feeRatePerVb;
1216
+ dlcOffer.cetLocktime = cetLocktime;
1217
+ dlcOffer.refundLocktime = refundLocktime;
1218
+ assert_1.default((() => {
1219
+ const finalizer = new core_1.DualFundingTxFinalizer(dlcOffer.fundingInputs, dlcOffer.payoutSPK, dlcOffer.changeSPK, null, null, null, dlcOffer.feeRatePerVb);
1220
+ const funding = fundingInputs.reduce((total, input) => {
1221
+ return total + input.prevTx.outputs[input.prevTxVout].value.sats;
1222
+ }, BigInt(0));
1223
+ return funding >= offerCollateralSatoshis + finalizer.offerFees;
1224
+ })(), 'fundingInputs for dlcOffer must be greater than offerCollateralSatoshis plus offerFees');
1225
+ dlcOffer.validate();
1226
+ dlcOffers.push(dlcOffer);
1227
+ }
1228
+ return dlcOffers;
1229
+ }
1067
1230
  /**
1068
1231
  * Accept DLC Offer
1069
1232
  * @param _dlcOffer Dlc Offer Message
@@ -1120,6 +1283,75 @@ Payout Group found but incorrect group index');
1120
1283
  dlcAccept.negotiationFields = new messaging_1.NegotiationFieldsV0();
1121
1284
  return { dlcAccept, dlcTransactions: _dlcTransactions };
1122
1285
  }
1286
+ async batchAcceptDlcOffer(_dlcOffers, fixedInputs) {
1287
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
1288
+ const { dlcOffer } = Utils_1.checkTypes({ _dlcOffer });
1289
+ dlcOffer.validate();
1290
+ return dlcOffer;
1291
+ });
1292
+ const acceptCollaterals = dlcOffers.map((dlcOffer) => dlcOffer.contractInfo.totalCollateral -
1293
+ dlcOffer.offerCollateralSatoshis);
1294
+ const { fundingInputs: _fundingInputs, changeSPK, changeSerialId, initializeResponses, } = await this.BatchInitialize(acceptCollaterals, dlcOffers[0].feeRatePerVb, fixedInputs);
1295
+ // Check that none of the funding pubkeys are the same between the
1296
+ // dlcOffers and the dlcAccepts (from initializeResponses)
1297
+ dlcOffers.forEach((dlcOffer) => {
1298
+ initializeResponses.forEach((initializeResponse) => {
1299
+ assert_1.default(Buffer.compare(dlcOffer.fundingPubKey, initializeResponse.fundingPubKey) !== 0, 'DlcOffer and DlcAccept FundingPubKey cannot be the same');
1300
+ });
1301
+ });
1302
+ _fundingInputs.forEach((input) => assert_1.default(input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0'));
1303
+ const fundingInputs = _fundingInputs.map((input) => input);
1304
+ fundingInputs.sort((a, b) => Number(a.inputSerialId) - Number(b.inputSerialId));
1305
+ const dlcAccepts = [];
1306
+ initializeResponses.forEach((initializeResponse, i) => {
1307
+ const dlcOffer = dlcOffers[i];
1308
+ const dlcAccept = new messaging_1.DlcAcceptV0();
1309
+ const { fundingPubKey, payoutSPK, payoutSerialId } = initializeResponse;
1310
+ dlcAccept.tempContractId = crypto_1.sha256(dlcOffers[i].serialize());
1311
+ dlcAccept.acceptCollateralSatoshis = acceptCollaterals[i];
1312
+ dlcAccept.fundingPubKey = fundingPubKey;
1313
+ dlcAccept.payoutSPK = payoutSPK;
1314
+ dlcAccept.payoutSerialId = payoutSerialId;
1315
+ dlcAccept.fundingInputs = fundingInputs;
1316
+ dlcAccept.changeSPK = changeSPK;
1317
+ dlcAccept.changeSerialId = changeSerialId;
1318
+ assert_1.default(dlcAccept.changeSerialId !== dlcOffer.fundOutputSerialId, 'changeSerialId cannot equal the fundOutputSerialId');
1319
+ assert_1.default(dlcOffer.payoutSerialId !== dlcAccept.payoutSerialId, 'offer.payoutSerialId cannot equal accept.payoutSerialId');
1320
+ assert_1.default((() => {
1321
+ const ids = [
1322
+ dlcOffer.changeSerialId,
1323
+ dlcAccept.changeSerialId,
1324
+ dlcOffer.fundOutputSerialId,
1325
+ ];
1326
+ return new Set(ids).size === ids.length;
1327
+ })(), 'offer.changeSerialID, accept.changeSerialId and fundOutputSerialId must be unique');
1328
+ dlcAccept.validate();
1329
+ assert_1.default((() => {
1330
+ const finalizer = new core_1.DualFundingTxFinalizer(dlcOffer.fundingInputs, dlcOffer.payoutSPK, dlcOffer.changeSPK, dlcAccept.fundingInputs, dlcAccept.payoutSPK, dlcAccept.changeSPK, dlcOffer.feeRatePerVb);
1331
+ const funding = fundingInputs.reduce((total, input) => {
1332
+ return total + input.prevTx.outputs[input.prevTxVout].value.sats;
1333
+ }, BigInt(0));
1334
+ return funding >= acceptCollaterals[i] + finalizer.acceptFees;
1335
+ })(), 'fundingInputs for dlcAccept must be greater than acceptCollateralSatoshis plus acceptFees');
1336
+ dlcAccepts.push(dlcAccept);
1337
+ });
1338
+ const { dlcTransactionsList, nestedMessagesList, } = await this.createBatchDlcTxs(dlcOffers, dlcAccepts);
1339
+ for (let i = 0; i < dlcAccepts.length; i++) {
1340
+ const dlcOffer = dlcOffers[i];
1341
+ const dlcAccept = dlcAccepts[i];
1342
+ const dlcTransactions = dlcTransactionsList[i];
1343
+ const messagesList = nestedMessagesList[i];
1344
+ const { cetSignatures, refundSignature, } = await this.CreateCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcTransactions, messagesList, false);
1345
+ assert_1.default(dlcTransactions.type === messaging_1.MessageType.DlcTransactionsV0, 'DlcTransactions must be V0');
1346
+ const _dlcTransactions = dlcTransactions;
1347
+ const contractId = crypto_1.xor(_dlcTransactions.fundTx.txId.serialize(), dlcAccept.tempContractId);
1348
+ _dlcTransactions.contractId = contractId;
1349
+ dlcAccepts[i].cetSignatures = cetSignatures;
1350
+ dlcAccepts[i].refundSignature = refundSignature;
1351
+ dlcAccepts[i].negotiationFields = new messaging_1.NegotiationFieldsV0();
1352
+ }
1353
+ return { dlcAccepts, dlcTransactionsList };
1354
+ }
1123
1355
  /**
1124
1356
  * Sign Dlc Accept Message
1125
1357
  * @param _dlcOffer Dlc Offer Message
@@ -1149,6 +1381,39 @@ Payout Group found but incorrect group index');
1149
1381
  dlcSign.fundingSignatures = fundingSignatures;
1150
1382
  return { dlcSign, dlcTransactions: dlcTxs };
1151
1383
  }
1384
+ async batchSignDlcAccept(_dlcOffers, _dlcAccepts) {
1385
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
1386
+ const { dlcOffer } = Utils_1.checkTypes({ _dlcOffer });
1387
+ dlcOffer.validate();
1388
+ return dlcOffer;
1389
+ });
1390
+ const dlcAccepts = _dlcAccepts.map((_dlcAccept) => {
1391
+ const { dlcAccept } = Utils_1.checkTypes({ _dlcAccept });
1392
+ dlcAccept.validate();
1393
+ return dlcAccept;
1394
+ });
1395
+ const { dlcTransactionsList, nestedMessagesList, } = await this.createBatchDlcTxs(dlcOffers, dlcAccepts);
1396
+ const dlcSigns = [];
1397
+ const fundingSignatures = await this.CreateFundingSigs(dlcOffers[0], dlcAccepts[0], dlcTransactionsList[0], true);
1398
+ for (let i = 0; i < dlcAccepts.length; i++) {
1399
+ const dlcOffer = dlcOffers[i];
1400
+ const dlcAccept = dlcAccepts[i];
1401
+ const dlcTransactions = dlcTransactionsList[i];
1402
+ const messagesList = nestedMessagesList[i];
1403
+ const dlcSign = new messaging_1.DlcSignV0();
1404
+ await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTransactions, messagesList, true);
1405
+ const { cetSignatures, refundSignature, } = await this.CreateCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcTransactions, messagesList, true);
1406
+ const dlcTxs = dlcTransactions;
1407
+ const contractId = crypto_1.xor(dlcTxs.fundTx.txId.serialize(), dlcAccept.tempContractId);
1408
+ dlcTxs.contractId = contractId;
1409
+ dlcSign.contractId = contractId;
1410
+ dlcSign.cetSignatures = cetSignatures;
1411
+ dlcSign.refundSignature = refundSignature;
1412
+ dlcSign.fundingSignatures = fundingSignatures;
1413
+ dlcSigns.push(dlcSign);
1414
+ }
1415
+ return { dlcSigns, dlcTransactionsList };
1416
+ }
1152
1417
  /**
1153
1418
  * Finalize Dlc Sign
1154
1419
  * @param _dlcOffer Dlc Offer Message
@@ -1172,6 +1437,39 @@ Payout Group found but incorrect group index');
1172
1437
  const fundTx = await this.CreateFundingTx(dlcOffer, dlcAccept, dlcSign, dlcTxs, fundingSignatures);
1173
1438
  return fundTx;
1174
1439
  }
1440
+ async batchFinalizeDlcSign(_dlcOffers, _dlcAccepts, _dlcSigns, _dlcTxsList) {
1441
+ const dlcOffers = _dlcOffers.map((_dlcOffer) => {
1442
+ const { dlcOffer } = Utils_1.checkTypes({ _dlcOffer });
1443
+ dlcOffer.validate();
1444
+ return dlcOffer;
1445
+ });
1446
+ const dlcAccepts = _dlcAccepts.map((_dlcAccept) => {
1447
+ const { dlcAccept } = Utils_1.checkTypes({ _dlcAccept });
1448
+ dlcAccept.validate();
1449
+ return dlcAccept;
1450
+ });
1451
+ const dlcSigns = _dlcSigns.map((_dlcSign) => {
1452
+ const { dlcSign } = Utils_1.checkTypes({ _dlcSign });
1453
+ return dlcSign;
1454
+ });
1455
+ const dlcTxsList = _dlcTxsList.map((_dlcTxs) => {
1456
+ const { dlcTxs } = Utils_1.checkTypes({ _dlcTxs });
1457
+ return dlcTxs;
1458
+ });
1459
+ await this.VerifyFundingSigs(dlcOffers[0], dlcAccepts[0], dlcSigns[0], dlcTxsList[0], false);
1460
+ for (let i = 0; i < dlcOffers.length; i++) {
1461
+ const dlcOffer = dlcOffers[i];
1462
+ const dlcAccept = dlcAccepts[i];
1463
+ const dlcSign = dlcSigns[i];
1464
+ const dlcTxs = dlcTxsList[i];
1465
+ const payoutResponses = this.GetPayouts(dlcOffer);
1466
+ const { messagesList } = this.FlattenPayouts(payoutResponses);
1467
+ await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTxs, messagesList, false);
1468
+ }
1469
+ const fundingSignatures = await this.CreateFundingSigs(dlcOffers[0], dlcAccepts[0], dlcTxsList[0], false);
1470
+ const fundTx = await this.CreateFundingTx(dlcOffers[0], dlcAccepts[0], dlcSigns[0], dlcTxsList[0], fundingSignatures);
1471
+ return fundTx;
1472
+ }
1175
1473
  /**
1176
1474
  * Execute DLC
1177
1475
  * @param _dlcOffer Dlc Offer Message
@@ -1621,10 +1919,18 @@ Payout Group found but incorrect group index');
1621
1919
  await this.CfdLoaded();
1622
1920
  return this._cfdDlcJs.CreateDlcTransactions(jsonObject);
1623
1921
  }
1922
+ async CreateBatchDlcTransactions(jsonObject) {
1923
+ await this.CfdLoaded();
1924
+ return this._cfdDlcJs.CreateBatchDlcTransactions(jsonObject);
1925
+ }
1624
1926
  async CreateFundTransaction(jsonObject) {
1625
1927
  await this.CfdLoaded();
1626
1928
  return this._cfdDlcJs.CreateFundTransaction(jsonObject);
1627
1929
  }
1930
+ async CreateBatchFundTransaction(jsonObject) {
1931
+ await this.CfdLoaded();
1932
+ return this._cfdDlcJs.CreateBatchFundTransaction(jsonObject);
1933
+ }
1628
1934
  async CreateRefundTransaction(jsonObject) {
1629
1935
  await this.CfdLoaded();
1630
1936
  return this._cfdDlcJs.CreateRefundTransaction(jsonObject);