@bsv/sdk 1.1.29 → 1.1.32

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.
Files changed (61) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/primitives/Schnorr.js +92 -0
  3. package/dist/cjs/src/primitives/Schnorr.js.map +1 -0
  4. package/dist/cjs/src/primitives/index.js +3 -1
  5. package/dist/cjs/src/primitives/index.js.map +1 -1
  6. package/dist/cjs/src/totp/totp.js +1 -1
  7. package/dist/cjs/src/totp/totp.js.map +1 -1
  8. package/dist/cjs/src/transaction/Beef.js +292 -155
  9. package/dist/cjs/src/transaction/Beef.js.map +1 -1
  10. package/dist/cjs/src/transaction/BeefParty.js +46 -26
  11. package/dist/cjs/src/transaction/BeefParty.js.map +1 -1
  12. package/dist/cjs/src/transaction/BeefTx.js +31 -16
  13. package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
  14. package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
  15. package/dist/cjs/src/transaction/Transaction.js +12 -6
  16. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  17. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  18. package/dist/esm/src/primitives/Schnorr.js +87 -0
  19. package/dist/esm/src/primitives/Schnorr.js.map +1 -0
  20. package/dist/esm/src/primitives/index.js +1 -0
  21. package/dist/esm/src/primitives/index.js.map +1 -1
  22. package/dist/esm/src/totp/totp.js +1 -1
  23. package/dist/esm/src/totp/totp.js.map +1 -1
  24. package/dist/esm/src/transaction/Beef.js +294 -157
  25. package/dist/esm/src/transaction/Beef.js.map +1 -1
  26. package/dist/esm/src/transaction/BeefParty.js +47 -27
  27. package/dist/esm/src/transaction/BeefParty.js.map +1 -1
  28. package/dist/esm/src/transaction/BeefTx.js +35 -20
  29. package/dist/esm/src/transaction/BeefTx.js.map +1 -1
  30. package/dist/esm/src/transaction/MerklePath.js.map +1 -1
  31. package/dist/esm/src/transaction/Transaction.js +12 -6
  32. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  33. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  34. package/dist/types/src/primitives/Schnorr.d.ts +65 -0
  35. package/dist/types/src/primitives/Schnorr.d.ts.map +1 -0
  36. package/dist/types/src/primitives/index.d.ts +1 -0
  37. package/dist/types/src/primitives/index.d.ts.map +1 -1
  38. package/dist/types/src/transaction/Beef.d.ts +131 -90
  39. package/dist/types/src/transaction/Beef.d.ts.map +1 -1
  40. package/dist/types/src/transaction/BeefParty.d.ts +34 -23
  41. package/dist/types/src/transaction/BeefParty.d.ts.map +1 -1
  42. package/dist/types/src/transaction/BeefTx.d.ts +11 -6
  43. package/dist/types/src/transaction/BeefTx.d.ts.map +1 -1
  44. package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
  45. package/dist/types/src/transaction/Transaction.d.ts +8 -2
  46. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  47. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  48. package/dist/umd/bundle.js +1 -1
  49. package/docs/primitives.md +120 -9
  50. package/docs/transaction.md +141 -9
  51. package/package.json +1 -1
  52. package/src/primitives/Schnorr.ts +95 -0
  53. package/src/primitives/__tests/Schnorr.test.ts +272 -0
  54. package/src/primitives/index.ts +1 -0
  55. package/src/totp/totp.ts +1 -1
  56. package/src/transaction/Beef.ts +493 -378
  57. package/src/transaction/BeefParty.ts +71 -58
  58. package/src/transaction/BeefTx.ts +133 -143
  59. package/src/transaction/MerklePath.ts +11 -11
  60. package/src/transaction/Transaction.ts +42 -36
  61. package/src/transaction/__tests/Beef.test.ts +55 -10
@@ -67,7 +67,7 @@ export default class Transaction {
67
67
  * @param txid Optional TXID of the transaction to retrieve from the BEEF data.
68
68
  * @returns An anchored transaction, linked to its associated inputs populated with merkle paths.
69
69
  */
70
- static fromBEEF(beef: number[], txid?: string): Transaction {
70
+ static fromBEEF (beef: number[], txid?: string): Transaction {
71
71
  const reader = new Reader(beef)
72
72
  const { transactions, BUMPs } = Transaction.parseBEEFData(reader)
73
73
 
@@ -115,7 +115,7 @@ export default class Transaction {
115
115
  * @param beef A binary representation of an Atomic BEEF structure.
116
116
  * @returns The subject transaction, linked to its associated inputs populated with merkle paths.
117
117
  */
118
- static fromAtomicBEEF(beef: number[]): Transaction {
118
+ static fromAtomicBEEF (beef: number[]): Transaction {
119
119
  const reader = new Reader(beef)
120
120
  // Read the Atomic BEEF prefix
121
121
  const prefix = reader.readUInt32LE()
@@ -194,7 +194,7 @@ export default class Transaction {
194
194
  * @param reader The Reader positioned at the start of BEEF data.
195
195
  * @returns An object containing the transactions and BUMPs.
196
196
  */
197
- private static parseBEEFData(reader: Reader): { transactions: Record<string, { pathIndex?: number, tx: Transaction }>, BUMPs: MerklePath[] } {
197
+ private static parseBEEFData (reader: Reader): { transactions: Record<string, { pathIndex?: number, tx: Transaction }>, BUMPs: MerklePath[] } {
198
198
  // Read the version
199
199
  const version = reader.readUInt32LE()
200
200
  if (version !== BEEF_MAGIC) {
@@ -231,7 +231,7 @@ export default class Transaction {
231
231
  * @param ef A binary representation of a transaction in EF format.
232
232
  * @returns An extended transaction, linked to its associated inputs by locking script and satoshis amounts only.
233
233
  */
234
- static fromEF(ef: number[]): Transaction {
234
+ static fromEF (ef: number[]): Transaction {
235
235
  const br = new Reader(ef)
236
236
  const version = br.readUInt32LE()
237
237
  if (toHex(br.read(6)) !== '0000000000ef') throw new Error('Invalid EF marker')
@@ -293,7 +293,7 @@ export default class Transaction {
293
293
  * outputs: { vout: number, offset: number, length: number }[]
294
294
  * }
295
295
  */
296
- static parseScriptOffsets(bin: number[]): {
296
+ static parseScriptOffsets (bin: number[]): {
297
297
  inputs: Array<{ vin: number, offset: number, length: number }>
298
298
  outputs: Array<{ vout: number, offset: number, length: number }>
299
299
  } {
@@ -319,7 +319,7 @@ export default class Transaction {
319
319
  return { inputs, outputs }
320
320
  }
321
321
 
322
- static fromReader(br: Reader): Transaction {
322
+ static fromReader (br: Reader): Transaction {
323
323
  const version = br.readUInt32LE()
324
324
  const inputsLength = br.readVarIntNum()
325
325
  const inputs: TransactionInput[] = []
@@ -360,7 +360,7 @@ export default class Transaction {
360
360
  * @param {number[]} bin - The binary array representation of the transaction.
361
361
  * @returns {Transaction} - A new Transaction instance.
362
362
  */
363
- static fromBinary(bin: number[]): Transaction {
363
+ static fromBinary (bin: number[]): Transaction {
364
364
  const br = new Reader(bin)
365
365
  return Transaction.fromReader(br)
366
366
  }
@@ -372,7 +372,7 @@ export default class Transaction {
372
372
  * @param {string} hex - The hexadecimal string representation of the transaction.
373
373
  * @returns {Transaction} - A new Transaction instance.
374
374
  */
375
- static fromHex(hex: string): Transaction {
375
+ static fromHex (hex: string): Transaction {
376
376
  return Transaction.fromBinary(toArray(hex, 'hex'))
377
377
  }
378
378
 
@@ -383,7 +383,7 @@ export default class Transaction {
383
383
  * @param {string} hex - The hexadecimal string representation of the transaction EF.
384
384
  * @returns {Transaction} - A new Transaction instance.
385
385
  */
386
- static fromHexEF(hex: string): Transaction {
386
+ static fromHexEF (hex: string): Transaction {
387
387
  return Transaction.fromEF(toArray(hex, 'hex'))
388
388
  }
389
389
 
@@ -398,11 +398,11 @@ export default class Transaction {
398
398
  * @param {string} [txid] - Optional TXID of the transaction to retrieve from the BEEF data.
399
399
  * @returns {Transaction} - A new Transaction instance.
400
400
  */
401
- static fromHexBEEF(hex: string, txid?: string): Transaction {
401
+ static fromHexBEEF (hex: string, txid?: string): Transaction {
402
402
  return Transaction.fromBEEF(toArray(hex, 'hex'), txid)
403
403
  }
404
404
 
405
- constructor(
405
+ constructor (
406
406
  version: number = 1,
407
407
  inputs: TransactionInput[] = [],
408
408
  outputs: TransactionOutput[] = [],
@@ -424,7 +424,7 @@ export default class Transaction {
424
424
  * @param {TransactionInput} input - The TransactionInput object to add to the transaction.
425
425
  * @throws {Error} - If the input does not have a sourceTXID or sourceTransaction defined.
426
426
  */
427
- addInput(input: TransactionInput): void {
427
+ addInput (input: TransactionInput): void {
428
428
  if (
429
429
  typeof input.sourceTXID === 'undefined' &&
430
430
  typeof input.sourceTransaction === 'undefined'
@@ -444,7 +444,7 @@ export default class Transaction {
444
444
  *
445
445
  * @param {TransactionOutput} output - The TransactionOutput object to add to the transaction.
446
446
  */
447
- addOutput(output: TransactionOutput): void {
447
+ addOutput (output: TransactionOutput): void {
448
448
  this.cachedHash = undefined
449
449
  this.outputs.push(output)
450
450
  }
@@ -454,7 +454,7 @@ export default class Transaction {
454
454
  *
455
455
  * @param {Record<string, any>} metadata - The metadata object to merge into the existing metadata.
456
456
  */
457
- updateMetadata(metadata: Record<string, any>): void {
457
+ updateMetadata (metadata: Record<string, any>): void {
458
458
  this.metadata = {
459
459
  ...this.metadata,
460
460
  ...metadata
@@ -472,7 +472,7 @@ export default class Transaction {
472
472
  *
473
473
  * TODO: Benford's law change distribution.
474
474
  */
475
- async fee(modelOrFee?: FeeModel | number, changeDistribution: 'equal' | 'random' = 'equal'): Promise<void> {
475
+ async fee (modelOrFee?: FeeModel | number, changeDistribution: 'equal' | 'random' = 'equal'): Promise<void> {
476
476
  this.cachedHash = undefined
477
477
  if (typeof modelOrFee === 'undefined') {
478
478
  modelOrFee = new SatoshisPerKilobyte(10)
@@ -533,7 +533,7 @@ export default class Transaction {
533
533
  *
534
534
  * @returns The current transaction fee
535
535
  */
536
- getFee(): number {
536
+ getFee (): number {
537
537
  let totalIn = 0
538
538
  for (const input of this.inputs) {
539
539
  if (typeof input.sourceTransaction !== 'object') {
@@ -551,7 +551,7 @@ export default class Transaction {
551
551
  /**
552
552
  * Signs a transaction, hydrating all its unlocking scripts based on the provided script templates where they are available.
553
553
  */
554
- async sign(): Promise<void> {
554
+ async sign (): Promise<void> {
555
555
  this.cachedHash = undefined
556
556
  for (const out of this.outputs) {
557
557
  if (typeof out.satoshis === 'undefined') {
@@ -582,7 +582,7 @@ export default class Transaction {
582
582
  * @param broadcaster The Broadcaster instance wwhere the transaction will be sent
583
583
  * @returns A BroadcastResponse or BroadcastFailure from the Broadcaster
584
584
  */
585
- async broadcast(broadcaster: Broadcaster = defaultBroadcaster()): Promise<BroadcastResponse | BroadcastFailure> {
585
+ async broadcast (broadcaster: Broadcaster = defaultBroadcaster()): Promise<BroadcastResponse | BroadcastFailure> {
586
586
  return await broadcaster.broadcast(this)
587
587
  }
588
588
 
@@ -591,7 +591,7 @@ export default class Transaction {
591
591
  *
592
592
  * @returns {number[]} - The binary array representation of the transaction.
593
593
  */
594
- toBinary(): number[] {
594
+ toBinary (): number[] {
595
595
  const writer = new Writer()
596
596
  writer.writeUInt32LE(this.version)
597
597
  writer.writeVarIntNum(this.inputs.length)
@@ -623,7 +623,7 @@ export default class Transaction {
623
623
  *
624
624
  * @returns {number[]} - The BRC-30 EF representation of the transaction.
625
625
  */
626
- toEF(): number[] {
626
+ toEF (): number[] {
627
627
  const writer = new Writer()
628
628
  writer.writeUInt32LE(this.version)
629
629
  writer.write([0, 0, 0, 0, 0, 0xef])
@@ -663,7 +663,7 @@ export default class Transaction {
663
663
  *
664
664
  * @returns {string} - The hexadecimal string representation of the transaction EF.
665
665
  */
666
- toHexEF(): string {
666
+ toHexEF (): string {
667
667
  return toHex(this.toEF())
668
668
  }
669
669
 
@@ -672,7 +672,7 @@ export default class Transaction {
672
672
  *
673
673
  * @returns {string} - The hexadecimal string representation of the transaction.
674
674
  */
675
- toHex(): string {
675
+ toHex (): string {
676
676
  return toHex(this.toBinary())
677
677
  }
678
678
 
@@ -681,7 +681,7 @@ export default class Transaction {
681
681
  *
682
682
  * @returns {string} - The hexadecimal string representation of the transaction BEEF.
683
683
  */
684
- toHexBEEF(): string {
684
+ toHexBEEF (): string {
685
685
  return toHex(this.toBEEF())
686
686
  }
687
687
 
@@ -690,7 +690,7 @@ export default class Transaction {
690
690
  *
691
691
  * @returns {string} - The hexadecimal string representation of the transaction Atomic BEEF.
692
692
  */
693
- toHexAtomicBEEF(): string {
693
+ toHexAtomicBEEF (): string {
694
694
  return toHex(this.toAtomicBEEF())
695
695
  }
696
696
 
@@ -700,7 +700,7 @@ export default class Transaction {
700
700
  * @param {'hex' | undefined} enc - The encoding to use for the hash. If 'hex', returns a hexadecimal string; otherwise returns a binary array.
701
701
  * @returns {string | number[]} - The hash of the transaction in the specified format.
702
702
  */
703
- hash(enc?: 'hex'): number[] | string {
703
+ hash (enc?: 'hex'): number[] | string {
704
704
  let hash
705
705
  if (this.cachedHash) {
706
706
  hash = this.cachedHash
@@ -719,21 +719,21 @@ export default class Transaction {
719
719
  *
720
720
  * @returns {number[]} - The ID of the transaction in the binary array format.
721
721
  */
722
- id(): number[]
722
+ id (): number[]
723
723
  /**
724
724
  * Calculates the transaction's ID in hexadecimal format.
725
725
  *
726
726
  * @param {'hex'} enc - The encoding to use for the ID. If 'hex', returns a hexadecimal string.
727
727
  * @returns {string} - The ID of the transaction in the hex format.
728
728
  */
729
- id(enc: 'hex'): string
729
+ id (enc: 'hex'): string
730
730
  /**
731
731
  * Calculates the transaction's ID.
732
732
  *
733
733
  * @param {'hex' | undefined} enc - The encoding to use for the ID. If 'hex', returns a hexadecimal string; otherwise returns a binary array.
734
734
  * @returns {string | number[]} - The ID of the transaction in the specified format.
735
735
  */
736
- id(enc?: 'hex'): number[] | string {
736
+ id (enc?: 'hex'): number[] | string {
737
737
  const id = [...this.hash() as number[]]
738
738
  id.reverse()
739
739
  if (enc === 'hex') {
@@ -751,7 +751,7 @@ export default class Transaction {
751
751
  *
752
752
  * @example tx.verify(new WhatsOnChain(), new SatoshisPerKilobyte(1))
753
753
  */
754
- async verify(
754
+ async verify (
755
755
  chainTracker: ChainTracker | 'scripts only' = defaultChainTracker(),
756
756
  feeModel?: FeeModel
757
757
  ): Promise<boolean> {
@@ -859,10 +859,13 @@ export default class Transaction {
859
859
 
860
860
  /**
861
861
  * Serializes this transaction, together with its inputs and the respective merkle proofs, into the BEEF (BRC-62) format. This enables efficient verification of its compliance with the rules of SPV.
862
+ *
863
+ * @param allowPartial If true, error will not be thrown if there are any missing sourceTransactions.
862
864
  *
863
865
  * @returns The serialized BEEF structure
866
+ * @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
864
867
  */
865
- toBEEF(): number[] {
868
+ toBEEF (allowPartial?: boolean): number[] {
866
869
  const writer = new Writer()
867
870
  writer.writeUInt32LE(4022206465)
868
871
  const BUMPs: MerklePath[] = []
@@ -907,10 +910,10 @@ export default class Transaction {
907
910
  if (!hasProof) {
908
911
  for (let i = 0; i < tx.inputs.length; i++) {
909
912
  const input = tx.inputs[i]
910
- if (typeof input.sourceTransaction !== 'object') {
913
+ if (typeof input.sourceTransaction === 'object')
914
+ addPathsAndInputs(input.sourceTransaction)
915
+ else if (!allowPartial)
911
916
  throw new Error('A required source transaction is missing!')
912
- }
913
- addPathsAndInputs(input.sourceTransaction)
914
917
  }
915
918
  }
916
919
  }
@@ -940,16 +943,19 @@ export default class Transaction {
940
943
  * and then the BEEF data containing only the subject transaction and its dependencies.
941
944
  * This format ensures that the BEEF structure is atomic and contains no unrelated transactions.
942
945
  *
946
+ * @param allowPartial If true, error will not be thrown if there are any missing sourceTransactions.
947
+ *
943
948
  * @returns {number[]} - The serialized Atomic BEEF structure.
949
+ * @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
944
950
  */
945
- toAtomicBEEF(): number[] {
951
+ toAtomicBEEF (allowPartial?: boolean): number[] {
946
952
  const writer = new Writer()
947
953
  // Write the Atomic BEEF prefix
948
954
  writer.writeUInt32LE(0x01010101)
949
955
  // Write the subject TXID (big-endian)
950
- writer.write(this.id() as number[])
956
+ writer.write(this.id())
951
957
  // Append the BEEF data
952
- const beefData = this.toBEEF()
958
+ const beefData = this.toBEEF(allowPartial)
953
959
  writer.write(beefData)
954
960
  return writer.toArray()
955
961
  }
@@ -1,9 +1,17 @@
1
+ // The following imports allow flag a large number type checking errors by the VsCode editor due to missing type information:
1
2
  import BeefTx from "../../../dist/cjs/src/transaction/BeefTx"
2
3
  import Beef from "../../../dist/cjs/src/transaction/Beef"
3
4
  import BeefParty from "../../../dist/cjs/src/transaction/BeefParty"
4
5
  import { BEEF_MAGIC, BEEF_MAGIC_V2 } from "../../../dist/cjs/src/transaction/Beef"
5
6
  import Transaction from "../../../dist/cjs/src/transaction/Transaction"
6
7
 
8
+ // The following imports allow full type checking by the VsCode editor, but tests will fail to run:
9
+ //import BeefTx from '../BeefTx'
10
+ //import Beef from '../Beef'
11
+ //import BeefParty from "../BeefParty"
12
+ //import { BEEF_MAGIC, BEEF_MAGIC_V2 } from "../Beef"
13
+ //import Transaction from "../Transaction"
14
+
7
15
  describe('Beef tests', () => {
8
16
  jest.setTimeout(99999999)
9
17
 
@@ -56,8 +64,8 @@ describe('Beef tests', () => {
56
64
  expect(btx.rawTx).toBe(undefined)
57
65
  }
58
66
 
59
- const missing = beef.sortTxs()
60
- expect(missing.length).toBe(0)
67
+ const r = beef.sortTxs()
68
+ expect(r.missingInputs.length).toBe(0)
61
69
  expect(beef.toLogString()).toBe(log2)
62
70
 
63
71
  {
@@ -72,8 +80,8 @@ describe('Beef tests', () => {
72
80
  {
73
81
  const beef = new Beef()
74
82
  beef.mergeTransaction(Transaction.fromHex(txs[0]))
75
- const missing = beef.sortTxs()
76
- expect(missing).toEqual(['bd4a39c6dce3bdd982be3c67eb04b83934fd431f8bcb64f9da4413c91c634d07'])
83
+ const { missingInputs } = beef.sortTxs()
84
+ expect(missingInputs).toEqual(['bd4a39c6dce3bdd982be3c67eb04b83934fd431f8bcb64f9da4413c91c634d07'])
77
85
  const beef0 = Beef.fromString(beefs[0])
78
86
  beef.mergeBump(beef0.bumps[0])
79
87
  beef.mergeRawTx(beef0.txs[0].rawTx!, undefined)
@@ -215,10 +223,10 @@ describe('Beef tests', () => {
215
223
  const v = bp.getTrimmedBeefForParty('a').toLogString()
216
224
  expect(v).toBe(`BEEF with 0 BUMPS and 2 Transactions, isValid false
217
225
  TX 0
218
- txid: 4
226
+ txid: 3
219
227
  txidOnly
220
228
  TX 1
221
- txid: 3
229
+ txid: 4
222
230
  txidOnly
223
231
  `)
224
232
  }
@@ -226,10 +234,10 @@ describe('Beef tests', () => {
226
234
  const v = bp.getTrimmedBeefForParty('b').toLogString()
227
235
  expect(v).toBe(`BEEF with 0 BUMPS and 2 Transactions, isValid false
228
236
  TX 0
229
- txid: 2
237
+ txid: 1
230
238
  txidOnly
231
239
  TX 1
232
- txid: 1
240
+ txid: 2
233
241
  txidOnly
234
242
  `)
235
243
  }
@@ -237,15 +245,52 @@ describe('Beef tests', () => {
237
245
  const v = bp.getTrimmedBeefForParty('c').toLogString()
238
246
  expect(v).toBe(`BEEF with 0 BUMPS and 2 Transactions, isValid false
239
247
  TX 0
240
- txid: 4
248
+ txid: 1
241
249
  txidOnly
242
250
  TX 1
243
- txid: 1
251
+ txid: 4
244
252
  txidOnly
245
253
  `)
246
254
  }
247
255
  })
248
256
 
257
+ test('5_AtomicBeef', async () => {
258
+ {
259
+ const beef = Beef.fromString(beefs[0])
260
+ expect(beef.toHex()).toBe(beefs[0])
261
+ const sr = beef.sortTxs()
262
+ const beefHex = beef.toHex()
263
+ const tx = beef.txs[beef.txs.length - 1].tx!
264
+ expect(tx).toBeTruthy()
265
+ const atomic = tx.toAtomicBEEF(true)
266
+ // Verify that atomic BEEF can be deserialized.
267
+ const beef2 = Beef.fromBinary(atomic)
268
+ // The merkle path isn't linked to tx by default.
269
+ expect(beef2.toHex()).not.toBe(beefHex)
270
+ {
271
+ const atx = beef.findAtomicTransaction(tx.id('hex'))
272
+ const atomic = atx.toAtomicBEEF(true)
273
+ // Verify that atomic BEEF can be deserialized.
274
+ const beef2 = Beef.fromBinary(atomic)
275
+ // The merkle path now is linked to tx by default.
276
+ expect(beef2.toHex()).toBe(beefHex)
277
+ }
278
+ }
279
+ {
280
+ const beef = Beef.fromString(beefs[0])
281
+ expect(beef.toHex()).toBe(beefs[0])
282
+ beef.mergeTransaction(Transaction.fromHex(txs[0]))
283
+ const sr = beef.sortTxs()
284
+ const beefHex = beef.toHex()
285
+ const tx = beef.txs[beef.txs.length - 1].tx!
286
+ expect(tx).toBeTruthy()
287
+ const atx = beef.findAtomicTransaction(tx.id('hex'))
288
+ const atomic = atx.toAtomicBEEF()
289
+ // Verify that atomic BEEF can be deserialized.
290
+ const beef2 = Beef.fromBinary(atomic)
291
+ expect(beef2.toHex()).toBe(beefHex)
292
+ }
293
+ })
249
294
  })
250
295
 
251
296
  const txs: string[] = [