@vbyte/btc-dev 1.1.8 → 2.1.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 (181) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/LICENSE +21 -121
  3. package/README.md +69 -3
  4. package/dist/const.d.ts +3 -0
  5. package/dist/const.js +23 -22
  6. package/dist/error.d.ts +11 -0
  7. package/dist/error.js +20 -0
  8. package/dist/index.d.ts +12 -11
  9. package/dist/index.js +11 -10
  10. package/dist/lib/address/api.d.ts +2 -2
  11. package/dist/lib/address/api.js +13 -12
  12. package/dist/lib/address/encode.d.ts +1 -1
  13. package/dist/lib/address/encode.js +26 -24
  14. package/dist/lib/address/index.d.ts +6 -6
  15. package/dist/lib/address/index.js +6 -6
  16. package/dist/lib/address/p2pkh.d.ts +2 -2
  17. package/dist/lib/address/p2pkh.js +15 -15
  18. package/dist/lib/address/p2sh.d.ts +2 -2
  19. package/dist/lib/address/p2sh.js +14 -14
  20. package/dist/lib/address/p2tr.d.ts +2 -2
  21. package/dist/lib/address/p2tr.js +14 -14
  22. package/dist/lib/address/p2wpkh.d.ts +2 -2
  23. package/dist/lib/address/p2wpkh.js +15 -15
  24. package/dist/lib/address/p2wsh.d.ts +2 -2
  25. package/dist/lib/address/p2wsh.js +14 -14
  26. package/dist/lib/address/script.d.ts +1 -1
  27. package/dist/lib/address/script.js +16 -16
  28. package/dist/lib/address/util.d.ts +1 -1
  29. package/dist/lib/address/util.js +24 -22
  30. package/dist/lib/meta/index.d.ts +4 -4
  31. package/dist/lib/meta/index.js +4 -4
  32. package/dist/lib/meta/locktime.d.ts +1 -1
  33. package/dist/lib/meta/locktime.js +13 -12
  34. package/dist/lib/meta/ref.js +13 -9
  35. package/dist/lib/meta/scribe.d.ts +2 -2
  36. package/dist/lib/meta/scribe.js +71 -56
  37. package/dist/lib/meta/sequence.d.ts +1 -1
  38. package/dist/lib/meta/sequence.js +21 -19
  39. package/dist/lib/script/decode.d.ts +2 -2
  40. package/dist/lib/script/decode.js +53 -17
  41. package/dist/lib/script/encode.d.ts +1 -1
  42. package/dist/lib/script/encode.js +21 -16
  43. package/dist/lib/script/index.d.ts +5 -13
  44. package/dist/lib/script/index.js +5 -14
  45. package/dist/lib/script/lock.d.ts +2 -2
  46. package/dist/lib/script/lock.js +15 -12
  47. package/dist/lib/script/util.js +4 -4
  48. package/dist/lib/script/words.js +131 -130
  49. package/dist/lib/sighash/index.d.ts +3 -3
  50. package/dist/lib/sighash/index.js +3 -3
  51. package/dist/lib/sighash/segwit.d.ts +2 -2
  52. package/dist/lib/sighash/segwit.js +18 -14
  53. package/dist/lib/sighash/taproot.d.ts +2 -2
  54. package/dist/lib/sighash/taproot.js +27 -23
  55. package/dist/lib/sighash/util.d.ts +2 -2
  56. package/dist/lib/sighash/util.js +8 -7
  57. package/dist/lib/signer/index.d.ts +2 -2
  58. package/dist/lib/signer/index.js +2 -2
  59. package/dist/lib/signer/sign.d.ts +1 -1
  60. package/dist/lib/signer/sign.js +43 -7
  61. package/dist/lib/signer/verify.d.ts +17 -3
  62. package/dist/lib/signer/verify.js +232 -3
  63. package/dist/lib/taproot/cblock.d.ts +1 -1
  64. package/dist/lib/taproot/cblock.js +16 -17
  65. package/dist/lib/taproot/encode.d.ts +1 -1
  66. package/dist/lib/taproot/encode.js +9 -8
  67. package/dist/lib/taproot/index.d.ts +4 -4
  68. package/dist/lib/taproot/index.js +4 -4
  69. package/dist/lib/taproot/parse.d.ts +1 -1
  70. package/dist/lib/taproot/parse.js +15 -15
  71. package/dist/lib/taproot/tree.d.ts +2 -2
  72. package/dist/lib/taproot/tree.js +12 -7
  73. package/dist/lib/tx/create.d.ts +1 -1
  74. package/dist/lib/tx/create.js +28 -12
  75. package/dist/lib/tx/decode.d.ts +2 -2
  76. package/dist/lib/tx/decode.js +52 -17
  77. package/dist/lib/tx/encode.d.ts +2 -2
  78. package/dist/lib/tx/encode.js +13 -16
  79. package/dist/lib/tx/index.d.ts +7 -7
  80. package/dist/lib/tx/index.js +7 -7
  81. package/dist/lib/tx/parse.d.ts +1 -1
  82. package/dist/lib/tx/parse.js +9 -9
  83. package/dist/lib/tx/size.d.ts +2 -2
  84. package/dist/lib/tx/size.js +9 -11
  85. package/dist/lib/tx/util.d.ts +2 -2
  86. package/dist/lib/tx/util.js +22 -20
  87. package/dist/lib/tx/validate.d.ts +1 -1
  88. package/dist/lib/tx/validate.js +37 -9
  89. package/dist/lib/witness/index.d.ts +2 -2
  90. package/dist/lib/witness/index.js +2 -2
  91. package/dist/lib/witness/parse.d.ts +2 -2
  92. package/dist/lib/witness/parse.js +24 -23
  93. package/dist/lib/witness/util.d.ts +2 -2
  94. package/dist/lib/witness/util.js +5 -5
  95. package/dist/main.cjs +3305 -2035
  96. package/dist/main.cjs.map +1 -1
  97. package/dist/module.mjs +3303 -2036
  98. package/dist/module.mjs.map +1 -1
  99. package/dist/package.json +24 -19
  100. package/dist/schema/base.d.ts +1 -1
  101. package/dist/schema/base.js +17 -13
  102. package/dist/schema/index.d.ts +2 -2
  103. package/dist/schema/index.js +2 -2
  104. package/dist/schema/taproot.d.ts +1 -1
  105. package/dist/schema/taproot.js +2 -2
  106. package/dist/schema/tx.d.ts +1 -1
  107. package/dist/schema/tx.js +4 -4
  108. package/dist/script.js +10 -12
  109. package/dist/script.js.map +1 -1
  110. package/dist/types/address.d.ts +4 -4
  111. package/dist/types/index.d.ts +8 -8
  112. package/dist/types/index.js +8 -8
  113. package/dist/types/meta.d.ts +4 -4
  114. package/dist/types/psbt.d.ts +2 -2
  115. package/dist/types/script.d.ts +2 -2
  116. package/dist/types/sighash.d.ts +2 -2
  117. package/dist/types/witness.d.ts +5 -5
  118. package/docs/API.md +1145 -0
  119. package/docs/CONVENTIONS.md +316 -0
  120. package/docs/FAQ.md +396 -0
  121. package/docs/GUIDE.md +1102 -0
  122. package/package.json +24 -19
  123. package/src/const.ts +0 -61
  124. package/src/index.ts +0 -13
  125. package/src/lib/address/api.ts +0 -50
  126. package/src/lib/address/encode.ts +0 -183
  127. package/src/lib/address/index.ts +0 -7
  128. package/src/lib/address/p2pkh.ts +0 -94
  129. package/src/lib/address/p2sh.ts +0 -96
  130. package/src/lib/address/p2tr.ts +0 -91
  131. package/src/lib/address/p2wpkh.ts +0 -94
  132. package/src/lib/address/p2wsh.ts +0 -92
  133. package/src/lib/address/script.ts +0 -63
  134. package/src/lib/address/util.ts +0 -87
  135. package/src/lib/meta/index.ts +0 -4
  136. package/src/lib/meta/locktime.ts +0 -57
  137. package/src/lib/meta/ref.ts +0 -107
  138. package/src/lib/meta/scribe.ts +0 -256
  139. package/src/lib/meta/sequence.ts +0 -146
  140. package/src/lib/script/decode.ts +0 -85
  141. package/src/lib/script/encode.ts +0 -129
  142. package/src/lib/script/index.ts +0 -20
  143. package/src/lib/script/lock.ts +0 -73
  144. package/src/lib/script/util.ts +0 -78
  145. package/src/lib/script/words.ts +0 -182
  146. package/src/lib/sighash/index.ts +0 -3
  147. package/src/lib/sighash/segwit.ts +0 -152
  148. package/src/lib/sighash/taproot.ts +0 -206
  149. package/src/lib/sighash/util.ts +0 -51
  150. package/src/lib/signer/index.ts +0 -2
  151. package/src/lib/signer/sign.ts +0 -39
  152. package/src/lib/signer/verify.ts +0 -88
  153. package/src/lib/taproot/cblock.ts +0 -96
  154. package/src/lib/taproot/encode.ts +0 -49
  155. package/src/lib/taproot/index.ts +0 -4
  156. package/src/lib/taproot/parse.ts +0 -65
  157. package/src/lib/taproot/tree.ts +0 -94
  158. package/src/lib/tx/create.ts +0 -90
  159. package/src/lib/tx/decode.ts +0 -123
  160. package/src/lib/tx/encode.ts +0 -155
  161. package/src/lib/tx/index.ts +0 -7
  162. package/src/lib/tx/parse.ts +0 -69
  163. package/src/lib/tx/size.ts +0 -68
  164. package/src/lib/tx/util.ts +0 -111
  165. package/src/lib/tx/validate.ts +0 -49
  166. package/src/lib/witness/index.ts +0 -2
  167. package/src/lib/witness/parse.ts +0 -127
  168. package/src/lib/witness/util.ts +0 -18
  169. package/src/schema/base.ts +0 -57
  170. package/src/schema/index.ts +0 -2
  171. package/src/schema/taproot.ts +0 -12
  172. package/src/schema/tx.ts +0 -48
  173. package/src/types/address.ts +0 -35
  174. package/src/types/index.ts +0 -8
  175. package/src/types/meta.ts +0 -48
  176. package/src/types/psbt.ts +0 -15
  177. package/src/types/script.ts +0 -18
  178. package/src/types/sighash.ts +0 -16
  179. package/src/types/taproot.ts +0 -41
  180. package/src/types/txdata.ts +0 -85
  181. package/src/types/witness.ts +0 -42
@@ -1,11 +1,13 @@
1
- import { Buff, Stream } from '@vbyte/buff';
2
- import { Assert, ECC } from '@vbyte/micro-lib';
3
- import { parse_witness } from '../../lib/witness/parse.js';
4
- import { encode_tapbranch, encode_tapscript, encode_taptweak, } from './encode.js';
1
+ import { Buff, Stream } from "@vbyte/buff";
2
+ import { Assert } from "@vbyte/util";
3
+ import { ECC } from "@vbyte/crypto";
4
+ import { DecodingError, ValidationError } from "../../error.js";
5
+ import { parse_witness } from "../../lib/witness/parse.js";
6
+ import { encode_tapbranch, encode_tapscript, encode_taptweak, } from "./encode.js";
5
7
  export function parse_taproot_witness(witness) {
6
8
  const { cblock, params, script } = parse_witness(witness);
7
- Assert.exists(cblock, 'cblock is null');
8
- Assert.exists(script, 'script is null');
9
+ Assert.exists(cblock, "cblock is null");
10
+ Assert.exists(script, "script is null");
9
11
  const cblk = parse_cblock(cblock);
10
12
  const target = encode_tapscript(script, cblk.version);
11
13
  let branch = target.hex;
@@ -13,9 +15,9 @@ export function parse_taproot_witness(witness) {
13
15
  branch = encode_tapbranch(branch, leaf).hex;
14
16
  }
15
17
  const tweak = encode_taptweak(cblk.int_key, branch);
16
- const tapkey = ECC.tweak_pubkey(cblk.int_key, tweak, 'bip340');
17
- params.map(e => Buff.bytes(e).hex);
18
- return { cblock: cblk, params, script, tapkey: tapkey.hex, tweak: tweak.hex };
18
+ const tapkey = ECC.tweak_pubkey(cblk.int_key, tweak, "bip340");
19
+ const hexParams = params.map((e) => Buff.bytes(e).hex);
20
+ return { cblock: cblk, params: hexParams, script, tapkey: tapkey.hex, tweak: tweak.hex };
19
21
  }
20
22
  export function parse_cblock(cblock) {
21
23
  const buffer = new Stream(cblock);
@@ -27,21 +29,19 @@ export function parse_cblock(cblock) {
27
29
  path.push(buffer.read(32).hex);
28
30
  }
29
31
  if (buffer.size !== 0) {
30
- throw new Error('Non-empty buffer on control block: ' + String(buffer));
32
+ throw new DecodingError(`control block has ${buffer.size} extra bytes. Expected: 33 + (32 * path_length) bytes`);
31
33
  }
32
34
  return { int_key, path, parity, version };
33
35
  }
34
36
  export function parse_cblock_parity(cbits) {
35
- return (cbits % 2 === 0)
36
- ? [cbits - 0, 0x02]
37
- : [cbits - 1, 0x03];
37
+ return cbits % 2 === 0 ? [cbits, 0x02] : [cbits - 1, 0x03];
38
38
  }
39
39
  export function parse_pubkey_parity(pubkey) {
40
- Assert.size(pubkey, 33, 'invalid pubkey size');
40
+ Assert.ok(Buff.bytes(pubkey).length === 33, "invalid pubkey size");
41
41
  const [parity] = Buff.bytes(pubkey);
42
42
  if (parity === 0x02)
43
43
  return 0;
44
44
  if (parity === 0x03)
45
45
  return 1;
46
- throw new Error('Invalid parity bit: ' + String(parity));
46
+ throw new ValidationError(`invalid pubkey parity prefix: 0x${parity.toString(16)}. Expected 0x02 (even) or 0x03 (odd)`);
47
47
  }
@@ -1,3 +1,3 @@
1
- import type { TapTree, MerkleProof } from '../../types/index.js';
1
+ import type { MerkleProof, TapTree } from "../../types/index.js";
2
2
  export declare function get_merkle_root(leaves: TapTree): string;
3
- export declare function merkleize(taptree: TapTree, target?: string, path?: string[]): MerkleProof;
3
+ export declare function merkleize(taptree: TapTree, target?: string, path?: string[], depth?: number): MerkleProof;
@@ -1,18 +1,23 @@
1
- import { Buff } from '@vbyte/buff';
2
- import { encode_tapbranch } from './encode.js';
1
+ import { Buff } from "@vbyte/buff";
2
+ import { ValidationError } from "../../error.js";
3
+ import { encode_tapbranch } from "./encode.js";
4
+ const MAX_TAPROOT_DEPTH = 128;
3
5
  export function get_merkle_root(leaves) {
4
6
  return merkleize(leaves)[0];
5
7
  }
6
- export function merkleize(taptree, target, path = []) {
8
+ export function merkleize(taptree, target, path = [], depth = 0) {
9
+ if (depth > MAX_TAPROOT_DEPTH) {
10
+ throw new ValidationError(`Taproot tree depth ${depth} exceeds maximum ${MAX_TAPROOT_DEPTH}`, "depth");
11
+ }
7
12
  const leaves = [];
8
13
  const tree = [];
9
14
  if (taptree.length < 1) {
10
- throw new Error('Tree is empty!');
15
+ throw new ValidationError("Taproot tree cannot be empty", "taptree");
11
16
  }
12
17
  for (let i = 0; i < taptree.length; i++) {
13
18
  const bytes = taptree[i];
14
19
  if (Array.isArray(bytes)) {
15
- let [tapleaf, new_target, branches] = merkleize(bytes, target);
20
+ const [tapleaf, new_target, branches] = merkleize(bytes, target, [], depth + 1);
16
21
  target = new_target;
17
22
  leaves.push(tapleaf);
18
23
  for (const branch of branches) {
@@ -34,7 +39,7 @@ export function merkleize(taptree, target, path = []) {
34
39
  for (let i = 0; i < leaves.length - 1; i += 2) {
35
40
  const branch = encode_tapbranch(leaves[i], leaves[i + 1]).hex;
36
41
  tree.push(branch);
37
- if (typeof target === 'string') {
42
+ if (typeof target === "string") {
38
43
  if (target === leaves[i]) {
39
44
  path.push(leaves[i + 1]);
40
45
  target = branch;
@@ -45,5 +50,5 @@ export function merkleize(taptree, target, path = []) {
45
50
  }
46
51
  }
47
52
  }
48
- return merkleize(tree, target, path);
53
+ return merkleize(tree, target, path, depth + 1);
49
54
  }
@@ -1,4 +1,4 @@
1
- import type { TxData, TxInput, TxOutput, TxTemplate, TxSpendInput, TxCoinbaseInput, TxOutputTemplate, TxVirtualInput, TxInputTemplate } from '../../types/index.js';
1
+ import type { TxCoinbaseInput, TxData, TxInput, TxInputTemplate, TxOutput, TxOutputTemplate, TxSpendInput, TxTemplate, TxVirtualInput } from "../../types/index.js";
2
2
  export declare function create_coinbase_input(config: TxInputTemplate): TxCoinbaseInput;
3
3
  export declare function create_virtual_input(config: TxInputTemplate): TxVirtualInput;
4
4
  export declare function create_spend_input(config: TxInputTemplate): TxSpendInput;
@@ -1,28 +1,44 @@
1
- import { Assert } from '@vbyte/micro-lib';
2
- import { COINBASE, DEFAULT } from '../../const.js';
3
- import { normalize_prevout, normalize_sequence, normalize_value } from './util.js';
4
- import { assert_tx_template, assert_vin_template, assert_vout_template } from './validate.js';
1
+ import { Assert } from "@vbyte/util";
2
+ import { COINBASE, DEFAULT } from "../../const.js";
3
+ import { normalize_prevout, normalize_sequence, normalize_value, } from "./util.js";
4
+ import { assert_tx_template, assert_vin_template, assert_vout_template, } from "./validate.js";
5
5
  export function create_coinbase_input(config) {
6
6
  assert_vin_template(config);
7
- Assert.exists(config.coinbase, 'coinbase is required');
7
+ Assert.exists(config.coinbase, "coinbase is required");
8
8
  const txid = COINBASE.TXID;
9
9
  const vout = COINBASE.VOUT;
10
10
  const coinbase = config.coinbase;
11
11
  const witness = config.witness ?? [];
12
12
  const sequence = normalize_sequence(config.sequence);
13
- return { coinbase, prevout: null, script_sig: null, sequence, witness, txid, vout };
13
+ return {
14
+ coinbase,
15
+ prevout: null,
16
+ script_sig: null,
17
+ sequence,
18
+ witness,
19
+ txid,
20
+ vout,
21
+ };
14
22
  }
15
23
  export function create_virtual_input(config) {
16
24
  assert_vin_template(config);
17
- Assert.is_empty(config.coinbase, 'coinbase is not allowed');
18
- Assert.is_empty(config.prevout, 'prevout is not allowed');
25
+ Assert.is_empty(config.coinbase, "coinbase is not allowed");
26
+ Assert.is_empty(config.prevout, "prevout is not allowed");
19
27
  const { txid, vout, script_sig = null, witness = [] } = config;
20
28
  const sequence = normalize_sequence(config.sequence);
21
- return { txid, vout, coinbase: null, prevout: null, script_sig, sequence, witness };
29
+ return {
30
+ txid,
31
+ vout,
32
+ coinbase: null,
33
+ prevout: null,
34
+ script_sig,
35
+ sequence,
36
+ witness,
37
+ };
22
38
  }
23
39
  export function create_spend_input(config) {
24
40
  assert_vin_template(config);
25
- Assert.exists(config.prevout, 'prevout is required');
41
+ Assert.exists(config.prevout, "prevout is required");
26
42
  const { txid, vout, script_sig = null, witness = [] } = config;
27
43
  const prevout = normalize_prevout(config.prevout);
28
44
  const sequence = normalize_sequence(config.sequence);
@@ -46,7 +62,7 @@ export function create_tx(config) {
46
62
  const { vin = [], vout = [] } = config ?? { vin: [], vout: [] };
47
63
  const locktime = config.locktime ?? DEFAULT.LOCKTIME;
48
64
  const version = config.version ?? DEFAULT.VERSION;
49
- const inputs = vin.map(txin => create_tx_input(txin));
50
- const outputs = vout.map(txout => create_tx_output(txout));
65
+ const inputs = vin.map((txin) => create_tx_input(txin));
66
+ const outputs = vout.map((txout) => create_tx_output(txout));
51
67
  return { locktime, vin: inputs, vout: outputs, version };
52
68
  }
@@ -1,4 +1,4 @@
1
- import { Stream } from '@vbyte/buff';
2
- import { TxDecodedData } from '../../types/index.js';
1
+ import { Stream } from "@vbyte/buff";
2
+ import type { TxDecodedData } from "../../types/index.js";
3
3
  export declare function decode_tx(txdata: string | Uint8Array, use_segwit?: boolean): TxDecodedData;
4
4
  export declare function read_payload(stream: Stream): string | null;
@@ -1,13 +1,19 @@
1
- import { Stream } from '@vbyte/buff';
2
- import { Assert } from '@vbyte/micro-lib/assert';
3
- import { parse_error } from '@vbyte/micro-lib/util';
4
- import { COINBASE } from '../../const.js';
1
+ import { Stream } from "@vbyte/buff";
2
+ import { Assert } from "@vbyte/util";
3
+ import { COINBASE, MAX_VARINT_SIZE } from "../../const.js";
4
+ import { DecodingError } from "../../error.js";
5
+ const MAX_TX_SIZE = 4_000_000;
6
+ const MAX_TX_ELEMENTS = 100_000;
5
7
  export function decode_tx(txdata, use_segwit = true) {
6
- Assert.is_bytes(txdata, 'txdata must be hex or bytes');
8
+ Assert.ok(typeof txdata === "string" || txdata instanceof Uint8Array, "txdata must be hex or bytes");
9
+ const txSize = typeof txdata === "string" ? txdata.length / 2 : txdata.length;
10
+ if (txSize > MAX_TX_SIZE) {
11
+ throw new DecodingError(`Transaction size ${txSize} exceeds maximum ${MAX_TX_SIZE} bytes`);
12
+ }
7
13
  const stream = new Stream(txdata);
8
14
  const version = read_version(stream);
9
15
  let has_witness = check_witness_flag(stream);
10
- has_witness = (use_segwit) ? has_witness : false;
16
+ has_witness = use_segwit ? has_witness : false;
11
17
  const vin = read_inputs(stream);
12
18
  const vout = read_outputs(stream);
13
19
  if (has_witness) {
@@ -29,14 +35,17 @@ function check_witness_flag(stream) {
29
35
  return true;
30
36
  }
31
37
  else {
32
- throw new Error(`Invalid witness flag: ${flag}`);
38
+ throw new DecodingError(`Invalid witness flag: ${flag}`, 1);
33
39
  }
34
40
  }
35
41
  return false;
36
42
  }
37
43
  function read_inputs(stream) {
38
44
  const inputs = [];
39
- const vinCount = stream.varint();
45
+ const vinCount = stream.read_varint();
46
+ if (vinCount > MAX_TX_ELEMENTS) {
47
+ throw new DecodingError(`Input count ${vinCount} exceeds maximum ${MAX_TX_ELEMENTS}`);
48
+ }
40
49
  for (let i = 0; i < vinCount; i++) {
41
50
  const txinput = read_vin(stream);
42
51
  inputs.push(txinput);
@@ -50,21 +59,41 @@ function read_vin(stream) {
50
59
  const sequence = stream.read(4).reverse().num;
51
60
  const witness = [];
52
61
  if (txid === COINBASE.TXID && vout === COINBASE.VOUT) {
53
- return { coinbase: script_sig, prevout: null, script_sig: null, sequence, txid, vout, witness };
62
+ return {
63
+ coinbase: script_sig,
64
+ prevout: null,
65
+ script_sig: null,
66
+ sequence,
67
+ txid,
68
+ vout,
69
+ witness,
70
+ };
54
71
  }
55
72
  else {
56
- return { coinbase: null, prevout: null, script_sig, sequence, txid, vout, witness };
73
+ return {
74
+ coinbase: null,
75
+ prevout: null,
76
+ script_sig,
77
+ sequence,
78
+ txid,
79
+ vout,
80
+ witness,
81
+ };
57
82
  }
58
83
  }
59
84
  function read_outputs(stream) {
60
85
  const outputs = [];
61
- const vcount = stream.varint();
86
+ const vcount = stream.read_varint();
87
+ if (vcount > MAX_TX_ELEMENTS) {
88
+ throw new DecodingError(`Output count ${vcount} exceeds maximum ${MAX_TX_ELEMENTS}`);
89
+ }
62
90
  for (let i = 0; i < vcount; i++) {
63
91
  try {
64
92
  outputs.push(read_vout(stream));
65
93
  }
66
94
  catch (error) {
67
- throw new Error(`failed to decode output: ${i}: ${parse_error(error)}`);
95
+ const message = error instanceof Error ? error.message : String(error);
96
+ throw new DecodingError(`Failed to decode output at index ${i}: ${message}`);
68
97
  }
69
98
  }
70
99
  return outputs;
@@ -72,24 +101,30 @@ function read_outputs(stream) {
72
101
  function read_vout(stream) {
73
102
  const value = stream.read(8).reverse().big;
74
103
  const script_pk = read_payload(stream);
75
- Assert.exists(script_pk, 'failed to decode script_pk');
104
+ Assert.exists(script_pk, "failed to decode script_pk");
76
105
  return { value, script_pk };
77
106
  }
78
107
  function read_witness(stream) {
79
108
  const stack = [];
80
- const count = stream.varint();
109
+ const count = stream.read_varint();
110
+ if (count > MAX_TX_ELEMENTS) {
111
+ throw new DecodingError(`Witness element count ${count} exceeds maximum ${MAX_TX_ELEMENTS}`);
112
+ }
81
113
  for (let i = 0; i < count; i++) {
82
114
  const element = read_payload(stream);
83
115
  if (element === null) {
84
- throw new Error('failed to decode witness element: ' + i);
116
+ throw new DecodingError(`Failed to decode witness element at index ${i}`);
85
117
  }
86
118
  stack.push(element);
87
119
  }
88
120
  return stack;
89
121
  }
90
122
  export function read_payload(stream) {
91
- const size = stream.varint('le');
92
- return (size > 0) ? stream.read(size).hex : null;
123
+ const size = stream.read_varint("le");
124
+ if (size > MAX_VARINT_SIZE) {
125
+ throw new DecodingError(`Payload size ${size} exceeds maximum ${MAX_VARINT_SIZE}`);
126
+ }
127
+ return size > 0 ? stream.read(size).hex : null;
93
128
  }
94
129
  function read_locktime(stream) {
95
130
  return stream.read(4).reverse().to_num();
@@ -1,5 +1,5 @@
1
- import { Buff } from '@vbyte/buff';
2
- import { TxInput, TxOutput, TxData } from '../../types/index.js';
1
+ import { Buff } from "@vbyte/buff";
2
+ import type { TxData, TxInput, TxOutput } from "../../types/index.js";
3
3
  export declare function encode_tx(txdata: TxData, use_segwit?: boolean): Buff;
4
4
  export declare function encode_tx_version(num: number): Buff;
5
5
  export declare function encode_txin_txid(txid: string): Buff;
@@ -1,13 +1,13 @@
1
- import { Buff } from '@vbyte/buff';
2
- import { Assert } from '@vbyte/micro-lib';
3
- import { assert_tx_data } from './validate.js';
4
- import { COINBASE } from '../../const.js';
1
+ import { Buff } from "@vbyte/buff";
2
+ import { Assert } from "@vbyte/util";
3
+ import { COINBASE } from "../../const.js";
4
+ import { assert_tx_data } from "./validate.js";
5
5
  export function encode_tx(txdata, use_segwit = true) {
6
6
  assert_tx_data(txdata);
7
7
  const { version, vin, vout, locktime } = txdata;
8
8
  const buffer = [encode_tx_version(version)];
9
9
  if (use_segwit) {
10
- buffer.push(Buff.hex('0001'));
10
+ buffer.push(Buff.hex("0001"));
11
11
  }
12
12
  buffer.push(encode_tx_inputs(vin));
13
13
  buffer.push(encode_tx_outputs(vout));
@@ -32,7 +32,7 @@ export function encode_txin_sequence(sequence) {
32
32
  return Buff.num(sequence, 4).reverse();
33
33
  }
34
34
  export function encode_tx_inputs(vin) {
35
- const raw = [Buff.varint(vin.length, 'le')];
35
+ const raw = [Buff.create_varint(vin.length, "le")];
36
36
  for (const input of vin) {
37
37
  raw.push(encode_vin(input));
38
38
  }
@@ -44,7 +44,7 @@ export function encode_vin(txin) {
44
44
  encode_txin_txid(COINBASE.TXID),
45
45
  encode_txin_vout(COINBASE.VOUT),
46
46
  encode_script_data(txin.coinbase),
47
- encode_txin_sequence(txin.sequence)
47
+ encode_txin_sequence(txin.sequence),
48
48
  ]);
49
49
  }
50
50
  else {
@@ -52,7 +52,7 @@ export function encode_vin(txin) {
52
52
  encode_txin_txid(txin.txid),
53
53
  encode_txin_vout(txin.vout),
54
54
  encode_script_data(txin.script_sig),
55
- encode_txin_sequence(txin.sequence)
55
+ encode_txin_sequence(txin.sequence),
56
56
  ]);
57
57
  }
58
58
  }
@@ -60,7 +60,7 @@ export function encode_vout_value(value) {
60
60
  return Buff.big(value, 8).reverse();
61
61
  }
62
62
  export function encode_tx_outputs(vout) {
63
- const buffer = [Buff.varint(vout.length, 'le')];
63
+ const buffer = [Buff.create_varint(vout.length, "le")];
64
64
  for (const output of vout) {
65
65
  buffer.push(encode_tx_vout(output));
66
66
  }
@@ -68,13 +68,10 @@ export function encode_tx_outputs(vout) {
68
68
  }
69
69
  export function encode_tx_vout(txout) {
70
70
  const { value, script_pk } = txout;
71
- return Buff.join([
72
- encode_vout_value(value),
73
- encode_script_data(script_pk)
74
- ]);
71
+ return Buff.join([encode_vout_value(value), encode_script_data(script_pk)]);
75
72
  }
76
73
  export function encode_vin_witness(data) {
77
- const buffer = [Buff.varint(data.length)];
74
+ const buffer = [Buff.create_varint(data.length)];
78
75
  for (const param of data) {
79
76
  buffer.push(encode_script_data(param));
80
77
  }
@@ -86,9 +83,9 @@ export function encode_tx_locktime(locktime) {
86
83
  export function encode_script_data(script) {
87
84
  if (script !== null) {
88
85
  Assert.is_hex(script);
89
- return Buff.hex(script).prefix_varint('le');
86
+ return Buff.hex(script).prefix_varint("le");
90
87
  }
91
88
  else {
92
- return Buff.hex('00');
89
+ return Buff.hex("00");
93
90
  }
94
91
  }
@@ -1,7 +1,7 @@
1
- export * from './create.js';
2
- export * from './decode.js';
3
- export * from './encode.js';
4
- export * from './util.js';
5
- export * from './parse.js';
6
- export * from './size.js';
7
- export * from './validate.js';
1
+ export * from "./create.js";
2
+ export * from "./decode.js";
3
+ export * from "./encode.js";
4
+ export * from "./parse.js";
5
+ export * from "./size.js";
6
+ export * from "./util.js";
7
+ export * from "./validate.js";
@@ -1,7 +1,7 @@
1
- export * from './create.js';
2
- export * from './decode.js';
3
- export * from './encode.js';
4
- export * from './util.js';
5
- export * from './parse.js';
6
- export * from './size.js';
7
- export * from './validate.js';
1
+ export * from "./create.js";
2
+ export * from "./decode.js";
3
+ export * from "./encode.js";
4
+ export * from "./parse.js";
5
+ export * from "./size.js";
6
+ export * from "./util.js";
7
+ export * from "./validate.js";
@@ -1,3 +1,3 @@
1
- import type { TxData, TxOutputTemplate } from '../../types/index.js';
1
+ import type { TxData, TxOutputTemplate } from "../../types/index.js";
2
2
  export declare function parse_tx(txdata: unknown, prevouts?: TxOutputTemplate[]): TxData;
3
3
  export declare function serialize_tx(txdata: unknown): Record<string, unknown>;
@@ -1,10 +1,10 @@
1
- import { Assert } from '@vbyte/micro-lib/assert';
2
- import { decode_tx } from './decode.js';
3
- import { assert_tx_template } from './validate.js';
4
- import { create_tx, create_tx_output } from './create.js';
1
+ import { Assert } from "@vbyte/util";
2
+ import { create_tx, create_tx_output } from "./create.js";
3
+ import { decode_tx } from "./decode.js";
4
+ import { assert_tx_template } from "./validate.js";
5
5
  export function parse_tx(txdata, prevouts) {
6
6
  let tx;
7
- if (typeof txdata === 'string' || txdata instanceof Uint8Array) {
7
+ if (typeof txdata === "string" || txdata instanceof Uint8Array) {
8
8
  tx = decode_tx(txdata);
9
9
  }
10
10
  else {
@@ -12,10 +12,10 @@ export function parse_tx(txdata, prevouts) {
12
12
  tx = create_tx(txdata);
13
13
  }
14
14
  if (prevouts) {
15
- Assert.has_items(prevouts, 'prevouts must be a non-empty array');
15
+ Assert.has_items(prevouts, "prevouts must be a non-empty array");
16
16
  for (const [idx, vin] of tx.vin.entries()) {
17
17
  const prevout = prevouts.at(idx);
18
- Assert.exists(prevout, 'prevout not found for input index: ' + idx);
18
+ Assert.exists(prevout, `prevout not found for input index: ${idx}`);
19
19
  vin.prevout = create_tx_output(prevout);
20
20
  }
21
21
  }
@@ -31,14 +31,14 @@ export function serialize_tx(txdata) {
31
31
  if (e.prevout !== null) {
32
32
  vin.push({
33
33
  script_pk: e.prevout.script_pk,
34
- value: Number(e.prevout.value)
34
+ value: String(e.prevout.value),
35
35
  });
36
36
  }
37
37
  }
38
38
  for (const e of tx.vout) {
39
39
  vout.push({
40
40
  script_pk: e.script_pk,
41
- value: Number(e.value)
41
+ value: String(e.value),
42
42
  });
43
43
  }
44
44
  return { version, locktime, vin, vout };
@@ -1,5 +1,5 @@
1
- import { Bytes } from '@vbyte/buff';
2
- import type { TxData, TxInput, TxOutput, TxSize } from '../../types/index.js';
1
+ import { type Bytes } from "@vbyte/buff";
2
+ import type { TxData, TxInput, TxOutput, TxSize } from "../../types/index.js";
3
3
  export declare function get_vsize(bytes: Bytes): number;
4
4
  export declare function get_txsize(txdata: string | TxData): TxSize;
5
5
  export declare function get_vin_size(vin: TxInput[]): number;
@@ -1,19 +1,17 @@
1
- import { Buff } from '@vbyte/buff';
2
- import { parse_tx } from './parse.js';
3
- import { encode_tx, encode_tx_inputs, encode_tx_outputs, encode_tx_vout, encode_vin, encode_vin_witness } from './encode.js';
1
+ import { Buff } from "@vbyte/buff";
2
+ import { encode_tx, encode_tx_inputs, encode_tx_outputs, encode_tx_vout, encode_vin, encode_vin_witness, } from "./encode.js";
3
+ import { parse_tx } from "./parse.js";
4
4
  const WIT_FLAG_BYTES = 2;
5
5
  export function get_vsize(bytes) {
6
6
  const weight = Buff.bytes(bytes).length;
7
- const remain = (weight % 4 > 0) ? 1 : 0;
8
- return Math.ceil(weight / 4) + remain;
7
+ return Math.ceil(weight / 4);
9
8
  }
10
9
  export function get_txsize(txdata) {
11
10
  const json = parse_tx(txdata);
12
11
  const base = encode_tx(json, false).length;
13
12
  const total = encode_tx(json, true).length;
14
13
  const weight = base * 3 + total;
15
- const remain = (weight % 4 > 0) ? 1 : 0;
16
- const vsize = Math.ceil(weight / 4) + remain;
14
+ const vsize = Math.ceil(weight / 4);
17
15
  return { base, total, vsize, weight };
18
16
  }
19
17
  export function get_vin_size(vin) {
@@ -26,10 +24,10 @@ export function get_vout_size(vout) {
26
24
  }
27
25
  export function get_segwit_size(txinputs) {
28
26
  const segwit_data = txinputs
29
- .filter(e => e.witness.length > 0)
30
- .map(e => e.witness);
31
- return WIT_FLAG_BYTES + segwit_data
32
- .reduce((acc, e) => acc + encode_vin_witness(e).length, 0);
27
+ .filter((e) => e.witness.length > 0)
28
+ .map((e) => e.witness);
29
+ return (WIT_FLAG_BYTES +
30
+ segwit_data.reduce((acc, e) => acc + encode_vin_witness(e).length, 0));
33
31
  }
34
32
  export function get_txin_size(txinput) {
35
33
  const bytes = encode_vin(txinput);
@@ -1,5 +1,5 @@
1
- import { Buff } from '@vbyte/buff';
2
- import type { TxData, TxOutput, TxOutputTemplate, TxValue } from '../../types/index.js';
1
+ import { Buff } from "@vbyte/buff";
2
+ import type { TxData, TxOutput, TxOutputTemplate, TxValue } from "../../types/index.js";
3
3
  export declare function transcode_tx(txdata: string | Uint8Array, use_segwit?: boolean): Buff;
4
4
  export declare function get_txid(txdata: string | Uint8Array | TxData): string;
5
5
  export declare function get_txhash(txdata: string | Uint8Array | TxData): string;
@@ -1,12 +1,11 @@
1
- import { Buff } from '@vbyte/buff';
2
- import { Test } from '@vbyte/micro-lib';
3
- import { Assert } from '@vbyte/micro-lib/assert';
4
- import { hash256 } from '@vbyte/micro-lib/hash';
5
- import { decode_tx } from './decode.js';
6
- import { encode_tx } from './encode.js';
7
- import { parse_tx } from './parse.js';
8
- import { assert_tx_template } from './validate.js';
9
- import { DEFAULT } from '../../const.js';
1
+ import { Buff } from "@vbyte/buff";
2
+ import { Assert, Test } from "@vbyte/util";
3
+ import { hash256 } from "@vbyte/crypto/hash";
4
+ import { DEFAULT } from "../../const.js";
5
+ import { decode_tx } from "./decode.js";
6
+ import { encode_tx } from "./encode.js";
7
+ import { parse_tx } from "./parse.js";
8
+ import { assert_tx_template } from "./validate.js";
10
9
  export function transcode_tx(txdata, use_segwit = true) {
11
10
  const decoded = decode_tx(txdata);
12
11
  return encode_tx(decoded, use_segwit);
@@ -16,21 +15,21 @@ export function get_txid(txdata) {
16
15
  if (txdata instanceof Uint8Array) {
17
16
  buffer = transcode_tx(txdata, false);
18
17
  }
19
- else if (typeof txdata === 'object') {
18
+ else if (typeof txdata === "object") {
20
19
  assert_tx_template(txdata);
21
20
  buffer = encode_tx(txdata, false);
22
21
  }
23
- else if (typeof txdata === 'string') {
22
+ else if (typeof txdata === "string") {
24
23
  Assert.is_hex(txdata);
25
24
  buffer = transcode_tx(txdata, false);
26
25
  }
27
26
  else {
28
- throw new TypeError('invalid txdata type: ' + typeof txdata);
27
+ throw new TypeError(`invalid txdata type: ${typeof txdata}`);
29
28
  }
30
29
  return hash256(buffer).reverse().hex;
31
30
  }
32
31
  export function get_txhash(txdata) {
33
- if (typeof txdata === 'object') {
32
+ if (typeof txdata === "object") {
34
33
  assert_tx_template(txdata);
35
34
  txdata = encode_tx(txdata, true);
36
35
  }
@@ -41,13 +40,13 @@ export function get_tx_value(txdata) {
41
40
  assert_tx_template(tx);
42
41
  const vin = tx.vin.reduce((acc, txin) => acc + (txin.prevout?.value ?? 0n), 0n);
43
42
  const vout = tx.vout.reduce((acc, txout) => acc + txout.value, 0n);
44
- const fees = (vin > vout) ? (vin - vout) : 0n;
43
+ const fees = vin > vout ? vin - vout : 0n;
45
44
  return { fees, vin, vout };
46
45
  }
47
46
  export function get_prevouts(txdata) {
48
47
  assert_tx_template(txdata);
49
- const prevouts = txdata.vin.map(e => e.prevout);
50
- Assert.ok(prevouts.every(e => e !== null), 'prevouts missing from tx');
48
+ const prevouts = txdata.vin.map((e) => e.prevout);
49
+ Assert.ok(prevouts.every((e) => e !== null), "prevouts missing from tx");
51
50
  return prevouts;
52
51
  }
53
52
  export function normalize_sequence(sequence) {
@@ -57,15 +56,18 @@ export function normalize_sequence(sequence) {
57
56
  return Buff.hex(sequence, 4).reverse().num;
58
57
  if (Test.is_uint(sequence))
59
58
  return sequence;
60
- throw new Error('invalid sequence value: ' + String(sequence));
59
+ throw new Error(`invalid sequence value: ${String(sequence)}`);
61
60
  }
62
61
  export function normalize_value(value) {
63
62
  if (Test.is_uint(value))
64
63
  return BigInt(value);
65
- if (typeof value === 'bigint')
64
+ if (typeof value === "bigint")
66
65
  return value;
67
- throw new TypeError('invalid output value: ' + String(value));
66
+ throw new TypeError(`invalid output value: ${String(value)}`);
68
67
  }
69
68
  export function normalize_prevout(prevout) {
70
- return { script_pk: prevout.script_pk, value: normalize_value(prevout.value) };
69
+ return {
70
+ script_pk: prevout.script_pk,
71
+ value: normalize_value(prevout.value),
72
+ };
71
73
  }