@vbyte/btc-dev 1.0.11 → 1.0.13

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 (67) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.js +0 -1
  3. package/dist/lib/sighash/segwit.d.ts +4 -1
  4. package/dist/lib/sighash/segwit.js +6 -6
  5. package/dist/lib/sighash/taproot.d.ts +7 -6
  6. package/dist/lib/sighash/taproot.js +24 -53
  7. package/dist/lib/sighash/util.d.ts +4 -2
  8. package/dist/lib/sighash/util.js +16 -2
  9. package/dist/lib/signer/sign.js +8 -5
  10. package/dist/lib/signer/verify.d.ts +1 -2
  11. package/dist/lib/signer/verify.js +1 -5
  12. package/dist/lib/tx/create.d.ts +7 -6
  13. package/dist/lib/tx/create.js +25 -27
  14. package/dist/lib/tx/decode.d.ts +4 -9
  15. package/dist/lib/tx/decode.js +16 -28
  16. package/dist/lib/tx/encode.d.ts +1 -1
  17. package/dist/lib/tx/encode.js +6 -6
  18. package/dist/lib/tx/parse.d.ts +3 -2
  19. package/dist/lib/tx/parse.js +38 -5
  20. package/dist/lib/tx/util.d.ts +8 -4
  21. package/dist/lib/tx/util.js +39 -15
  22. package/dist/lib/tx/validate.d.ts +4 -2
  23. package/dist/lib/tx/validate.js +9 -2
  24. package/dist/main.cjs +4049 -4230
  25. package/dist/main.cjs.map +1 -1
  26. package/dist/module.mjs +4040 -4216
  27. package/dist/module.mjs.map +1 -1
  28. package/dist/package.json +2 -2
  29. package/dist/schema/taproot.d.ts +2 -2
  30. package/dist/schema/tx.d.ts +53 -40
  31. package/dist/schema/tx.js +9 -6
  32. package/dist/script.js +8 -8
  33. package/dist/script.js.map +1 -1
  34. package/dist/types/txdata.d.ts +17 -1
  35. package/package.json +2 -2
  36. package/src/index.ts +0 -2
  37. package/src/lib/sighash/segwit.ts +6 -6
  38. package/src/lib/sighash/taproot.ts +40 -70
  39. package/src/lib/sighash/util.ts +25 -3
  40. package/src/lib/signer/sign.ts +9 -5
  41. package/src/lib/signer/verify.ts +1 -18
  42. package/src/lib/tx/create.ts +46 -38
  43. package/src/lib/tx/decode.ts +23 -45
  44. package/src/lib/tx/encode.ts +10 -9
  45. package/src/lib/tx/parse.ts +61 -8
  46. package/src/lib/tx/util.ts +57 -20
  47. package/src/lib/tx/validate.ts +15 -2
  48. package/src/schema/tx.ts +10 -6
  49. package/src/types/txdata.ts +20 -1
  50. package/dist/class/index.d.ts +0 -5
  51. package/dist/class/index.js +0 -5
  52. package/dist/class/signer.d.ts +0 -18
  53. package/dist/class/signer.js +0 -34
  54. package/dist/class/tx.d.ts +0 -40
  55. package/dist/class/tx.js +0 -96
  56. package/dist/class/txin.d.ts +0 -29
  57. package/dist/class/txin.js +0 -62
  58. package/dist/class/txout.d.ts +0 -19
  59. package/dist/class/txout.js +0 -37
  60. package/dist/class/witness.d.ts +0 -18
  61. package/dist/class/witness.js +0 -46
  62. package/src/class/index.ts +0 -5
  63. package/src/class/signer.ts +0 -49
  64. package/src/class/tx.ts +0 -136
  65. package/src/class/txin.ts +0 -89
  66. package/src/class/txout.ts +0 -61
  67. package/src/class/witness.ts +0 -75
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from './class/index.js';
2
1
  export * as ADDRESS from './lib/address/index.js';
3
2
  export * as META from './lib/meta/index.js';
4
3
  export * as PSBT from './lib/psbt/index.js';
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- export * from './class/index.js';
2
1
  export * as ADDRESS from './lib/address/index.js';
3
2
  export * as META from './lib/meta/index.js';
4
3
  export * as PSBT from './lib/psbt/index.js';
@@ -1,3 +1,6 @@
1
1
  import { Buff } from '@vbyte/buff';
2
- import { SigHashOptions, TxData } from '../../types/index.js';
2
+ import { SigHashOptions, TxData, TxInput, TxOutput } from '../../types/index.js';
3
3
  export declare function hash_segwit_tx(txdata: TxData, options?: SigHashOptions): Buff;
4
+ export declare function bip143_hash_prevouts(vin: TxInput[], isAnypay?: boolean): Uint8Array;
5
+ export declare function bip143_hash_sequence(vin: TxInput[], sigflag: number, isAnyPay: boolean): Uint8Array;
6
+ export declare function bip143_hash_outputs(vout: TxOutput[], sigflag: number, idx?: number): Uint8Array;
@@ -33,20 +33,20 @@ export function hash_segwit_tx(txdata, options = {}) {
33
33
  }
34
34
  const sighash = [
35
35
  encode_tx_version(version),
36
- hash_prevouts(vin, is_anypay),
37
- hash_sequence(vin, flag, is_anypay),
36
+ bip143_hash_prevouts(vin, is_anypay),
37
+ bip143_hash_sequence(vin, flag, is_anypay),
38
38
  encode_txin_txid(txid),
39
39
  encode_txin_vout(prevIdx),
40
40
  prefix_script_size(script),
41
41
  encode_vout_value(value),
42
42
  encode_txin_sequence(sequence),
43
- hash_outputs(vout, flag, txindex),
43
+ bip143_hash_outputs(vout, flag, txindex),
44
44
  encode_tx_locktime(locktime),
45
45
  Buff.num(sigflag, 4).reverse()
46
46
  ];
47
47
  return hash256(Buff.join(sighash));
48
48
  }
49
- function hash_prevouts(vin, isAnypay) {
49
+ export function bip143_hash_prevouts(vin, isAnypay) {
50
50
  if (isAnypay === true) {
51
51
  return Buff.num(0, 32);
52
52
  }
@@ -57,7 +57,7 @@ function hash_prevouts(vin, isAnypay) {
57
57
  }
58
58
  return hash256(Buff.join(stack));
59
59
  }
60
- function hash_sequence(vin, sigflag, isAnyPay) {
60
+ export function bip143_hash_sequence(vin, sigflag, isAnyPay) {
61
61
  if (isAnyPay || sigflag !== 0x01) {
62
62
  return Buff.num(0, 32);
63
63
  }
@@ -67,7 +67,7 @@ function hash_sequence(vin, sigflag, isAnyPay) {
67
67
  }
68
68
  return hash256(Buff.join(stack));
69
69
  }
70
- function hash_outputs(vout, sigflag, idx) {
70
+ export function bip143_hash_outputs(vout, sigflag, idx) {
71
71
  const stack = [];
72
72
  if (sigflag === 0x01) {
73
73
  for (const { value, script_pk } of vout) {
@@ -1,9 +1,10 @@
1
1
  import { Buff } from '@vbyte/buff';
2
2
  import type { SigHashOptions, TxData, TxInput, TxOutput } from '../../types/index.js';
3
3
  export declare function hash_taproot_tx(template: TxData | string, config?: SigHashOptions): Buff;
4
- export declare function hash_outpoints(vin: TxInput[]): Buff;
5
- export declare function hash_sequence(vin: TxInput[]): Buff;
6
- export declare function hash_amounts(prevouts: TxOutput[]): Buff;
7
- export declare function hash_scripts(prevouts: TxOutput[]): Buff;
8
- export declare function hash_outputs(vout: TxOutput[]): Buff;
9
- export declare function hash_output(vout: TxOutput): Buff;
4
+ export declare function get_taproot_tx_preimage(template: TxData | string, config?: SigHashOptions): Buff;
5
+ export declare function bip341_hash_outpoints(vin: TxInput[]): Buff;
6
+ export declare function bip341_hash_sequence(vin: TxInput[]): Buff;
7
+ export declare function bip341_hash_amounts(prevouts: TxOutput[]): Buff;
8
+ export declare function bip341_hash_scripts(prevouts: TxOutput[]): Buff;
9
+ export declare function bip341_hash_outputs(vout: TxOutput[]): Buff;
10
+ export declare function bip341_hash_output(vout: TxOutput): Buff;
@@ -1,13 +1,16 @@
1
1
  import { Buff } from '@vbyte/buff';
2
2
  import { Assert } from '@vbyte/micro-lib';
3
3
  import { hash340, sha256 } from '@vbyte/micro-lib/hash';
4
- import { prefix_script_size } from '../../lib/script/util.js';
5
4
  import { encode_tapscript } from '../../lib/taproot/encode.js';
6
5
  import { parse_tx } from '../../lib/tx/parse.js';
7
6
  import * as CONST from '../../const.js';
8
- import { parse_txinput } from './util.js';
9
- import { encode_txin_vout, encode_tx_locktime, encode_txin_sequence, encode_txin_txid, encode_vout_value, encode_tx_version } from '../../lib/tx/encode.js';
7
+ import { parse_txinput, get_annex_data, get_prevout } from './util.js';
8
+ import { encode_txin_vout, encode_tx_locktime, encode_txin_sequence, encode_txin_txid, encode_vout_value, encode_tx_version, encode_script_data } from '../../lib/tx/encode.js';
10
9
  export function hash_taproot_tx(template, config = {}) {
10
+ const preimage = get_taproot_tx_preimage(template, config);
11
+ return hash340('TapSighash', preimage);
12
+ }
13
+ export function get_taproot_tx_preimage(template, config = {}) {
11
14
  const { script, txindex, sigflag = 0x00, extflag = 0x00, key_version = 0x00, separator_pos = 0xFFFFFFFF } = config;
12
15
  const tx = parse_tx(template);
13
16
  const { version, vin: input, vout: output, locktime } = tx;
@@ -28,9 +31,7 @@ export function hash_taproot_tx(template, config = {}) {
28
31
  const annexBit = (annex !== undefined) ? 1 : 0;
29
32
  const extendBit = (extension !== undefined) ? 1 : 0;
30
33
  const spendType = ((extflag + extendBit) * 2) + annexBit;
31
- const hashtag = hash340('TapSighash');
32
34
  const preimage = [
33
- hashtag,
34
35
  Buff.num(0x00, 1),
35
36
  Buff.num(sigflag, 1),
36
37
  encode_tx_version(version),
@@ -38,15 +39,15 @@ export function hash_taproot_tx(template, config = {}) {
38
39
  ];
39
40
  if (!is_anypay) {
40
41
  const prevouts = input.map(e => get_prevout(e));
41
- preimage.push(hash_outpoints(input), hash_amounts(prevouts), hash_scripts(prevouts), hash_sequence(input));
42
+ preimage.push(bip341_hash_outpoints(input), bip341_hash_amounts(prevouts), bip341_hash_scripts(prevouts), bip341_hash_sequence(input));
42
43
  }
43
44
  if ((sigflag & 0x03) < 2 || (sigflag & 0x03) > 3) {
44
- preimage.push(hash_outputs(output));
45
+ preimage.push(bip341_hash_outputs(output));
45
46
  }
46
47
  preimage.push(Buff.num(spendType, 1));
47
48
  if (is_anypay) {
48
49
  const { value, script_pk } = get_prevout(txinput);
49
- preimage.push(encode_txin_txid(txid), encode_txin_vout(vout), encode_vout_value(value), prefix_script_size(script_pk), encode_txin_sequence(sequence));
50
+ preimage.push(encode_txin_txid(txid), encode_txin_vout(vout), encode_vout_value(value), encode_script_data(script_pk), encode_txin_sequence(sequence));
50
51
  }
51
52
  else {
52
53
  Assert.ok(typeof txindex === 'number');
@@ -57,14 +58,14 @@ export function hash_taproot_tx(template, config = {}) {
57
58
  }
58
59
  if ((sigflag & 0x03) === 0x03) {
59
60
  Assert.ok(typeof txindex === 'number');
60
- preimage.push(hash_output(output[txindex]));
61
+ preimage.push(bip341_hash_output(output[txindex]));
61
62
  }
62
63
  if (extension !== undefined) {
63
- preimage.push(Buff.bytes(extension), Buff.num(key_version), Buff.num(separator_pos, 4));
64
+ preimage.push(Buff.bytes(extension), Buff.num(key_version), Buff.num(separator_pos, 4, 'le'));
64
65
  }
65
- return sha256(Buff.join(preimage));
66
+ return Buff.join(preimage);
66
67
  }
67
- export function hash_outpoints(vin) {
68
+ export function bip341_hash_outpoints(vin) {
68
69
  const stack = [];
69
70
  for (const { txid, vout } of vin) {
70
71
  stack.push(encode_txin_txid(txid));
@@ -72,53 +73,23 @@ export function hash_outpoints(vin) {
72
73
  }
73
74
  return sha256(Buff.join(stack));
74
75
  }
75
- export function hash_sequence(vin) {
76
- const stack = [];
77
- for (const { sequence } of vin) {
78
- stack.push(encode_txin_sequence(sequence));
79
- }
80
- return sha256(Buff.join(stack));
76
+ export function bip341_hash_sequence(vin) {
77
+ return sha256(...vin.map(vin => encode_txin_sequence(vin.sequence)));
81
78
  }
82
- export function hash_amounts(prevouts) {
83
- const stack = [];
84
- for (const { value } of prevouts) {
85
- stack.push(encode_vout_value(value));
86
- }
87
- return sha256(Buff.join(stack));
79
+ export function bip341_hash_amounts(prevouts) {
80
+ return sha256(...prevouts.map(prevout => encode_vout_value(prevout.value)));
88
81
  }
89
- export function hash_scripts(prevouts) {
90
- const stack = [];
91
- for (const { script_pk } of prevouts) {
92
- stack.push(prefix_script_size(script_pk));
93
- }
94
- return sha256(Buff.join(stack));
82
+ export function bip341_hash_scripts(prevouts) {
83
+ return sha256(...prevouts.map(prevout => encode_script_data(prevout.script_pk)));
95
84
  }
96
- export function hash_outputs(vout) {
85
+ export function bip341_hash_outputs(vout) {
97
86
  const stack = [];
98
87
  for (const { value, script_pk } of vout) {
99
88
  stack.push(encode_vout_value(value));
100
- stack.push(prefix_script_size(script_pk));
101
- }
102
- return sha256(Buff.join(stack));
103
- }
104
- export function hash_output(vout) {
105
- return sha256(encode_vout_value(vout.value), prefix_script_size(vout.script_pk));
106
- }
107
- function get_annex_data(witness) {
108
- if (witness === undefined)
109
- return;
110
- if (witness.length < 2)
111
- return;
112
- const annex = witness.at(-1);
113
- if (typeof annex === 'string' && annex.startsWith('50')) {
114
- const bytes = Buff.hex(annex).prefix_varint('be');
115
- return sha256(bytes);
89
+ stack.push(encode_script_data(script_pk));
116
90
  }
117
- return undefined;
91
+ return sha256(...stack);
118
92
  }
119
- function get_prevout(vin) {
120
- if (vin.prevout === null) {
121
- throw new Error('Prevout data missing for input: ' + String(vin.txid));
122
- }
123
- return vin.prevout;
93
+ export function bip341_hash_output(vout) {
94
+ return sha256(encode_vout_value(vout.value), encode_script_data(vout.script_pk));
124
95
  }
@@ -1,3 +1,5 @@
1
- import type { SigHashOptions, TxInput, TxData } from '../../types/index.js';
1
+ import { Buff } from '@vbyte/buff';
2
+ import type { SigHashOptions, TxInput, TxData, TxOutput } from '../../types/index.js';
3
+ export declare function get_prevout(vin: TxInput): TxOutput;
2
4
  export declare function parse_txinput(txdata: TxData, config?: SigHashOptions): TxInput;
3
- export declare function format_sigflag(flag: number): string;
5
+ export declare function get_annex_data(witness?: string[]): Buff | undefined;
@@ -1,5 +1,10 @@
1
1
  import { Buff } from '@vbyte/buff';
2
2
  import { Assert } from '@vbyte/micro-lib';
3
+ import { sha256 } from '@vbyte/micro-lib/hash';
4
+ export function get_prevout(vin) {
5
+ Assert.exists(vin.prevout, 'Prevout data missing for input: ' + String(vin.txid));
6
+ return vin.prevout;
7
+ }
3
8
  export function parse_txinput(txdata, config) {
4
9
  let { txindex, txinput } = config ?? {};
5
10
  if (txindex !== undefined) {
@@ -11,6 +16,15 @@ export function parse_txinput(txdata, config) {
11
16
  Assert.ok(txinput !== undefined);
12
17
  return txinput;
13
18
  }
14
- export function format_sigflag(flag) {
15
- return (flag !== 0) ? Buff.num(flag, 1).hex : '';
19
+ export function get_annex_data(witness) {
20
+ if (witness === undefined)
21
+ return;
22
+ if (witness.length < 2)
23
+ return;
24
+ const annex = witness.at(-1);
25
+ if (typeof annex === 'string' && annex.startsWith('50')) {
26
+ const bytes = Buff.hex(annex).prefix_varint('be');
27
+ return sha256(bytes);
28
+ }
29
+ return undefined;
16
30
  }
@@ -1,20 +1,23 @@
1
+ import { Buff } from '@vbyte/buff';
1
2
  import { ECC } from '@vbyte/micro-lib';
2
3
  import { parse_tx } from '../../lib/tx/parse.js';
3
4
  import { SIGHASH_DEFAULT } from '../../const.js';
4
- import { hash_segwit_tx } from '../sighash/segwit.js';
5
- import { hash_taproot_tx } from '../sighash/taproot.js';
6
- import { format_sigflag } from '../sighash/util.js';
5
+ import { hash_segwit_tx } from '../../lib/sighash/segwit.js';
6
+ import { hash_taproot_tx } from '../../lib/sighash/taproot.js';
7
7
  export function sign_segwit_tx(seckey, txdata, options) {
8
8
  const tx = parse_tx(txdata);
9
9
  const msg = hash_segwit_tx(tx, options);
10
- const sig = ECC.sign_ecdsa(seckey, msg).hex;
10
+ const sig = ECC.get_ecdsa_sig(seckey, msg).hex;
11
11
  const flag = format_sigflag(options.sigflag ?? SIGHASH_DEFAULT);
12
12
  return sig + flag;
13
13
  }
14
14
  export function sign_taproot_tx(seckey, txdata, options) {
15
15
  const tx = parse_tx(txdata);
16
16
  const msg = hash_taproot_tx(tx, options);
17
- const sig = ECC.sign_bip340(seckey, msg).hex;
17
+ const sig = ECC.get_bip340_sig(seckey, msg).hex;
18
18
  const flag = format_sigflag(options.sigflag ?? 0);
19
19
  return sig + flag;
20
20
  }
21
+ function format_sigflag(flag) {
22
+ return (flag !== 0) ? Buff.num(flag, 1).hex : '';
23
+ }
@@ -1,4 +1,3 @@
1
1
  import { Bytes } from '@vbyte/buff';
2
2
  import type { SigHashOptions, TxData } from '../../types/index.js';
3
- export declare function verify_segwit_tx(_txdata: TxData | Bytes, _config?: SigHashOptions): boolean;
4
- export declare function verify_taproot_tx(_txdata: TxData | Bytes, _config?: SigHashOptions): boolean;
3
+ export declare function verify_tx(_txdata: TxData | Bytes, _config?: SigHashOptions): boolean;
@@ -1,8 +1,4 @@
1
- export function verify_segwit_tx(_txdata, _config = {}) {
1
+ export function verify_tx(_txdata, _config = {}) {
2
2
  console.warn('verify_segwit_tx is not implemented');
3
3
  return true;
4
4
  }
5
- export function verify_taproot_tx(_txdata, _config = {}) {
6
- console.warn('verify_taproot_tx is not implemented');
7
- return true;
8
- }
@@ -1,6 +1,7 @@
1
- import type { TxData, TxInputTemplate, TxInput, TxOutput, TxTemplate, TxSpendInput, TxCoinbaseInput } from '../../types/index.js';
2
- export declare function create_coinbase_input(config: TxInputTemplate | TxInput): TxCoinbaseInput;
3
- export declare function create_spend_input(config: TxInputTemplate | TxInput): TxSpendInput;
4
- export declare function create_tx_input(config: TxInputTemplate | TxInput): TxInput;
5
- export declare function create_tx_output(config: TxOutput): TxOutput;
6
- export declare function create_tx(config: TxTemplate | TxData): TxData;
1
+ import type { TxData, TxInput, TxOutput, TxTemplate, TxSpendInput, TxCoinbaseInput, TxOutputTemplate, TxVirtualInput, TxInputTemplate } from '../../types/index.js';
2
+ export declare function create_coinbase_input(config: TxInputTemplate): TxCoinbaseInput;
3
+ export declare function create_virtual_input(config: TxInputTemplate): TxVirtualInput;
4
+ export declare function create_spend_input(config: TxInputTemplate): TxSpendInput;
5
+ export declare function create_tx_input(config: TxInputTemplate): TxInput;
6
+ export declare function create_tx_output(config: TxOutputTemplate): TxOutput;
7
+ export declare function create_tx(config?: TxTemplate): TxData;
@@ -1,51 +1,49 @@
1
1
  import { Assert } from '@vbyte/micro-lib';
2
2
  import { COINBASE, DEFAULT } from '../../const.js';
3
- import { assert_tx_output, assert_tx_template, assert_vin_template } from './validate.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';
4
5
  export function create_coinbase_input(config) {
5
6
  assert_vin_template(config);
6
7
  Assert.exists(config.coinbase, 'coinbase is required');
7
- const coinbase = config.coinbase;
8
- const prevout = null;
9
- const script_sig = null;
10
- const sequence = config.sequence ?? DEFAULT.SEQUENCE;
11
8
  const txid = COINBASE.TXID;
12
9
  const vout = COINBASE.VOUT;
10
+ const coinbase = config.coinbase;
13
11
  const witness = config.witness ?? [];
14
- return { coinbase, prevout, script_sig, sequence, witness, txid, vout };
12
+ const sequence = normalize_sequence(config.sequence);
13
+ return { coinbase, prevout: null, script_sig: null, sequence, witness, txid, vout };
14
+ }
15
+ export function create_virtual_input(config) {
16
+ assert_vin_template(config);
17
+ Assert.is_empty(config.coinbase, 'coinbase is not allowed');
18
+ Assert.is_empty(config.prevout, 'prevout is not allowed');
19
+ const { txid, vout, script_sig = null, witness = [] } = config;
20
+ const sequence = normalize_sequence(config.sequence);
21
+ return { txid, vout, coinbase: null, prevout: null, script_sig, sequence, witness };
15
22
  }
16
23
  export function create_spend_input(config) {
17
24
  assert_vin_template(config);
18
25
  Assert.exists(config.prevout, 'prevout is required');
19
- const prevout = config.prevout;
20
- const coinbase = null;
21
- const script_sig = config.script_sig ?? null;
22
- const sequence = config.sequence ?? DEFAULT.SEQUENCE;
23
- const witness = config.witness ?? [];
24
- return { ...config, coinbase, prevout, script_sig, sequence, witness };
26
+ const { txid, vout, script_sig = null, witness = [] } = config;
27
+ const prevout = normalize_prevout(config.prevout);
28
+ const sequence = normalize_sequence(config.sequence);
29
+ return { txid, vout, coinbase: null, prevout, script_sig, sequence, witness };
25
30
  }
26
31
  export function create_tx_input(config) {
27
- assert_vin_template(config);
28
- Assert.exists(config.txid, 'txid is required');
29
- Assert.exists(config.vout, 'vout is required');
30
- const coinbase = config.coinbase ?? null;
31
- const prevout = config.prevout ?? null;
32
- const script_sig = config.script_sig ?? null;
33
- const sequence = config.sequence ?? DEFAULT.SEQUENCE;
34
- const witness = config.witness ?? [];
35
- if (coinbase !== null)
32
+ if (config.coinbase)
36
33
  return create_coinbase_input(config);
37
- if (prevout !== null)
34
+ if (config.prevout)
38
35
  return create_spend_input(config);
39
- return { ...config, coinbase, prevout, script_sig, sequence, witness };
36
+ return create_virtual_input(config);
40
37
  }
41
38
  export function create_tx_output(config) {
42
- assert_tx_output(config);
43
- const { script_pk, value } = config;
44
- return { script_pk, value: BigInt(value) };
39
+ assert_vout_template(config);
40
+ const script_pk = config.script_pk;
41
+ const value = normalize_value(config.value);
42
+ return { script_pk, value };
45
43
  }
46
44
  export function create_tx(config) {
47
45
  assert_tx_template(config);
48
- const { vin = [], vout = [] } = config;
46
+ const { vin = [], vout = [] } = config ?? { vin: [], vout: [] };
49
47
  const locktime = config.locktime ?? DEFAULT.LOCKTIME;
50
48
  const version = config.version ?? DEFAULT.VERSION;
51
49
  const inputs = vin.map(txin => create_tx_input(txin));
@@ -1,9 +1,4 @@
1
- import { Bytes, Stream } from '@vbyte/buff';
2
- import { TxData, TxOutput } from '../../types/index.js';
3
- interface TxEncoderConfig {
4
- prevouts: TxOutput[];
5
- segwit: boolean;
6
- }
7
- export declare function decode_tx(txbytes: Bytes, options?: Partial<TxEncoderConfig>): TxData;
8
- export declare function read_script(stream: Stream, varint?: boolean): string | null;
9
- export {};
1
+ import { Stream } from '@vbyte/buff';
2
+ import { TxDecodedData } from '../../types/index.js';
3
+ export declare function decode_tx(txdata: string | Uint8Array, use_segwit?: boolean): TxDecodedData;
4
+ export declare function read_payload(stream: Stream): string | null;
@@ -1,20 +1,15 @@
1
1
  import { Stream } from '@vbyte/buff';
2
- import { Assert } from '@vbyte/micro-lib';
2
+ import { Assert } from '@vbyte/micro-lib/assert';
3
3
  import { parse_error } from '@vbyte/micro-lib/util';
4
4
  import { COINBASE } from '../../const.js';
5
- const DEFAULT_CONFIG = {
6
- prevouts: [],
7
- segwit: true
8
- };
9
- export function decode_tx(txbytes, options = {}) {
10
- const config = { ...DEFAULT_CONFIG, ...options };
11
- Assert.is_bytes(txbytes, 'transaction must be hex or a byte-array');
12
- const stream = new Stream(txbytes);
5
+ export function decode_tx(txdata, use_segwit = true) {
6
+ Assert.is_bytes(txdata, 'txdata must be hex or bytes');
7
+ const stream = new Stream(txdata);
13
8
  const version = read_version(stream);
14
- const has_witness = (config.segwit)
9
+ const has_witness = (use_segwit)
15
10
  ? check_witness_flag(stream)
16
11
  : false;
17
- const vin = read_inputs(stream, config.prevouts);
12
+ const vin = read_inputs(stream);
18
13
  const vout = read_outputs(stream);
19
14
  if (has_witness) {
20
15
  for (const txin of vin) {
@@ -40,29 +35,26 @@ function check_witness_flag(stream) {
40
35
  }
41
36
  return false;
42
37
  }
43
- function read_inputs(stream, prevouts) {
38
+ function read_inputs(stream) {
44
39
  const inputs = [];
45
40
  const vinCount = stream.varint();
46
41
  for (let i = 0; i < vinCount; i++) {
47
- const txinput = read_vin(stream, prevouts.at(i));
42
+ const txinput = read_vin(stream);
48
43
  inputs.push(txinput);
49
44
  }
50
45
  return inputs;
51
46
  }
52
- function read_vin(stream, prevout = null) {
47
+ function read_vin(stream) {
53
48
  const txid = stream.read(32).reverse().hex;
54
49
  const vout = stream.read(4).reverse().num;
55
- const script_sig = read_script(stream, true);
50
+ const script_sig = read_payload(stream);
56
51
  const sequence = stream.read(4).reverse().num;
57
52
  const witness = [];
58
53
  if (txid === COINBASE.TXID && vout === COINBASE.VOUT) {
59
54
  return { coinbase: script_sig, prevout: null, script_sig: null, sequence, txid, vout, witness };
60
55
  }
61
- else if (prevout !== null) {
62
- return { coinbase: null, prevout, script_sig, sequence, txid, vout, witness };
63
- }
64
56
  else {
65
- return { coinbase: null, prevout, script_sig, sequence, txid, vout, witness };
57
+ return { coinbase: null, prevout: null, script_sig, sequence, txid, vout, witness };
66
58
  }
67
59
  }
68
60
  function read_outputs(stream) {
@@ -80,7 +72,7 @@ function read_outputs(stream) {
80
72
  }
81
73
  function read_vout(stream) {
82
74
  const value = stream.read(8).reverse().big;
83
- const script_pk = read_script(stream, true);
75
+ const script_pk = read_payload(stream);
84
76
  Assert.exists(script_pk, 'failed to decode script_pk');
85
77
  return { value, script_pk };
86
78
  }
@@ -88,7 +80,7 @@ function read_witness(stream) {
88
80
  const stack = [];
89
81
  const count = stream.varint();
90
82
  for (let i = 0; i < count; i++) {
91
- const element = read_script(stream, true);
83
+ const element = read_payload(stream);
92
84
  if (element === null) {
93
85
  throw new Error('failed to decode witness element: ' + i);
94
86
  }
@@ -96,13 +88,9 @@ function read_witness(stream) {
96
88
  }
97
89
  return stack;
98
90
  }
99
- export function read_script(stream, varint) {
100
- const size = (varint === true)
101
- ? stream.varint('le')
102
- : stream.size;
103
- return size > 0
104
- ? stream.read(size).hex
105
- : null;
91
+ export function read_payload(stream) {
92
+ const size = stream.varint('le');
93
+ return (size > 0) ? stream.read(size).hex : null;
106
94
  }
107
95
  function read_locktime(stream) {
108
96
  return stream.read(4).reverse().to_num();
@@ -1,6 +1,6 @@
1
1
  import { Buff } from '@vbyte/buff';
2
2
  import { TxInput, TxOutput, TxData } from '../../types/index.js';
3
- export declare function encode_tx(txdata: TxData, segwit?: boolean): Buff;
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;
6
6
  export declare function encode_txin_vout(vout: number): Buff;
@@ -1,17 +1,17 @@
1
1
  import { Buff } from '@vbyte/buff';
2
2
  import { Assert } from '@vbyte/micro-lib';
3
- import { parse_tx } from './parse.js';
3
+ import { assert_tx_data } from './validate.js';
4
4
  import { COINBASE } from '../../const.js';
5
- export function encode_tx(txdata, segwit = true) {
6
- const tx = parse_tx(txdata);
7
- const { version, vin, vout, locktime } = tx;
5
+ export function encode_tx(txdata, use_segwit = true) {
6
+ assert_tx_data(txdata);
7
+ const { version, vin, vout, locktime } = txdata;
8
8
  const buffer = [encode_tx_version(version)];
9
- if (segwit) {
9
+ if (use_segwit) {
10
10
  buffer.push(Buff.hex('0001'));
11
11
  }
12
12
  buffer.push(encode_tx_inputs(vin));
13
13
  buffer.push(encode_tx_outputs(vout));
14
- if (segwit) {
14
+ if (use_segwit) {
15
15
  for (const input of vin) {
16
16
  buffer.push(encode_vin_witness(input.witness));
17
17
  }
@@ -1,2 +1,3 @@
1
- import type { TxData } from '../../types/index.js';
2
- export declare function parse_tx(txdata: unknown): TxData;
1
+ import type { TxData, TxOutputTemplate } from '../../types/index.js';
2
+ export declare function parse_tx(txdata: unknown, prevouts?: TxOutputTemplate[]): TxData;
3
+ export declare function serialize_tx(txdata: unknown): Record<string, unknown>;
@@ -1,12 +1,45 @@
1
+ import { Assert } from '@vbyte/micro-lib/assert';
1
2
  import { decode_tx } from './decode.js';
2
- import { create_tx } from './create.js';
3
3
  import { assert_tx_template } from './validate.js';
4
- export function parse_tx(txdata) {
5
- if (typeof txdata === 'string') {
6
- return decode_tx(txdata);
4
+ import { create_tx, create_tx_output } from './create.js';
5
+ export function parse_tx(txdata, prevouts) {
6
+ let tx;
7
+ if (typeof txdata === 'string' || txdata instanceof Uint8Array) {
8
+ tx = decode_tx(txdata);
7
9
  }
8
10
  else {
9
11
  assert_tx_template(txdata);
10
- return create_tx(txdata);
12
+ tx = create_tx(txdata);
11
13
  }
14
+ if (prevouts) {
15
+ Assert.has_items(prevouts, 'prevouts must be a non-empty array');
16
+ for (const [idx, vin] of tx.vin.entries()) {
17
+ const prevout = prevouts.at(idx);
18
+ Assert.exists(prevout, 'prevout not found for input index: ' + idx);
19
+ vin.prevout = create_tx_output(prevout);
20
+ }
21
+ }
22
+ return tx;
23
+ }
24
+ export function serialize_tx(txdata) {
25
+ const tx = parse_tx(txdata);
26
+ const version = tx.version;
27
+ const locktime = tx.locktime;
28
+ const vin = [];
29
+ const vout = [];
30
+ for (const e of tx.vin) {
31
+ if (e.prevout !== null) {
32
+ vin.push({
33
+ script_pk: e.prevout.script_pk,
34
+ value: Number(e.prevout.value)
35
+ });
36
+ }
37
+ }
38
+ for (const e of tx.vout) {
39
+ vout.push({
40
+ script_pk: e.script_pk,
41
+ value: Number(e.value)
42
+ });
43
+ }
44
+ return { version, locktime, vin, vout };
12
45
  }
@@ -1,8 +1,12 @@
1
- import type { TxData, TxOutput, TxOutputInfo, TxOutputType, TxValue, WitnessVersion } from '../../types/index.js';
1
+ import type { TxData, TxOutput, TxOutputInfo, TxOutputTemplate, TxOutputType, TxValue, WitnessVersion } from '../../types/index.js';
2
2
  export declare function is_return_script(script: string): boolean;
3
3
  export declare function get_vout_info(txout: TxOutput): TxOutputInfo;
4
4
  export declare function get_vout_type(script: string): TxOutputType;
5
5
  export declare function get_vout_version(script: string): WitnessVersion;
6
- export declare function get_txid(txdata: string | TxData): string;
7
- export declare function get_txhash(txdata: string | TxData): string;
8
- export declare function get_tx_value(txdata: string | TxData): TxValue;
6
+ export declare function get_txid(txdata: TxData): string;
7
+ export declare function get_txhash(txdata: TxData): string;
8
+ export declare function get_tx_value(txdata: TxData): TxValue;
9
+ export declare function get_prevouts(txdata: TxData): TxOutput[];
10
+ export declare function normalize_sequence(sequence?: number | string | null): number;
11
+ export declare function normalize_value(value: number | bigint): bigint;
12
+ export declare function normalize_prevout(prevout: TxOutputTemplate): TxOutput;