@atomicfinance/bitcoin-dlc-provider 3.5.1 → 3.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @atomicfinance/bitcoin-dlc-provider
2
2
 
3
+ ## 3.5.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 87ff085: Fix enum hashed outcomes
8
+ - Updated dependencies [87ff085]
9
+ - @atomicfinance/bitcoin-utils@3.5.3
10
+ - @atomicfinance/provider@3.5.3
11
+ - @atomicfinance/types@3.5.3
12
+ - @atomicfinance/utils@3.5.3
13
+
14
+ ## 3.5.2
15
+
16
+ ### Patch Changes
17
+
18
+ - 3e8815c: Add support for Enum DLCs
19
+ - Updated dependencies [3e8815c]
20
+ - @atomicfinance/bitcoin-utils@3.5.2
21
+ - @atomicfinance/provider@3.5.2
22
+ - @atomicfinance/types@3.5.2
23
+ - @atomicfinance/utils@3.5.2
24
+
3
25
  ## 3.5.1
4
26
 
5
27
  ### Patch Changes
@@ -270,8 +270,28 @@ class BitcoinDlcProvider extends provider_1.default {
270
270
  }));
271
271
  const localInputAmount = localInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
272
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);
273
+ let payouts = [];
274
+ let messagesList = [];
275
+ if (dlcOffer.contractInfo.type === messaging_1.MessageType.ContractInfoV0 &&
276
+ dlcOffer.contractInfo.contractDescriptor.type ===
277
+ messaging_1.MessageType.ContractDescriptorV0) {
278
+ for (const outcome of dlcOffer.contractInfo
279
+ .contractDescriptor.outcomes) {
280
+ payouts.push({
281
+ local: outcome.localPayout,
282
+ remote: dlcOffer.offerCollateralSatoshis +
283
+ dlcAccept.acceptCollateralSatoshis -
284
+ outcome.localPayout,
285
+ });
286
+ messagesList.push({ messages: [outcome.outcome.toString('hex')] });
287
+ }
288
+ }
289
+ else {
290
+ const payoutResponses = this.GetPayouts(dlcOffer);
291
+ const { payouts: tempPayouts, messagesList: tempMessagesList, } = this.FlattenPayouts(payoutResponses);
292
+ payouts = tempPayouts;
293
+ messagesList = tempMessagesList;
294
+ }
275
295
  const dlcTxRequest = {
276
296
  payouts,
277
297
  localFundPubkey,
@@ -463,18 +483,15 @@ class BitcoinDlcProvider extends provider_1.default {
463
483
  const fundPrivateKeyPair = await this.getMethod('keyPair')(derivationPath);
464
484
  const fundPrivateKey = Buffer.from(fundPrivateKeyPair.__D).toString('hex');
465
485
  const contractOraclePairs = this.GetContractOraclePairs(dlcOffer.contractInfo);
466
- const indices = this.GetIndicesFromPayouts(this.GetPayouts(_dlcOffer));
467
486
  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);
487
+ if (dlcOffer.contractInfo.type === messaging_1.MessageType.ContractInfoV0 &&
488
+ dlcOffer.contractInfo.contractDescriptor.type ===
489
+ messaging_1.MessageType.ContractDescriptorV0) {
490
+ for (const [_, { oracleInfo }] of contractOraclePairs.entries()) {
491
+ const oracleAnnouncement = oracleInfo.announcement;
492
+ const adaptorSigRequestPromises = [];
493
+ const tempMessagesList = messagesList;
494
+ const tempCetsHex = cetsHex;
478
495
  const cetSignRequest = {
479
496
  messagesList: tempMessagesList,
480
497
  cetsHex: tempCetsHex,
@@ -491,14 +508,52 @@ class BitcoinDlcProvider extends provider_1.default {
491
508
  const response = await this.CreateCetAdaptorSignatures(cetSignRequest);
492
509
  return response.adaptorPairs;
493
510
  })());
511
+ const adaptorPairs = (await Promise.all(adaptorSigRequestPromises)).flat();
512
+ sigs.push(adaptorPairs.map((adaptorPair) => {
513
+ return {
514
+ encryptedSig: Buffer.from(adaptorPair.signature, 'hex'),
515
+ dleqProof: Buffer.from(adaptorPair.proof, 'hex'),
516
+ };
517
+ }));
518
+ }
519
+ }
520
+ else {
521
+ const indices = this.GetIndicesFromPayouts(this.GetPayouts(_dlcOffer));
522
+ for (const [index, { oracleInfo }] of contractOraclePairs.entries()) {
523
+ const oracleAnnouncement = oracleInfo.announcement;
524
+ const startingIndex = indices[index].startingMessagesIndex, endingIndex = indices[index + 1].startingMessagesIndex;
525
+ const oracleEventMessagesList = messagesList.slice(startingIndex, endingIndex);
526
+ const oracleEventCetsHex = cetsHex.slice(startingIndex, endingIndex);
527
+ const chunk = 100;
528
+ const adaptorSigRequestPromises = [];
529
+ for (let i = 0, j = oracleEventMessagesList.length; i < j; i += chunk) {
530
+ const tempMessagesList = oracleEventMessagesList.slice(i, i + chunk);
531
+ const tempCetsHex = oracleEventCetsHex.slice(i, i + chunk);
532
+ const cetSignRequest = {
533
+ messagesList: tempMessagesList,
534
+ cetsHex: tempCetsHex,
535
+ privkey: fundPrivateKey,
536
+ fundTxId: dlcTxs.fundTx.txId.toString(),
537
+ fundVout: dlcTxs.fundTxVout,
538
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
539
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
540
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
541
+ oraclePubkey: oracleAnnouncement.oraclePubkey.toString('hex'),
542
+ oracleRValues: oracleAnnouncement.oracleEvent.oracleNonces.map((nonce) => nonce.toString('hex')),
543
+ };
544
+ adaptorSigRequestPromises.push((async () => {
545
+ const response = await this.CreateCetAdaptorSignatures(cetSignRequest);
546
+ return response.adaptorPairs;
547
+ })());
548
+ }
549
+ const adaptorPairs = (await Promise.all(adaptorSigRequestPromises)).flat();
550
+ sigs.push(adaptorPairs.map((adaptorPair) => {
551
+ return {
552
+ encryptedSig: Buffer.from(adaptorPair.signature, 'hex'),
553
+ dleqProof: Buffer.from(adaptorPair.proof, 'hex'),
554
+ };
555
+ }));
494
556
  }
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
557
  }
503
558
  const refundSignRequest = {
504
559
  refundTxHex: dlcTxs.refundTx.serialize().toString('hex'),
@@ -522,22 +577,20 @@ class BitcoinDlcProvider extends provider_1.default {
522
577
  _dlcTxs,
523
578
  });
524
579
  const cetsHex = dlcTxs.cets.map((cet) => cet.serialize().toString('hex'));
525
- const chunk = 100;
526
580
  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);
581
+ if (dlcOffer.contractInfo.type === messaging_1.MessageType.ContractInfoV0 &&
582
+ dlcOffer.contractInfo.contractDescriptor.type ===
583
+ messaging_1.MessageType.ContractDescriptorV0) {
584
+ for (const [_, { oracleInfo }] of contractOraclePairs.entries()) {
585
+ const oracleAnnouncement = oracleInfo.announcement;
586
+ const oracleEventCetsHex = cetsHex;
587
+ const oracleEventSigs = isOfferer
588
+ ? dlcAccept.cetSignatures.sigs
589
+ : dlcSign.cetSignatures.sigs;
590
+ const sigsValidity = [];
591
+ const tempMessagesList = messagesList;
592
+ const tempCetsHex = oracleEventCetsHex;
593
+ const tempSigs = oracleEventSigs;
541
594
  const tempAdaptorPairs = tempSigs.map((sig) => {
542
595
  return {
543
596
  signature: sig.encryptedSig.toString('hex'),
@@ -561,25 +614,86 @@ class BitcoinDlcProvider extends provider_1.default {
561
614
  const response = await this.VerifyCetAdaptorSignatures(verifyCetAdaptorSignaturesRequest);
562
615
  return response.valid;
563
616
  })());
617
+ let areSigsValid = (await Promise.all(sigsValidity)).every((b) => b);
618
+ const verifyRefundSigRequest = {
619
+ refundTxHex: dlcTxs.refundTx.serialize().toString('hex'),
620
+ signature: isOfferer
621
+ ? dlcAccept.refundSignature.toString('hex')
622
+ : dlcSign.refundSignature.toString('hex'),
623
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
624
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
625
+ fundTxId: dlcTxs.fundTx.txId.toString(),
626
+ fundVout: dlcTxs.fundTxVout,
627
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
628
+ verifyRemote: isOfferer,
629
+ };
630
+ areSigsValid =
631
+ areSigsValid &&
632
+ (await this.VerifyRefundTxSignature(verifyRefundSigRequest)).valid;
633
+ if (!areSigsValid) {
634
+ throw new Error('Invalid signatures received');
635
+ }
564
636
  }
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');
637
+ }
638
+ else {
639
+ const chunk = 100;
640
+ const indices = this.GetIndicesFromPayouts(this.GetPayouts(_dlcOffer));
641
+ for (const [index, { oracleInfo }] of contractOraclePairs.entries()) {
642
+ const oracleAnnouncement = oracleInfo.announcement;
643
+ const startingIndex = indices[index].startingMessagesIndex, endingIndex = indices[index + 1].startingMessagesIndex;
644
+ const oracleEventMessagesList = messagesList.slice(startingIndex, endingIndex);
645
+ const oracleEventCetsHex = cetsHex.slice(startingIndex, endingIndex);
646
+ const oracleEventSigs = (isOfferer
647
+ ? dlcAccept.cetSignatures.sigs
648
+ : dlcSign.cetSignatures.sigs).slice(startingIndex, endingIndex);
649
+ const sigsValidity = [];
650
+ for (let i = 0, j = oracleEventMessagesList.length; i < j; i += chunk) {
651
+ const tempMessagesList = oracleEventMessagesList.slice(i, i + chunk);
652
+ const tempCetsHex = oracleEventCetsHex.slice(i, i + chunk);
653
+ const tempSigs = oracleEventSigs.slice(i, i + chunk);
654
+ const tempAdaptorPairs = tempSigs.map((sig) => {
655
+ return {
656
+ signature: sig.encryptedSig.toString('hex'),
657
+ proof: sig.dleqProof.toString('hex'),
658
+ };
659
+ });
660
+ const verifyCetAdaptorSignaturesRequest = {
661
+ cetsHex: tempCetsHex,
662
+ messagesList: tempMessagesList,
663
+ oraclePubkey: oracleAnnouncement.oraclePubkey.toString('hex'),
664
+ oracleRValues: oracleAnnouncement.oracleEvent.oracleNonces.map((nonce) => nonce.toString('hex')),
665
+ adaptorPairs: tempAdaptorPairs,
666
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
667
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
668
+ fundTxId: dlcTxs.fundTx.txId.toString(),
669
+ fundVout: dlcTxs.fundTxVout,
670
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
671
+ verifyRemote: isOfferer,
672
+ };
673
+ sigsValidity.push((async () => {
674
+ const response = await this.VerifyCetAdaptorSignatures(verifyCetAdaptorSignaturesRequest);
675
+ return response.valid;
676
+ })());
677
+ }
678
+ let areSigsValid = (await Promise.all(sigsValidity)).every((b) => b);
679
+ const verifyRefundSigRequest = {
680
+ refundTxHex: dlcTxs.refundTx.serialize().toString('hex'),
681
+ signature: isOfferer
682
+ ? dlcAccept.refundSignature.toString('hex')
683
+ : dlcSign.refundSignature.toString('hex'),
684
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
685
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
686
+ fundTxId: dlcTxs.fundTx.txId.toString(),
687
+ fundVout: dlcTxs.fundTxVout,
688
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
689
+ verifyRemote: isOfferer,
690
+ };
691
+ areSigsValid =
692
+ areSigsValid &&
693
+ (await this.VerifyRefundTxSignature(verifyRefundSigRequest)).valid;
694
+ if (!areSigsValid) {
695
+ throw new Error('Invalid signatures received');
696
+ }
583
697
  }
584
698
  }
585
699
  }
@@ -828,8 +942,13 @@ Payout Group not found');
828
942
  case messaging_1.MessageType.ContractInfoV0: {
829
943
  const contractInfo = dlcOffer.contractInfo;
830
944
  switch (contractInfo.contractDescriptor.type) {
831
- case messaging_1.MessageType.ContractDescriptorV0:
832
- throw Error('ContractDescriptorV0 not yet supported');
945
+ case messaging_1.MessageType.ContractDescriptorV0: {
946
+ const oracleInfo = contractInfo.oracleInfo;
947
+ if (oracleInfo.announcement.oracleEvent.eventId !==
948
+ oracleAttestation.eventId)
949
+ throw Error('Incorrect Oracle Attestation. Event Id must match.');
950
+ break;
951
+ }
833
952
  case messaging_1.MessageType.ContractDescriptorV1: {
834
953
  const oracleInfo = contractInfo.oracleInfo;
835
954
  if (oracleInfo.announcement.oracleEvent.eventId !==
@@ -863,25 +982,48 @@ Payout Group not found');
863
982
  });
864
983
  if (isOfferer === undefined)
865
984
  isOfferer = await this.isOfferer(dlcOffer, dlcAccept);
866
- const { index: outcomeIndex, groupLength } = await this.FindOutcomeIndex(dlcOffer, oracleAttestation);
867
985
  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
- };
986
+ let signCetRequest;
987
+ if (dlcOffer.contractInfo.type === messaging_1.MessageType.ContractInfoV0 &&
988
+ dlcOffer.contractInfo.contractDescriptor.type ===
989
+ messaging_1.MessageType.ContractDescriptorV0) {
990
+ const outcomeIndex = dlcOffer.contractInfo
991
+ .contractDescriptor.outcomes.findIndex((outcome) => outcome.outcome.toString('hex') ===
992
+ (0, crypto_1.sha256)(Buffer.from(oracleAttestation.outcomes[0])).toString('hex'));
993
+ signCetRequest = {
994
+ cetHex: dlcTxs.cets[outcomeIndex].serialize().toString('hex'),
995
+ fundPrivkey: fundPrivateKey,
996
+ fundTxId: dlcTxs.fundTx.txId.toString(),
997
+ fundVout: dlcTxs.fundTxVout,
998
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
999
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
1000
+ oracleSignatures: oracleAttestation.signatures.map((sig) => sig.toString('hex')),
1001
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
1002
+ adaptorSignature: isOfferer
1003
+ ? dlcAccept.cetSignatures.sigs[outcomeIndex].encryptedSig.toString('hex')
1004
+ : dlcSign.cetSignatures.sigs[outcomeIndex].encryptedSig.toString('hex'),
1005
+ };
1006
+ }
1007
+ else {
1008
+ const { index: outcomeIndex, groupLength } = await this.FindOutcomeIndex(dlcOffer, oracleAttestation);
1009
+ const sliceIndex = -(oracleAttestation.signatures.length - groupLength);
1010
+ const oracleSignatures = sliceIndex === 0
1011
+ ? oracleAttestation.signatures
1012
+ : oracleAttestation.signatures.slice(0, sliceIndex);
1013
+ signCetRequest = {
1014
+ cetHex: dlcTxs.cets[outcomeIndex].serialize().toString('hex'),
1015
+ fundPrivkey: fundPrivateKey,
1016
+ fundTxId: dlcTxs.fundTx.txId.toString(),
1017
+ fundVout: dlcTxs.fundTxVout,
1018
+ localFundPubkey: dlcOffer.fundingPubKey.toString('hex'),
1019
+ remoteFundPubkey: dlcAccept.fundingPubKey.toString('hex'),
1020
+ oracleSignatures: oracleSignatures.map((sig) => sig.toString('hex')),
1021
+ fundInputAmount: dlcTxs.fundTx.outputs[dlcTxs.fundTxVout].value.sats,
1022
+ adaptorSignature: isOfferer
1023
+ ? dlcAccept.cetSignatures.sigs[outcomeIndex].encryptedSig.toString('hex')
1024
+ : dlcSign.cetSignatures.sigs[outcomeIndex].encryptedSig.toString('hex'),
1025
+ };
1026
+ }
885
1027
  const finalCet = (await this.SignCet(signCetRequest)).hex;
886
1028
  return bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(finalCet));
887
1029
  }
@@ -1417,8 +1559,20 @@ Payout Group not found');
1417
1559
  _dlcSign,
1418
1560
  _dlcTxs,
1419
1561
  });
1420
- const payoutResponses = this.GetPayouts(dlcOffer);
1421
- const { messagesList } = this.FlattenPayouts(payoutResponses);
1562
+ let messagesList = [];
1563
+ if (dlcOffer.contractInfo.type === messaging_1.MessageType.ContractInfoV0 &&
1564
+ dlcOffer.contractInfo.contractDescriptor.type ===
1565
+ messaging_1.MessageType.ContractDescriptorV0) {
1566
+ for (const outcome of dlcOffer.contractInfo
1567
+ .contractDescriptor.outcomes) {
1568
+ messagesList.push({ messages: [outcome.outcome.toString('hex')] });
1569
+ }
1570
+ }
1571
+ else {
1572
+ const payoutResponses = this.GetPayouts(dlcOffer);
1573
+ const { messagesList: oracleEventMessagesList } = this.FlattenPayouts(payoutResponses);
1574
+ messagesList = oracleEventMessagesList;
1575
+ }
1422
1576
  await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTxs, messagesList, false);
1423
1577
  await this.VerifyFundingSigs(dlcOffer, dlcAccept, dlcSign, dlcTxs, false);
1424
1578
  const fundingSignatures = await this.CreateFundingSigs(dlcOffer, dlcAccept, dlcTxs, false);