@vbyte/btc-dev 1.0.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.
Files changed (205) hide show
  1. package/LICENSE +121 -0
  2. package/README.md +5 -0
  3. package/dist/class/index.d.ts +5 -0
  4. package/dist/class/index.js +5 -0
  5. package/dist/class/signer.d.ts +18 -0
  6. package/dist/class/signer.js +32 -0
  7. package/dist/class/tx.d.ts +38 -0
  8. package/dist/class/tx.js +73 -0
  9. package/dist/class/txin.d.ts +29 -0
  10. package/dist/class/txin.js +68 -0
  11. package/dist/class/txout.d.ts +18 -0
  12. package/dist/class/txout.js +38 -0
  13. package/dist/class/witness.d.ts +20 -0
  14. package/dist/class/witness.js +57 -0
  15. package/dist/const.d.ts +22 -0
  16. package/dist/const.js +36 -0
  17. package/dist/index.d.ts +11 -0
  18. package/dist/index.js +10 -0
  19. package/dist/lib/address/encode.d.ts +3 -0
  20. package/dist/lib/address/encode.js +79 -0
  21. package/dist/lib/address/index.d.ts +20 -0
  22. package/dist/lib/address/index.js +21 -0
  23. package/dist/lib/address/p2pkh.d.ts +10 -0
  24. package/dist/lib/address/p2pkh.js +33 -0
  25. package/dist/lib/address/p2sh.d.ts +10 -0
  26. package/dist/lib/address/p2sh.js +33 -0
  27. package/dist/lib/address/p2tr.d.ts +8 -0
  28. package/dist/lib/address/p2tr.js +26 -0
  29. package/dist/lib/address/p2wpkh.d.ts +10 -0
  30. package/dist/lib/address/p2wpkh.js +34 -0
  31. package/dist/lib/address/p2wsh.d.ts +10 -0
  32. package/dist/lib/address/p2wsh.js +33 -0
  33. package/dist/lib/address/script.d.ts +5 -0
  34. package/dist/lib/address/script.js +46 -0
  35. package/dist/lib/address/util.d.ts +4 -0
  36. package/dist/lib/address/util.js +57 -0
  37. package/dist/lib/meta/index.d.ts +2 -0
  38. package/dist/lib/meta/index.js +2 -0
  39. package/dist/lib/meta/pointer.d.ts +42 -0
  40. package/dist/lib/meta/pointer.js +69 -0
  41. package/dist/lib/meta/scribe.d.ts +7 -0
  42. package/dist/lib/meta/scribe.js +192 -0
  43. package/dist/lib/psbt/encoder.d.ts +5 -0
  44. package/dist/lib/psbt/encoder.js +21 -0
  45. package/dist/lib/psbt/index.d.ts +4 -0
  46. package/dist/lib/psbt/index.js +4 -0
  47. package/dist/lib/psbt/meta.d.ts +3 -0
  48. package/dist/lib/psbt/meta.js +11 -0
  49. package/dist/lib/psbt/util.d.ts +5 -0
  50. package/dist/lib/psbt/util.js +44 -0
  51. package/dist/lib/psbt/validate.d.ts +2 -0
  52. package/dist/lib/psbt/validate.js +11 -0
  53. package/dist/lib/script/decode.d.ts +2 -0
  54. package/dist/lib/script/decode.js +55 -0
  55. package/dist/lib/script/encode.d.ts +6 -0
  56. package/dist/lib/script/encode.js +80 -0
  57. package/dist/lib/script/index.d.ts +126 -0
  58. package/dist/lib/script/index.js +17 -0
  59. package/dist/lib/script/util.d.ts +2 -0
  60. package/dist/lib/script/util.js +10 -0
  61. package/dist/lib/script/words.d.ts +116 -0
  62. package/dist/lib/script/words.js +164 -0
  63. package/dist/lib/sighash/index.d.ts +5 -0
  64. package/dist/lib/sighash/index.js +5 -0
  65. package/dist/lib/sighash/segwit.d.ts +3 -0
  66. package/dist/lib/sighash/segwit.js +89 -0
  67. package/dist/lib/sighash/sign.d.ts +3 -0
  68. package/dist/lib/sighash/sign.js +20 -0
  69. package/dist/lib/sighash/taproot.d.ts +9 -0
  70. package/dist/lib/sighash/taproot.js +124 -0
  71. package/dist/lib/sighash/util.d.ts +3 -0
  72. package/dist/lib/sighash/util.js +16 -0
  73. package/dist/lib/sighash/verify.d.ts +1 -0
  74. package/dist/lib/sighash/verify.js +1 -0
  75. package/dist/lib/taproot/cblock.d.ts +3 -0
  76. package/dist/lib/taproot/cblock.js +55 -0
  77. package/dist/lib/taproot/encode.d.ts +6 -0
  78. package/dist/lib/taproot/encode.js +26 -0
  79. package/dist/lib/taproot/index.d.ts +4 -0
  80. package/dist/lib/taproot/index.js +4 -0
  81. package/dist/lib/taproot/parse.d.ts +11 -0
  82. package/dist/lib/taproot/parse.js +47 -0
  83. package/dist/lib/taproot/tree.d.ts +3 -0
  84. package/dist/lib/taproot/tree.js +49 -0
  85. package/dist/lib/tx/create.d.ts +6 -0
  86. package/dist/lib/tx/create.js +54 -0
  87. package/dist/lib/tx/decode.d.ts +9 -0
  88. package/dist/lib/tx/decode.js +109 -0
  89. package/dist/lib/tx/encode.d.ts +15 -0
  90. package/dist/lib/tx/encode.js +94 -0
  91. package/dist/lib/tx/index.d.ts +10 -0
  92. package/dist/lib/tx/index.js +10 -0
  93. package/dist/lib/tx/locktime.d.ts +7 -0
  94. package/dist/lib/tx/locktime.js +37 -0
  95. package/dist/lib/tx/meta.d.ts +8 -0
  96. package/dist/lib/tx/meta.js +48 -0
  97. package/dist/lib/tx/parse.d.ts +2 -0
  98. package/dist/lib/tx/parse.js +12 -0
  99. package/dist/lib/tx/sequence.d.ts +7 -0
  100. package/dist/lib/tx/sequence.js +65 -0
  101. package/dist/lib/tx/size.d.ts +10 -0
  102. package/dist/lib/tx/size.js +48 -0
  103. package/dist/lib/tx/validate.d.ts +7 -0
  104. package/dist/lib/tx/validate.js +21 -0
  105. package/dist/lib/tx/witness.d.ts +3 -0
  106. package/dist/lib/tx/witness.js +85 -0
  107. package/dist/main.cjs +14625 -0
  108. package/dist/main.cjs.map +1 -0
  109. package/dist/module.mjs +14610 -0
  110. package/dist/module.mjs.map +1 -0
  111. package/dist/package.json +106 -0
  112. package/dist/schema/index.d.ts +2 -0
  113. package/dist/schema/index.js +2 -0
  114. package/dist/schema/taproot.d.ts +18 -0
  115. package/dist/schema/taproot.js +9 -0
  116. package/dist/schema/tx.d.ts +278 -0
  117. package/dist/schema/tx.js +35 -0
  118. package/dist/script.js +15 -0
  119. package/dist/script.js.map +1 -0
  120. package/dist/types/address.d.ts +34 -0
  121. package/dist/types/address.js +1 -0
  122. package/dist/types/index.d.ts +9 -0
  123. package/dist/types/index.js +9 -0
  124. package/dist/types/meta.d.ts +10 -0
  125. package/dist/types/meta.js +1 -0
  126. package/dist/types/psbt.d.ts +9 -0
  127. package/dist/types/psbt.js +1 -0
  128. package/dist/types/sighash.d.ts +14 -0
  129. package/dist/types/sighash.js +1 -0
  130. package/dist/types/taproot.d.ts +35 -0
  131. package/dist/types/taproot.js +1 -0
  132. package/dist/types/transaction.d.ts +81 -0
  133. package/dist/types/transaction.js +1 -0
  134. package/dist/types/txdata.d.ts +45 -0
  135. package/dist/types/txdata.js +1 -0
  136. package/dist/types/txmeta.d.ts +19 -0
  137. package/dist/types/txmeta.js +1 -0
  138. package/dist/types/witness.d.ts +30 -0
  139. package/dist/types/witness.js +1 -0
  140. package/package.json +106 -0
  141. package/src/class/index.ts +5 -0
  142. package/src/class/signer.ts +47 -0
  143. package/src/class/tx.ts +118 -0
  144. package/src/class/txin.ts +95 -0
  145. package/src/class/txout.ts +57 -0
  146. package/src/class/witness.ts +85 -0
  147. package/src/const.ts +43 -0
  148. package/src/index.ts +14 -0
  149. package/src/lib/address/encode.ts +183 -0
  150. package/src/lib/address/index.ts +24 -0
  151. package/src/lib/address/p2pkh.ts +65 -0
  152. package/src/lib/address/p2sh.ts +65 -0
  153. package/src/lib/address/p2tr.ts +51 -0
  154. package/src/lib/address/p2wpkh.ts +67 -0
  155. package/src/lib/address/p2wsh.ts +65 -0
  156. package/src/lib/address/script.ts +63 -0
  157. package/src/lib/address/util.ts +102 -0
  158. package/src/lib/meta/index.ts +2 -0
  159. package/src/lib/meta/pointer.ts +107 -0
  160. package/src/lib/meta/scribe.ts +251 -0
  161. package/src/lib/psbt/encoder.ts +24 -0
  162. package/src/lib/psbt/index.ts +4 -0
  163. package/src/lib/psbt/meta.ts +15 -0
  164. package/src/lib/psbt/util.ts +62 -0
  165. package/src/lib/psbt/validate.ts +18 -0
  166. package/src/lib/script/decode.ts +75 -0
  167. package/src/lib/script/encode.ts +130 -0
  168. package/src/lib/script/index.ts +26 -0
  169. package/src/lib/script/util.ts +78 -0
  170. package/src/lib/script/words.ts +182 -0
  171. package/src/lib/sighash/index.ts +5 -0
  172. package/src/lib/sighash/segwit.ts +152 -0
  173. package/src/lib/sighash/sign.ts +35 -0
  174. package/src/lib/sighash/taproot.ts +236 -0
  175. package/src/lib/sighash/util.ts +29 -0
  176. package/src/lib/sighash/verify.ts +83 -0
  177. package/src/lib/taproot/cblock.ts +95 -0
  178. package/src/lib/taproot/encode.ts +49 -0
  179. package/src/lib/taproot/index.ts +4 -0
  180. package/src/lib/taproot/parse.ts +65 -0
  181. package/src/lib/taproot/tree.ts +94 -0
  182. package/src/lib/tx/create.ts +82 -0
  183. package/src/lib/tx/decode.ts +145 -0
  184. package/src/lib/tx/encode.ts +154 -0
  185. package/src/lib/tx/index.ts +10 -0
  186. package/src/lib/tx/locktime.ts +57 -0
  187. package/src/lib/tx/meta.ts +73 -0
  188. package/src/lib/tx/parse.ts +16 -0
  189. package/src/lib/tx/sequence.ts +146 -0
  190. package/src/lib/tx/size.ts +77 -0
  191. package/src/lib/tx/validate.ts +36 -0
  192. package/src/lib/tx/witness.ts +122 -0
  193. package/src/schema/index.ts +2 -0
  194. package/src/schema/taproot.ts +12 -0
  195. package/src/schema/tx.ts +42 -0
  196. package/src/types/address.ts +39 -0
  197. package/src/types/index.ts +9 -0
  198. package/src/types/meta.ts +10 -0
  199. package/src/types/psbt.ts +15 -0
  200. package/src/types/sighash.ts +16 -0
  201. package/src/types/taproot.ts +40 -0
  202. package/src/types/transaction.ts +98 -0
  203. package/src/types/txdata.ts +53 -0
  204. package/src/types/txmeta.ts +25 -0
  205. package/src/types/witness.ts +36 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Bitcoin Transaction Sequence Field Manipulation
3
+ *
4
+ * This module provides functionality for encoding and decoding the sequence field in Bitcoin transactions.
5
+ * The sequence field is a 32-bit integer that can be used for various purposes:
6
+ *
7
+ * 1. Relative timelocks (BIP-68).
8
+ * 2. Custom protocol data.
9
+ *
10
+ * The implementation follows BIP-68 for timelock functionality, and extends it with a custom protocol
11
+ * that allows additional metadata to be encoded in the sequence field (to be used by on-chain indexers).
12
+ */
13
+
14
+ import type { SequenceConfig, SequenceInfo } from '@/types/index.js'
15
+
16
+ /* ===== [ Constants ] ===================================================== */
17
+
18
+ const TIMELOCK_DISABLE = 0x80000000 // Bit 31: When set, disables relative timelock per BIP-68.
19
+ const TIMELOCK_TYPE = 0x00400000 // Bit 22: When set, indicates timestamp-based lock; when clear, indicates block-height-based lock.
20
+ const TIMELOCK_VALUE_MASK = 0x0000FFFF // Bits 0-15: Mask for extracting timelock value (16 bits).
21
+ const TIMELOCK_VALUE_MAX = 0xFFFF // Maximum value for timelock (2^16 - 1).
22
+ const TIMELOCK_GRANULARITY = 512 // Seconds per timestamp unit (BIP-68 specification).
23
+
24
+ /* ===== [ API ] ============================================================ */
25
+
26
+ export namespace Sequence {
27
+ export const encode = encode_sequence
28
+ export const decode = decode_sequence
29
+ }
30
+
31
+ /* ===== [ Encoder ] ======================================================== */
32
+
33
+ /**
34
+ * Encodes a SequenceData object into a 32-bit integer sequence value
35
+ *
36
+ * @param data - The sequence data to encode
37
+ * @returns A 32-bit integer representing the encoded sequence
38
+ * @throws Error if the input data is invalid or exceeds maximum values
39
+ */
40
+ export function encode_sequence (data : SequenceConfig): number {
41
+ // If the timelock is based on a block height,
42
+ if (data.mode === 'height') {
43
+ // Validate the height value.
44
+ const height = parse_height(data.height)
45
+ // For heightlock, only encode the height value (TIMELOCK_TYPE bit remains clear)
46
+ return (height & TIMELOCK_VALUE_MASK) >>> 0
47
+ }
48
+ // If the timelock is based on a timestamp,
49
+ if (data.mode === 'stamp') {
50
+ // Convert timestamp to 512-second granularity units as per BIP-68.
51
+ const stamp = parse_stamp(data.stamp)
52
+ // Set the TIMELOCK_TYPE bit and encode the timestamp value.
53
+ return (TIMELOCK_TYPE | (stamp & TIMELOCK_VALUE_MASK)) >>> 0
54
+ }
55
+ // Throw an error if the mode is unrecognized.
56
+ throw new Error('invalid timelock mode: ' + data.mode)
57
+ }
58
+
59
+ /* ===== [ Decoder ] ========================================================= */
60
+
61
+ /**
62
+ * Decodes a 32-bit sequence value into a SequenceData object
63
+ *
64
+ * @param sequence - The 32-bit sequence value to decode
65
+ * @returns A SequenceData object or null if the sequence doesn't represent special data
66
+ * @throws Error if the sequence value is invalid or exceeds maximum values
67
+ */
68
+ export function decode_sequence (sequence: number | string) : SequenceInfo | null {
69
+ // Parse and validate the sequence value.
70
+ const seq = parse_sequence(sequence)
71
+ // If the sequence is disabled, return null.
72
+ if (seq & TIMELOCK_DISABLE) return null
73
+ // Extract the value.
74
+ const value = seq & TIMELOCK_VALUE_MASK
75
+ // Check for timestamp-based lock (TIMELOCK_TYPE bit is set).
76
+ if (seq & TIMELOCK_TYPE) {
77
+ // Convert granularity units back to seconds for timestamp.
78
+ const stamp = value * TIMELOCK_GRANULARITY
79
+ // Validate the timestamp value.
80
+ if (stamp > 0xFFFFFFFF) {
81
+ throw new Error('Decoded timestamp exceeds 32-bit limit')
82
+ }
83
+ // Return the decoded timelock.
84
+ return { mode: 'stamp', stamp }
85
+ } else {
86
+ // Validate the height value.
87
+ if (value > TIMELOCK_VALUE_MAX) {
88
+ throw new Error('Decoded height exceeds maximum')
89
+ }
90
+ // Return the decoded heightlock.
91
+ return { mode: 'height', height: value }
92
+ }
93
+ }
94
+
95
+ /* ===== [ Helpers ] ========================================================= */
96
+
97
+ /**
98
+ * Parses a sequence value into a number.
99
+ *
100
+ * @param sequence - The sequence value to parse.
101
+ * @returns The parsed sequence value.
102
+ * @throws Error if the sequence value is invalid.
103
+ */
104
+ function parse_sequence (sequence: number | string): number {
105
+ const seq = (typeof sequence === 'string')
106
+ ? parseInt(sequence, 16)
107
+ : sequence
108
+ if (!Number.isInteger(seq) || seq < 0 || seq > 0xFFFFFFFF) {
109
+ throw new Error(`invalid sequence value: ${seq}`)
110
+ }
111
+ return seq
112
+ }
113
+
114
+ /**
115
+ * Parses a timestamp value into a 512-second granularity units.
116
+ *
117
+ * @param stamp - The timestamp value to parse.
118
+ * @returns The parsed timestamp value.
119
+ * @throws Error if the timestamp value is invalid.
120
+ */
121
+ function parse_stamp (stamp? : number) : number {
122
+ if (stamp === undefined || !Number.isInteger(stamp)) {
123
+ throw new Error(`timestamp must be a number`)
124
+ }
125
+ // Convert timestamp to 512-second granularity units as per BIP-68.
126
+ const ts = Math.floor(stamp / TIMELOCK_GRANULARITY)
127
+ // Validate the timestamp value.
128
+ if (!Number.isInteger(ts) || ts < 0 || ts > TIMELOCK_VALUE_MAX) {
129
+ throw new Error(`timelock value must be an integer between 0 and ${TIMELOCK_VALUE_MAX} (in 512-second increments)`)
130
+ }
131
+ return ts
132
+ }
133
+
134
+ /**
135
+ * Parses a height value into a number.
136
+ *
137
+ * @param height - The height value to parse.
138
+ * @returns The parsed height value.
139
+ * @throws Error if the height value is invalid.
140
+ */
141
+ function parse_height (height? : number) : number {
142
+ if (height === undefined || !Number.isInteger(height) || height < 0 || height > TIMELOCK_VALUE_MAX) {
143
+ throw new Error(`Heightlock value must be an integer between 0 and ${TIMELOCK_VALUE_MAX}`)
144
+ }
145
+ return height
146
+ }
@@ -0,0 +1,77 @@
1
+ import { Buff, Bytes } from '@vbyte/buff'
2
+ import { parse_tx_data } from './parse.js'
3
+
4
+ import {
5
+ encode_tx_data,
6
+ encode_tx_inputs,
7
+ encode_tx_outputs,
8
+ encode_tx_vout,
9
+ encode_vin,
10
+ encode_vin_witness
11
+ } from './encode.js'
12
+
13
+ import type {
14
+ TxData,
15
+ TxInput,
16
+ TxOutput,
17
+ TxSize,
18
+ WitnessSize,
19
+ } from '@/types/index.js'
20
+
21
+ const WIT_FLAG_BYTES = 2
22
+ const WIT_LENGTH_BYTE = 1
23
+
24
+ export function get_vsize (
25
+ bytes : Bytes
26
+ ) : number {
27
+ const weight = Buff.bytes(bytes).length
28
+ const remain = (weight % 4 > 0) ? 1 : 0
29
+ return Math.floor(weight / 4) + remain
30
+ }
31
+
32
+ export function get_txsize (
33
+ txdata : string | TxData
34
+ ) : TxSize {
35
+ const json = parse_tx_data(txdata)
36
+ const base = encode_tx_data(json, false).length
37
+ const size = encode_tx_data(json, true).length
38
+ const weight = base * 3 + size
39
+ const remain = (weight % 4 > 0) ? 1 : 0
40
+ const vsize = Math.floor(weight / 4) + remain
41
+ return { base, real: size, vsize, weight }
42
+ }
43
+
44
+ export function get_vin_size (vin : TxInput[]) : number {
45
+ const bytes = encode_tx_inputs(vin)
46
+ return bytes.length
47
+ }
48
+
49
+ export function get_vout_size (vout : TxOutput[]) : number {
50
+ const bytes = encode_tx_outputs(vout)
51
+ return bytes.length
52
+ }
53
+
54
+ export function get_segwit_size (txinputs : TxInput[]) : number {
55
+ const segwit_data = txinputs
56
+ .filter(e => e.witness.length > 0)
57
+ .map(e => e.witness)
58
+ return WIT_FLAG_BYTES + segwit_data
59
+ .reduce((acc, e) => acc + encode_vin_witness(e).length, 0)
60
+ }
61
+
62
+ export function get_txin_size (txinput : TxInput) : number {
63
+ const bytes = encode_vin(txinput)
64
+ return bytes.length
65
+ }
66
+
67
+ export function get_txout_size (txoutput : TxOutput) : number {
68
+ const bytes = encode_tx_vout(txoutput)
69
+ return bytes.length
70
+ }
71
+
72
+ export function get_witness_size (witness : Bytes[]) : WitnessSize {
73
+ const stack = witness.map(e => Buff.bytes(e))
74
+ const size = stack.reduce((prev, next) => prev + next.length, 0)
75
+ const vsize = Math.ceil(WIT_LENGTH_BYTE + size / 4)
76
+ return { size, vsize }
77
+ }
@@ -0,0 +1,36 @@
1
+ import * as Schema from '@/schema/index.js'
2
+
3
+ import {
4
+ SpendInput,
5
+ TxData,
6
+ TxInput,
7
+ TxInputTemplate,
8
+ TxOutput,
9
+ TxTemplate,
10
+ } from '@/types/index.js'
11
+
12
+ export function assert_tx_template (txdata : unknown) : asserts txdata is TxTemplate {
13
+ Schema.tx.tx_template.parse(txdata)
14
+ }
15
+
16
+ export function assert_has_prevouts (vin : TxInput[]) : asserts vin is SpendInput[] {
17
+ if (vin.some(txin => txin.prevout === null)) {
18
+ throw new Error('transaction missing prevouts')
19
+ }
20
+ }
21
+
22
+ export function assert_tx_data (txdata : unknown) : asserts txdata is TxData {
23
+ Schema.tx.tx_data.parse(txdata)
24
+ }
25
+
26
+ export function assert_tx_input (tx_input : unknown) : asserts tx_input is TxInput {
27
+ Schema.tx.tx_input.parse(tx_input)
28
+ }
29
+
30
+ export function assert_tx_output (tx_output : unknown) : asserts tx_output is TxOutput {
31
+ Schema.tx.tx_output.parse(tx_output)
32
+ }
33
+
34
+ export function assert_vin_template (vin_template : unknown) : asserts vin_template is TxInputTemplate {
35
+ Schema.tx.vin_template.parse(vin_template)
36
+ }
@@ -0,0 +1,122 @@
1
+ import { Buff, Bytes } from '@vbyte/buff'
2
+ import { is_valid_script } from '@/lib/script/decode.js'
3
+ import { TAPLEAF_VERSIONS } from '@/const.js'
4
+
5
+ import type {
6
+ WitnessInfo,
7
+ WitnessType
8
+ } from '@/types/index.js'
9
+
10
+ export function parse_witness_data (
11
+ witness : Bytes[]
12
+ ) : WitnessInfo {
13
+ // Parse the witness data.
14
+ const elems = witness.map(e => Buff.bytes(e))
15
+ const annex = parse_annex_data(elems)
16
+ if (annex !== null) elems.pop()
17
+ const cblock = parse_cblock_data(elems)
18
+ if (cblock !== null) elems.pop()
19
+ const type = parse_witness_type(elems, cblock)
20
+ const version = parse_witness_version(type)
21
+ const script = parse_witness_script(elems, type)
22
+ if (script !== null) elems.pop()
23
+ const params = elems.map(e => e.hex)
24
+ return { annex, cblock, params, script, type, version }
25
+ }
26
+
27
+ function parse_annex_data (
28
+ data : Uint8Array[]
29
+ ) : string | null {
30
+ // Get the last element of the array.
31
+ let elem = data.at(-1)
32
+ // Check if the element fits the annex format.
33
+ if (
34
+ data.length > 1 &&
35
+ elem instanceof Uint8Array &&
36
+ elem[0] === 0x50
37
+ ) {
38
+ // Return the element.
39
+ return new Buff(elem).hex
40
+ } else {
41
+ // Return null.
42
+ return null
43
+ }
44
+ }
45
+
46
+ function parse_cblock_data (
47
+ data : Uint8Array[]
48
+ ) : string | null {
49
+ let elem = data.at(-1)
50
+ if (
51
+ data.length > 1 &&
52
+ elem instanceof Uint8Array &&
53
+ elem.length > 32 &&
54
+ TAPLEAF_VERSIONS.includes(elem[0] & 0xfe)
55
+ ) {
56
+ // Return the element.
57
+ return new Buff(elem).hex
58
+ } else {
59
+ // Return null.
60
+ return null
61
+ }
62
+ }
63
+
64
+ function parse_witness_script (
65
+ elems : Uint8Array[],
66
+ type : WitnessType
67
+ ) {
68
+ let script : Uint8Array | undefined
69
+ switch (type) {
70
+ case 'p2tr-ts':
71
+ script = elems.at(-1)
72
+ case 'p2w-sh':
73
+ script = elems.at(-1)
74
+ }
75
+ return (script !== undefined) ? new Buff(script).hex : null
76
+ }
77
+
78
+ function parse_witness_type (
79
+ elems : Uint8Array[],
80
+ cblock : string | null
81
+ ) : WitnessType {
82
+ // Get the important elements of the witness.
83
+ let param_0 = elems.at(0),
84
+ param_1 = elems.at(1),
85
+ param_x = elems.at(-1)
86
+ // If the cblock is present and the last element exists:
87
+ if (cblock !== null && param_x !== undefined) {
88
+ return 'p2tr-ts'
89
+ // If the witness elements match the profile of a p2w-pkh:
90
+ } else if (
91
+ elems.length === 2 &&
92
+ param_0 !== undefined &&
93
+ param_1 !== undefined &&
94
+ param_0.length >= 64 &&
95
+ param_1.length === 33
96
+ ) {
97
+ return 'p2w-pkh'
98
+ // If the witness elements match the profile of a p2tr-pk:
99
+ } else if (
100
+ elems.length === 1 &&
101
+ param_0 !== undefined &&
102
+ param_0.length === 64
103
+ ) {
104
+ return 'p2tr-pk'
105
+ // If there is at least two witness elements:
106
+ } else if (
107
+ elems.length > 1 &&
108
+ param_x !== undefined &&
109
+ is_valid_script(param_x)
110
+ ) {
111
+ return 'p2w-sh'
112
+ // If the witness elements don't match any known profile:
113
+ } else {
114
+ return 'unknown'
115
+ }
116
+ }
117
+
118
+ function parse_witness_version (type : WitnessType) : number | null {
119
+ if (type.startsWith('p2tr')) return 1
120
+ if (type.startsWith('p2w')) return 0
121
+ return null
122
+ }
@@ -0,0 +1,2 @@
1
+ export * as taproot from './taproot.js'
2
+ export * as tx from './tx.js'
@@ -0,0 +1,12 @@
1
+ import { z } from 'zod'
2
+
3
+ import { byte32, uint } from '@vbyte/micro-lib/schema'
4
+
5
+ export const taptree = z.union([ z.array(byte32), byte32 ])
6
+
7
+ export const config = z.object({
8
+ pubkey : byte32,
9
+ leaves : taptree.array().optional(),
10
+ target : byte32.optional(),
11
+ version : uint.optional(),
12
+ })
@@ -0,0 +1,42 @@
1
+ import { z } from 'zod'
2
+
3
+ import { big, hex, hex32, uint } from '@vbyte/micro-lib/schema'
4
+
5
+ export const sats = big.max(2_100_000_000_000_000n)
6
+
7
+ export const tx_output = z.object({
8
+ value : sats,
9
+ script_pk : hex,
10
+ })
11
+
12
+ export const tx_input = z.object({
13
+ coinbase : hex.nullable(),
14
+ txid : hex32,
15
+ vout : uint,
16
+ prevout : tx_output.nullable(),
17
+ script_sig : hex.nullable(),
18
+ sequence : uint,
19
+ witness : z.array(hex)
20
+ })
21
+
22
+ export const tx_data = z.object({
23
+ version : uint,
24
+ vin : z.array(tx_input),
25
+ vout : z.array(tx_output),
26
+ locktime : uint,
27
+ })
28
+
29
+ export const vin_template = tx_input.extend({
30
+ coinbase : hex.nullable().optional(),
31
+ prevout : tx_output.nullable().optional(),
32
+ script_sig : hex.nullable().optional(),
33
+ sequence : uint.optional(),
34
+ witness : z.array(hex).optional(),
35
+ })
36
+
37
+ export const tx_template = z.object({
38
+ version : uint.optional(),
39
+ vin : z.array(vin_template).default([]),
40
+ vout : z.array(tx_output).default([]),
41
+ locktime : uint.optional(),
42
+ })
@@ -0,0 +1,39 @@
1
+ export type AddressFormat = 'base58' | 'bech32' | 'bech32m'
2
+ export type AddressType = 'p2pkh' | 'p2sh' | 'p2w-pkh' | 'p2w-sh' | 'p2tr'
3
+ export type ChainNetwork = 'main' | 'testnet' | 'regtest'
4
+ export type AddressData = AddressContext & ScriptData
5
+
6
+ export type AddressConfigEntry = [
7
+ prefix : string,
8
+ type : AddressType,
9
+ network : ChainNetwork,
10
+ size : number,
11
+ format : AddressFormat,
12
+ version : number
13
+ ]
14
+
15
+ export interface DecodedAddress {
16
+ format : AddressFormat
17
+ data : Uint8Array
18
+ prefix? : string
19
+ version? : number
20
+ }
21
+
22
+ export interface AddressConfig {
23
+ format : AddressFormat
24
+ network : ChainNetwork
25
+ prefix : string
26
+ size : number
27
+ type : AddressType
28
+ version : number
29
+ }
30
+
31
+ export interface AddressContext extends AddressConfig {
32
+ data : Uint8Array
33
+ hex : string
34
+ }
35
+
36
+ export interface ScriptData {
37
+ script_asm : string[]
38
+ script_hex : string
39
+ }
@@ -0,0 +1,9 @@
1
+ export * from './address.js'
2
+ export * from './meta.js'
3
+ export * from './psbt.js'
4
+ export * from './sighash.js'
5
+ export * from './taproot.js'
6
+ export * from './transaction.js'
7
+ export * from './txdata.js'
8
+ export * from './txmeta.js'
9
+ export * from './witness.js'
@@ -0,0 +1,10 @@
1
+ export interface InscriptionData {
2
+ content ?: string
3
+ delegate ?: string
4
+ mimetype ?: string
5
+ opcode ?: number
6
+ parent ?: string
7
+ pointer ?: number
8
+ ref ?: string
9
+ rune ?: string
10
+ }
@@ -0,0 +1,15 @@
1
+ import type { Transaction } from '@scure/btc-signer'
2
+
3
+ import type {
4
+ TransactionInput,
5
+ TransactionOutput
6
+ } from '@scure/btc-signer/psbt'
7
+
8
+ export type PSBTData = Transaction
9
+ export type PSBTInput = TransactionInput
10
+ export type PSBTOutput = TransactionOutput
11
+
12
+ export interface PSBTPrevouts {
13
+ amounts : bigint[]
14
+ scripts : Uint8Array[]
15
+ }
@@ -0,0 +1,16 @@
1
+ import { TxInput } from './txdata.js'
2
+
3
+ export type SigHashType = 'segwit' | 'taproot'
4
+
5
+ export interface SigHashOptions {
6
+ extension ?: string // Extend hash with additional commitment (for taproot).
7
+ extflag ?: number // Set the extention version flag (future use).
8
+ txindex ?: number // Index value of the input you wish to sign for.
9
+ key_version ?: number // Set the key version flag (future use).
10
+ pubkey ?: string // Verify using this pubkey instead of the tapkey.
11
+ script ?: string // Use this script for signing and validation.
12
+ separator_pos ?: number // If using OP_CODESEPARATOR, specify the latest opcode position.
13
+ sigflag ?: number // Set the signature type flag.
14
+ throws ?: boolean // Should throw an exception on failure.
15
+ txinput ?: TxInput // Use this txinput for signing and validation.
16
+ }
@@ -0,0 +1,40 @@
1
+ type Bytes = string | Uint8Array
2
+
3
+ export type TapTree = Array<Bytes | Bytes[]>
4
+
5
+ export type MerkleProof = [
6
+ root : string,
7
+ target : string | undefined,
8
+ path : string[]
9
+ ]
10
+
11
+ export interface TaprootConfig {
12
+ pubkey : Bytes
13
+ leaves ?: TapTree
14
+ target ?: Bytes
15
+ version ?: number
16
+ }
17
+
18
+ export interface TaprootContext {
19
+ cblock : string
20
+ int_key : string
21
+ parity : number
22
+ taproot : string | null
23
+ tapkey : string
24
+ taptweak : string
25
+ }
26
+
27
+ export interface ControlBlock {
28
+ int_key : string
29
+ parity : number
30
+ path : string[]
31
+ version : number
32
+ }
33
+
34
+ export interface ProofData {
35
+ cblock : ControlBlock
36
+ params : string[]
37
+ script : string
38
+ tapkey : string
39
+ tweak : string
40
+ }
@@ -0,0 +1,98 @@
1
+ import { TxOutput } from './txdata.js'
2
+ import { LocktimeInfo, SequenceInfo } from './txmeta.js'
3
+
4
+ import type {
5
+ WitnessType,
6
+ WitnessVersion
7
+ } from './witness.js'
8
+
9
+ export type TxOutputType = WitnessType | 'p2pkh' | 'p2sh' | 'opreturn'
10
+
11
+ export interface TxOutputInfo {
12
+ type : TxOutputType
13
+ version : WitnessVersion
14
+ }
15
+
16
+ export interface TxInputInfo {
17
+ type : WitnessType
18
+ version : WitnessVersion
19
+ }
20
+
21
+ export interface LocktimeField {
22
+ hex : string
23
+ data : LocktimeInfo | null
24
+ value : number
25
+ }
26
+
27
+ export interface SequenceField {
28
+ hex : string
29
+ data : SequenceInfo | null
30
+ value : number
31
+ }
32
+
33
+ export interface ScriptField {
34
+ asm : string[]
35
+ hex : string
36
+ }
37
+
38
+ export interface TxSize {
39
+ base : number
40
+ real : number
41
+ weight : number
42
+ vsize : number
43
+ }
44
+
45
+ export interface TxValue {
46
+ fees : bigint
47
+ vin : bigint
48
+ vout : bigint
49
+ }
50
+
51
+ export interface WitnessSize {
52
+ size : number
53
+ vsize : number
54
+ }
55
+
56
+ export interface TransactionData {
57
+ hash : string
58
+ locktime : LocktimeField
59
+ return : TxOutput | null
60
+ size : TxSize
61
+ spends : TxOutputField[]
62
+ txid : string
63
+ value : TxValue
64
+ version : number
65
+ vin : TxInputField[]
66
+ vout : TxOutputField[]
67
+ }
68
+
69
+ export interface WitnessField {
70
+ annex : string | null
71
+ cblock : string | null
72
+ params : string[]
73
+ script : ScriptField | null
74
+ size : number
75
+ stack : string[]
76
+ type : WitnessType
77
+ version : WitnessVersion
78
+ vsize : number
79
+ }
80
+
81
+ export interface TxInputField {
82
+ coinbase? : string | null
83
+ prevout? : TxOutputField | null
84
+ script_sig? : ScriptField | null
85
+ sequence : SequenceField
86
+ size : number
87
+ txid : string
88
+ vout : number
89
+ witness? : WitnessField | null
90
+ }
91
+
92
+ export interface TxOutputField {
93
+ script_pk : ScriptField
94
+ size : number
95
+ type : TxOutputType
96
+ value : bigint
97
+ version : WitnessVersion | null
98
+ }