@bsv/sdk 1.1.24 → 1.1.26

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 (53) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/totp/totp.js +1 -1
  3. package/dist/cjs/src/totp/totp.js.map +1 -1
  4. package/dist/cjs/src/transaction/Beef.js +492 -0
  5. package/dist/cjs/src/transaction/Beef.js.map +1 -0
  6. package/dist/cjs/src/transaction/BeefParty.js +97 -0
  7. package/dist/cjs/src/transaction/BeefParty.js.map +1 -0
  8. package/dist/cjs/src/transaction/BeefTx.js +123 -0
  9. package/dist/cjs/src/transaction/BeefTx.js.map +1 -0
  10. package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
  11. package/dist/cjs/src/transaction/Transaction.js +156 -35
  12. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  13. package/dist/cjs/src/transaction/index.js +7 -1
  14. package/dist/cjs/src/transaction/index.js.map +1 -1
  15. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  16. package/dist/esm/src/totp/totp.js +1 -1
  17. package/dist/esm/src/totp/totp.js.map +1 -1
  18. package/dist/esm/src/transaction/Beef.js +485 -0
  19. package/dist/esm/src/transaction/Beef.js.map +1 -0
  20. package/dist/esm/src/transaction/BeefParty.js +93 -0
  21. package/dist/esm/src/transaction/BeefParty.js.map +1 -0
  22. package/dist/esm/src/transaction/BeefTx.js +121 -0
  23. package/dist/esm/src/transaction/BeefTx.js.map +1 -0
  24. package/dist/esm/src/transaction/MerklePath.js.map +1 -1
  25. package/dist/esm/src/transaction/Transaction.js +156 -35
  26. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  27. package/dist/esm/src/transaction/index.js +3 -0
  28. package/dist/esm/src/transaction/index.js.map +1 -1
  29. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  30. package/dist/types/src/transaction/Beef.d.ts +143 -0
  31. package/dist/types/src/transaction/Beef.d.ts.map +1 -0
  32. package/dist/types/src/transaction/BeefParty.d.ts +62 -0
  33. package/dist/types/src/transaction/BeefParty.d.ts.map +1 -0
  34. package/dist/types/src/transaction/BeefTx.d.ts +35 -0
  35. package/dist/types/src/transaction/BeefTx.d.ts.map +1 -0
  36. package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
  37. package/dist/types/src/transaction/Transaction.d.ts +44 -4
  38. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  39. package/dist/types/src/transaction/index.d.ts +3 -0
  40. package/dist/types/src/transaction/index.d.ts.map +1 -1
  41. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  42. package/docs/primitives.md +372 -55
  43. package/docs/transaction.md +531 -5
  44. package/package.json +1 -1
  45. package/src/totp/totp.ts +1 -1
  46. package/src/transaction/Beef.ts +533 -0
  47. package/src/transaction/BeefParty.ts +100 -0
  48. package/src/transaction/BeefTx.ts +121 -0
  49. package/src/transaction/MerklePath.ts +11 -11
  50. package/src/transaction/Transaction.ts +196 -59
  51. package/src/transaction/__tests/Beef.test.ts +290 -0
  52. package/src/transaction/__tests/Transaction.test.ts +222 -3
  53. package/src/transaction/index.ts +3 -0
@@ -12,6 +12,7 @@ import Spend from '../script/Spend.js'
12
12
  import ChainTracker from './ChainTracker.js'
13
13
  import { defaultBroadcaster } from './broadcasters/DefaultBroadcaster.js'
14
14
  import { defaultChainTracker } from './chaintrackers/DefaultChainTracker.js'
15
+ import { BEEF_MAGIC } from './Beef.js'
15
16
 
16
17
  /**
17
18
  * Represents a complete Bitcoin transaction. This class encapsulates all the details
@@ -30,7 +31,7 @@ import { defaultChainTracker } from './chaintrackers/DefaultChainTracker.js'
30
31
  * earliest time or block height at which the transaction can be added to the block chain.
31
32
  * @property {Record<string, any>} metadata - A key-value store for attaching additional data to
32
33
  * the transaction object, not included in the transaction itself. Useful for adding descriptions, internal reference numbers, or other information.
33
- * @property {MerkleProof} [merkleProof] - Optional. A merkle proof demonstrating the transaction's
34
+ * @property {MerkleProof} [merklePath] - Optional. A merkle proof demonstrating the transaction's
34
35
  * inclusion in a block. Useful for transaction verification using SPV.
35
36
  *
36
37
  * @example
@@ -59,44 +60,109 @@ export default class Transaction {
59
60
 
60
61
  /**
61
62
  * Creates a new transaction, linked to its inputs and their associated merkle paths, from a BEEF (BRC-62) structure.
62
- * @param beef A binary representation of a transaction in BEEF format.
63
+ * Optionally, you can provide a specific TXID to retrieve a particular transaction from the BEEF data.
64
+ * If the TXID is provided but not found in the BEEF data, an error will be thrown.
65
+ * If no TXID is provided, the last transaction in the BEEF data is returned.
66
+ * @param beef A binary representation of transactions in BEEF format.
67
+ * @param txid Optional TXID of the transaction to retrieve from the BEEF data.
63
68
  * @returns An anchored transaction, linked to its associated inputs populated with merkle paths.
64
69
  */
65
- static fromBEEF (beef: number[]): Transaction {
70
+ static fromBEEF(beef: number[], txid?: string): Transaction {
66
71
  const reader = new Reader(beef)
67
- // Read the version
68
- const version = reader.readUInt32LE()
69
- if (version !== 4022206465) {
70
- throw new Error(`Invalid BEEF version. Expected 4022206465, received ${version}.`)
72
+ const { transactions, BUMPs } = Transaction.parseBEEFData(reader)
73
+
74
+ // The last transaction in the BEEF data can be used if txid is not provided
75
+ const txids = Object.keys(transactions)
76
+ const lastTXID = txids[txids.length - 1]
77
+ const targetTXID = txid || lastTXID
78
+
79
+ if (!transactions[targetTXID]) {
80
+ throw new Error(`Transaction with TXID ${targetTXID} not found in BEEF data.`)
71
81
  }
72
82
 
73
- // Read the BUMPs
74
- const numberOfBUMPs = reader.readVarIntNum()
75
- const BUMPs = []
76
- for (let i = 0; i < numberOfBUMPs; i++) {
77
- BUMPs.push(MerklePath.fromReader(reader))
83
+ // Recursive function for adding merkle proofs or input transactions
84
+ const addPathOrInputs = (obj: { pathIndex?: number, tx: Transaction }): void => {
85
+ if (typeof obj.pathIndex === 'number') {
86
+ const path = BUMPs[obj.pathIndex]
87
+ if (typeof path !== 'object') {
88
+ throw new Error('Invalid merkle path index found in BEEF!')
89
+ }
90
+ obj.tx.merklePath = path
91
+ } else {
92
+ for (let i = 0; i < obj.tx.inputs.length; i++) {
93
+ const input = obj.tx.inputs[i]
94
+ const sourceObj = transactions[input.sourceTXID]
95
+ if (typeof sourceObj !== 'object') {
96
+ throw new Error(`Reference to unknown TXID in BEEF: ${input.sourceTXID}`)
97
+ }
98
+ input.sourceTransaction = sourceObj.tx
99
+ addPathOrInputs(sourceObj)
100
+ }
101
+ }
78
102
  }
79
103
 
80
- // Read all transactions into an object
81
- // The object has keys of TXIDs and values of objects with transactions and BUMP indexes
82
- const numberOfTransactions = reader.readVarIntNum()
83
- const transactions: Record<string, { pathIndex?: number, tx: Transaction }> = {}
84
- let lastTXID: string
85
- for (let i = 0; i < numberOfTransactions; i++) {
86
- const tx = Transaction.fromReader(reader)
87
- const obj: { pathIndex?: number, tx: Transaction } = { tx }
88
- const txid = tx.id('hex')
89
- if (i + 1 === numberOfTransactions) { // The last tXID is stored for later
90
- lastTXID = txid
104
+ addPathOrInputs(transactions[targetTXID])
105
+
106
+ return transactions[targetTXID].tx
107
+ }
108
+
109
+ /**
110
+ * Creates a new transaction from an Atomic BEEF (BRC-95) structure.
111
+ * Extracts the subject transaction and ensures that all transactions within the BEEF data
112
+ * are part of the dependency graph of the subject transaction.
113
+ * Throws errors if the Atomic BEEF data does not strictly adhere to the BRC-95 specification.
114
+ *
115
+ * @param beef A binary representation of an Atomic BEEF structure.
116
+ * @returns The subject transaction, linked to its associated inputs populated with merkle paths.
117
+ */
118
+ static fromAtomicBEEF(beef: number[]): Transaction {
119
+ const reader = new Reader(beef)
120
+ // Read the Atomic BEEF prefix
121
+ const prefix = reader.readUInt32LE()
122
+ if (prefix !== 0x01010101) {
123
+ throw new Error(`Invalid Atomic BEEF prefix. Expected 0x01010101, received ${prefix.toString(16)}.`)
124
+ }
125
+
126
+ // Read the subject TXID
127
+ const subjectTXIDArray = reader.read(32)
128
+ const subjectTXID = toHex(subjectTXIDArray)
129
+
130
+ // The remaining data is the BEEF data
131
+ const beefReader = new Reader(reader.read())
132
+ const { transactions, BUMPs } = Transaction.parseBEEFData(beefReader)
133
+
134
+ // Ensure that the subject transaction exists
135
+ if (!transactions[subjectTXID]) {
136
+ throw new Error(`Subject transaction with TXID ${subjectTXID} not found in Atomic BEEF data.`)
137
+ }
138
+
139
+ // Ensure that all transactions are part of the dependency graph of the subject transaction
140
+ const validTxids = new Set<string>()
141
+ const traverseDependencies = (txid: string) => {
142
+ if (validTxids.has(txid)) {
143
+ return
91
144
  }
92
- const hasBump = Boolean(reader.readUInt8())
93
- if (hasBump) {
94
- obj.pathIndex = reader.readVarIntNum()
145
+ validTxids.add(txid)
146
+ const tx = transactions[txid].tx
147
+ for (const input of tx.inputs) {
148
+ const inputTxid = input.sourceTXID
149
+ if (!transactions[inputTxid]) {
150
+ throw new Error(`Input transaction with TXID ${inputTxid} is missing in Atomic BEEF data.`)
151
+ }
152
+ traverseDependencies(inputTxid)
95
153
  }
96
- transactions[txid] = obj
97
154
  }
98
155
 
99
- // Recursive function for adding merkle proofs or input transactions
156
+ traverseDependencies(subjectTXID)
157
+
158
+ // Check for any unrelated transactions
159
+ for (const txid in transactions) {
160
+ if (!validTxids.has(txid)) {
161
+ throw new Error(`Unrelated transaction with TXID ${txid} found in Atomic BEEF data.`)
162
+ }
163
+ }
164
+
165
+ // Build the transaction by linking inputs and merkle paths
100
166
  const addPathOrInputs = (obj: { pathIndex?: number, tx: Transaction }): void => {
101
167
  if (typeof obj.pathIndex === 'number') {
102
168
  const path = BUMPs[obj.pathIndex]
@@ -109,7 +175,7 @@ export default class Transaction {
109
175
  const input = obj.tx.inputs[i]
110
176
  const sourceObj = transactions[input.sourceTXID]
111
177
  if (typeof sourceObj !== 'object') {
112
- throw new Error(`Reference to unknown TXID in BUMP: ${input.sourceTXID}`)
178
+ throw new Error(`Reference to unknown TXID in BEEF: ${input.sourceTXID}`)
113
179
  }
114
180
  input.sourceTransaction = sourceObj.tx
115
181
  addPathOrInputs(sourceObj)
@@ -117,9 +183,47 @@ export default class Transaction {
117
183
  }
118
184
  }
119
185
 
120
- // Read the final transaction and Add inputs and merkle proofs to the final transaction, returning it
121
- addPathOrInputs(transactions[lastTXID])
122
- return transactions[lastTXID].tx
186
+ addPathOrInputs(transactions[subjectTXID])
187
+
188
+ return transactions[subjectTXID].tx
189
+ }
190
+
191
+ /**
192
+ * Parses BEEF data from a Reader and returns the transactions and BUMPs.
193
+ *
194
+ * @param reader The Reader positioned at the start of BEEF data.
195
+ * @returns An object containing the transactions and BUMPs.
196
+ */
197
+ private static parseBEEFData(reader: Reader): { transactions: Record<string, { pathIndex?: number, tx: Transaction }>, BUMPs: MerklePath[] } {
198
+ // Read the version
199
+ const version = reader.readUInt32LE()
200
+ if (version !== BEEF_MAGIC) {
201
+ throw new Error(`Invalid BEEF version. Expected ${BEEF_MAGIC}, received ${version}.`)
202
+ }
203
+
204
+ // Read the BUMPs
205
+ const numberOfBUMPs = reader.readVarIntNum()
206
+ const BUMPs = []
207
+ for (let i = 0; i < numberOfBUMPs; i++) {
208
+ BUMPs.push(MerklePath.fromReader(reader))
209
+ }
210
+
211
+ // Read all transactions into an object
212
+ // The object has keys of TXIDs and values of objects with transactions and BUMP indexes
213
+ const numberOfTransactions = reader.readVarIntNum()
214
+ const transactions: Record<string, { pathIndex?: number, tx: Transaction }> = {}
215
+ for (let i = 0; i < numberOfTransactions; i++) {
216
+ const tx = Transaction.fromReader(reader)
217
+ const obj: { pathIndex?: number, tx: Transaction } = { tx }
218
+ const txid = tx.id('hex')
219
+ const hasBump = Boolean(reader.readUInt8())
220
+ if (hasBump) {
221
+ obj.pathIndex = reader.readVarIntNum()
222
+ }
223
+ transactions[txid] = obj
224
+ }
225
+
226
+ return { transactions, BUMPs }
123
227
  }
124
228
 
125
229
  /**
@@ -127,7 +231,7 @@ export default class Transaction {
127
231
  * @param ef A binary representation of a transaction in EF format.
128
232
  * @returns An extended transaction, linked to its associated inputs by locking script and satoshis amounts only.
129
233
  */
130
- static fromEF (ef: number[]): Transaction {
234
+ static fromEF(ef: number[]): Transaction {
131
235
  const br = new Reader(ef)
132
236
  const version = br.readUInt32LE()
133
237
  if (toHex(br.read(6)) !== '0000000000ef') throw new Error('Invalid EF marker')
@@ -189,7 +293,7 @@ export default class Transaction {
189
293
  * outputs: { vout: number, offset: number, length: number }[]
190
294
  * }
191
295
  */
192
- static parseScriptOffsets (bin: number[]): {
296
+ static parseScriptOffsets(bin: number[]): {
193
297
  inputs: Array<{ vin: number, offset: number, length: number }>
194
298
  outputs: Array<{ vout: number, offset: number, length: number }>
195
299
  } {
@@ -215,7 +319,7 @@ export default class Transaction {
215
319
  return { inputs, outputs }
216
320
  }
217
321
 
218
- static fromReader (br: Reader): Transaction {
322
+ static fromReader(br: Reader): Transaction {
219
323
  const version = br.readUInt32LE()
220
324
  const inputsLength = br.readVarIntNum()
221
325
  const inputs: TransactionInput[] = []
@@ -256,7 +360,7 @@ export default class Transaction {
256
360
  * @param {number[]} bin - The binary array representation of the transaction.
257
361
  * @returns {Transaction} - A new Transaction instance.
258
362
  */
259
- static fromBinary (bin: number[]): Transaction {
363
+ static fromBinary(bin: number[]): Transaction {
260
364
  const br = new Reader(bin)
261
365
  return Transaction.fromReader(br)
262
366
  }
@@ -268,7 +372,7 @@ export default class Transaction {
268
372
  * @param {string} hex - The hexadecimal string representation of the transaction.
269
373
  * @returns {Transaction} - A new Transaction instance.
270
374
  */
271
- static fromHex (hex: string): Transaction {
375
+ static fromHex(hex: string): Transaction {
272
376
  return Transaction.fromBinary(toArray(hex, 'hex'))
273
377
  }
274
378
 
@@ -279,22 +383,26 @@ export default class Transaction {
279
383
  * @param {string} hex - The hexadecimal string representation of the transaction EF.
280
384
  * @returns {Transaction} - A new Transaction instance.
281
385
  */
282
- static fromHexEF (hex: string): Transaction {
386
+ static fromHexEF(hex: string): Transaction {
283
387
  return Transaction.fromEF(toArray(hex, 'hex'))
284
388
  }
285
389
 
286
390
  /**
287
391
  * Creates a Transaction instance from a hexadecimal string encoded BEEF.
392
+ * Optionally, you can provide a specific TXID to retrieve a particular transaction from the BEEF data.
393
+ * If the TXID is provided but not found in the BEEF data, an error will be thrown.
394
+ * If no TXID is provided, the last transaction in the BEEF data is returned.
288
395
  *
289
396
  * @static
290
397
  * @param {string} hex - The hexadecimal string representation of the transaction BEEF.
398
+ * @param {string} [txid] - Optional TXID of the transaction to retrieve from the BEEF data.
291
399
  * @returns {Transaction} - A new Transaction instance.
292
400
  */
293
- static fromHexBEEF (hex: string): Transaction {
294
- return Transaction.fromBEEF(toArray(hex, 'hex'))
401
+ static fromHexBEEF(hex: string, txid?: string): Transaction {
402
+ return Transaction.fromBEEF(toArray(hex, 'hex'), txid)
295
403
  }
296
404
 
297
- constructor (
405
+ constructor(
298
406
  version: number = 1,
299
407
  inputs: TransactionInput[] = [],
300
408
  outputs: TransactionOutput[] = [],
@@ -316,7 +424,7 @@ export default class Transaction {
316
424
  * @param {TransactionInput} input - The TransactionInput object to add to the transaction.
317
425
  * @throws {Error} - If the input does not have a sourceTXID or sourceTransaction defined.
318
426
  */
319
- addInput (input: TransactionInput): void {
427
+ addInput(input: TransactionInput): void {
320
428
  if (
321
429
  typeof input.sourceTXID === 'undefined' &&
322
430
  typeof input.sourceTransaction === 'undefined'
@@ -336,7 +444,7 @@ export default class Transaction {
336
444
  *
337
445
  * @param {TransactionOutput} output - The TransactionOutput object to add to the transaction.
338
446
  */
339
- addOutput (output: TransactionOutput): void {
447
+ addOutput(output: TransactionOutput): void {
340
448
  this.cachedHash = undefined
341
449
  this.outputs.push(output)
342
450
  }
@@ -346,7 +454,7 @@ export default class Transaction {
346
454
  *
347
455
  * @param {Record<string, any>} metadata - The metadata object to merge into the existing metadata.
348
456
  */
349
- updateMetadata (metadata: Record<string, any>): void {
457
+ updateMetadata(metadata: Record<string, any>): void {
350
458
  this.metadata = {
351
459
  ...this.metadata,
352
460
  ...metadata
@@ -364,7 +472,7 @@ export default class Transaction {
364
472
  *
365
473
  * TODO: Benford's law change distribution.
366
474
  */
367
- async fee (modelOrFee?: FeeModel | number, changeDistribution: 'equal' | 'random' = 'equal'): Promise<void> {
475
+ async fee(modelOrFee?: FeeModel | number, changeDistribution: 'equal' | 'random' = 'equal'): Promise<void> {
368
476
  this.cachedHash = undefined
369
477
  if (typeof modelOrFee === 'undefined') {
370
478
  modelOrFee = new SatoshisPerKilobyte(10)
@@ -425,7 +533,7 @@ export default class Transaction {
425
533
  *
426
534
  * @returns The current transaction fee
427
535
  */
428
- getFee (): number {
536
+ getFee(): number {
429
537
  let totalIn = 0
430
538
  for (const input of this.inputs) {
431
539
  if (typeof input.sourceTransaction !== 'object') {
@@ -443,7 +551,7 @@ export default class Transaction {
443
551
  /**
444
552
  * Signs a transaction, hydrating all its unlocking scripts based on the provided script templates where they are available.
445
553
  */
446
- async sign (): Promise<void> {
554
+ async sign(): Promise<void> {
447
555
  this.cachedHash = undefined
448
556
  for (const out of this.outputs) {
449
557
  if (typeof out.satoshis === 'undefined') {
@@ -474,7 +582,7 @@ export default class Transaction {
474
582
  * @param broadcaster The Broadcaster instance wwhere the transaction will be sent
475
583
  * @returns A BroadcastResponse or BroadcastFailure from the Broadcaster
476
584
  */
477
- async broadcast (broadcaster: Broadcaster = defaultBroadcaster()): Promise<BroadcastResponse | BroadcastFailure> {
585
+ async broadcast(broadcaster: Broadcaster = defaultBroadcaster()): Promise<BroadcastResponse | BroadcastFailure> {
478
586
  return await broadcaster.broadcast(this)
479
587
  }
480
588
 
@@ -483,7 +591,7 @@ export default class Transaction {
483
591
  *
484
592
  * @returns {number[]} - The binary array representation of the transaction.
485
593
  */
486
- toBinary (): number[] {
594
+ toBinary(): number[] {
487
595
  const writer = new Writer()
488
596
  writer.writeUInt32LE(this.version)
489
597
  writer.writeVarIntNum(this.inputs.length)
@@ -515,7 +623,7 @@ export default class Transaction {
515
623
  *
516
624
  * @returns {number[]} - The BRC-30 EF representation of the transaction.
517
625
  */
518
- toEF (): number[] {
626
+ toEF(): number[] {
519
627
  const writer = new Writer()
520
628
  writer.writeUInt32LE(this.version)
521
629
  writer.write([0, 0, 0, 0, 0, 0xef])
@@ -555,7 +663,7 @@ export default class Transaction {
555
663
  *
556
664
  * @returns {string} - The hexadecimal string representation of the transaction EF.
557
665
  */
558
- toHexEF (): string {
666
+ toHexEF(): string {
559
667
  return toHex(this.toEF())
560
668
  }
561
669
 
@@ -564,7 +672,7 @@ export default class Transaction {
564
672
  *
565
673
  * @returns {string} - The hexadecimal string representation of the transaction.
566
674
  */
567
- toHex (): string {
675
+ toHex(): string {
568
676
  return toHex(this.toBinary())
569
677
  }
570
678
 
@@ -573,17 +681,26 @@ export default class Transaction {
573
681
  *
574
682
  * @returns {string} - The hexadecimal string representation of the transaction BEEF.
575
683
  */
576
- toHexBEEF (): string {
684
+ toHexBEEF(): string {
577
685
  return toHex(this.toBEEF())
578
686
  }
579
687
 
688
+ /**
689
+ * Converts the transaction to a hexadecimal string Atomic BEEF.
690
+ *
691
+ * @returns {string} - The hexadecimal string representation of the transaction Atomic BEEF.
692
+ */
693
+ toHexAtomicBEEF(): string {
694
+ return toHex(this.toAtomicBEEF())
695
+ }
696
+
580
697
  /**
581
698
  * Calculates the transaction's hash.
582
699
  *
583
700
  * @param {'hex' | undefined} enc - The encoding to use for the hash. If 'hex', returns a hexadecimal string; otherwise returns a binary array.
584
701
  * @returns {string | number[]} - The hash of the transaction in the specified format.
585
702
  */
586
- hash (enc?: 'hex'): number[] | string {
703
+ hash(enc?: 'hex'): number[] | string {
587
704
  let hash
588
705
  if (this.cachedHash) {
589
706
  hash = this.cachedHash
@@ -602,21 +719,21 @@ export default class Transaction {
602
719
  *
603
720
  * @returns {number[]} - The ID of the transaction in the binary array format.
604
721
  */
605
- id (): number[]
722
+ id(): number[]
606
723
  /**
607
724
  * Calculates the transaction's ID in hexadecimal format.
608
725
  *
609
726
  * @param {'hex'} enc - The encoding to use for the ID. If 'hex', returns a hexadecimal string.
610
727
  * @returns {string} - The ID of the transaction in the hex format.
611
728
  */
612
- id (enc: 'hex'): string
729
+ id(enc: 'hex'): string
613
730
  /**
614
731
  * Calculates the transaction's ID.
615
732
  *
616
733
  * @param {'hex' | undefined} enc - The encoding to use for the ID. If 'hex', returns a hexadecimal string; otherwise returns a binary array.
617
734
  * @returns {string | number[]} - The ID of the transaction in the specified format.
618
735
  */
619
- id (enc?: 'hex'): number[] | string {
736
+ id(enc?: 'hex'): number[] | string {
620
737
  const id = [...this.hash() as number[]]
621
738
  id.reverse()
622
739
  if (enc === 'hex') {
@@ -634,7 +751,7 @@ export default class Transaction {
634
751
  *
635
752
  * @example tx.verify(new WhatsOnChain(), new SatoshisPerKilobyte(1))
636
753
  */
637
- async verify (
754
+ async verify(
638
755
  chainTracker: ChainTracker | 'scripts only' = defaultChainTracker(),
639
756
  feeModel?: FeeModel
640
757
  ): Promise<boolean> {
@@ -745,7 +862,7 @@ export default class Transaction {
745
862
  *
746
863
  * @returns The serialized BEEF structure
747
864
  */
748
- toBEEF (): number[] {
865
+ toBEEF(): number[] {
749
866
  const writer = new Writer()
750
867
  writer.writeUInt32LE(4022206465)
751
868
  const BUMPs: MerklePath[] = []
@@ -816,4 +933,24 @@ export default class Transaction {
816
933
  }
817
934
  return writer.toArray()
818
935
  }
936
+
937
+ /**
938
+ * Serializes this transaction and its inputs into the Atomic BEEF (BRC-95) format.
939
+ * The Atomic BEEF format starts with a 4-byte prefix `0x01010101`, followed by the TXID of the subject transaction,
940
+ * and then the BEEF data containing only the subject transaction and its dependencies.
941
+ * This format ensures that the BEEF structure is atomic and contains no unrelated transactions.
942
+ *
943
+ * @returns {number[]} - The serialized Atomic BEEF structure.
944
+ */
945
+ toAtomicBEEF(): number[] {
946
+ const writer = new Writer()
947
+ // Write the Atomic BEEF prefix
948
+ writer.writeUInt32LE(0x01010101)
949
+ // Write the subject TXID (big-endian)
950
+ writer.write(this.id() as number[])
951
+ // Append the BEEF data
952
+ const beefData = this.toBEEF()
953
+ writer.write(beefData)
954
+ return writer.toArray()
955
+ }
819
956
  }