Refactor: Remove all require statements, remove ECPair, remove tiny-secp256k1 dep
This commit is contained in:
parent
f209b0e410
commit
e5a77304fa
87 changed files with 1447 additions and 1161 deletions
src
address.d.tsaddress.jsbip66.d.tsbip66.jsblock.d.tsblock.jsbufferutils.d.tsbufferutils.jscrypto.d.tscrypto.jsecpair.jsindex.d.tsindex.jsmerkle.d.tsmerkle.jsnetworks.d.tsnetworks.jsops.d.tsops.js
payments
embed.d.tsembed.jsindex.d.tsindex.jslazy.d.tslazy.jsp2ms.d.tsp2ms.jsp2pk.d.tsp2pk.jsp2pkh.d.tsp2pkh.jsp2sh.d.tsp2sh.jsp2wpkh.d.tsp2wpkh.jsp2wsh.d.tsp2wsh.js
psbt.d.tspsbt.jspush_data.d.tspush_data.jsscript.d.tsscript.jsscript_number.d.tsscript_number.jsscript_signature.d.tsscript_signature.jstransaction.d.tstransaction.jstypes.d.tstypes.js
17
src/address.d.ts
vendored
Normal file
17
src/address.d.ts
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
/// <reference types="node" />
|
||||
import { Network } from './networks';
|
||||
export interface Base58CheckResult {
|
||||
hash: Buffer;
|
||||
version: number;
|
||||
}
|
||||
export interface Bech32Result {
|
||||
version: number;
|
||||
prefix: string;
|
||||
data: Buffer;
|
||||
}
|
||||
export declare function fromBase58Check(address: string): Base58CheckResult;
|
||||
export declare function fromBech32(address: string): Bech32Result;
|
||||
export declare function toBase58Check(hash: Buffer, version: number): string;
|
||||
export declare function toBech32(data: Buffer, version: number, prefix: string): string;
|
||||
export declare function fromOutputScript(output: Buffer, network?: Network): string;
|
||||
export declare function toOutputScript(address: string, network?: Network): Buffer;
|
|
@ -1,12 +1,13 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.toOutputScript = exports.fromOutputScript = exports.toBech32 = exports.toBase58Check = exports.fromBech32 = exports.fromBase58Check = void 0;
|
||||
const networks = require('./networks');
|
||||
const payments = require('./payments');
|
||||
const bscript = require('./script');
|
||||
const types = require('./types');
|
||||
const { bech32, bech32m } = require('bech32');
|
||||
const bech32_1 = require('bech32');
|
||||
const bs58check = require('bs58check');
|
||||
const typeforce = require('typeforce');
|
||||
const { typeforce } = types;
|
||||
const FUTURE_SEGWIT_MAX_SIZE = 40;
|
||||
const FUTURE_SEGWIT_MIN_SIZE = 2;
|
||||
const FUTURE_SEGWIT_MAX_VERSION = 16;
|
||||
|
@ -43,17 +44,17 @@ function fromBech32(address) {
|
|||
let result;
|
||||
let version;
|
||||
try {
|
||||
result = bech32.decode(address);
|
||||
result = bech32_1.bech32.decode(address);
|
||||
} catch (e) {}
|
||||
if (result) {
|
||||
version = result.words[0];
|
||||
if (version !== 0) throw new TypeError(address + ' uses wrong encoding');
|
||||
} else {
|
||||
result = bech32m.decode(address);
|
||||
result = bech32_1.bech32m.decode(address);
|
||||
version = result.words[0];
|
||||
if (version === 0) throw new TypeError(address + ' uses wrong encoding');
|
||||
}
|
||||
const data = bech32.fromWords(result.words.slice(1));
|
||||
const data = bech32_1.bech32.fromWords(result.words.slice(1));
|
||||
return {
|
||||
version,
|
||||
prefix: result.prefix,
|
||||
|
@ -70,11 +71,11 @@ function toBase58Check(hash, version) {
|
|||
}
|
||||
exports.toBase58Check = toBase58Check;
|
||||
function toBech32(data, version, prefix) {
|
||||
const words = bech32.toWords(data);
|
||||
const words = bech32_1.bech32.toWords(data);
|
||||
words.unshift(version);
|
||||
return version === 0
|
||||
? bech32.encode(prefix, words)
|
||||
: bech32m.encode(prefix, words);
|
||||
? bech32_1.bech32.encode(prefix, words)
|
||||
: bech32_1.bech32m.encode(prefix, words);
|
||||
}
|
||||
exports.toBech32 = toBech32;
|
||||
function fromOutputScript(output, network) {
|
||||
|
|
7
src/bip66.d.ts
vendored
Normal file
7
src/bip66.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/// <reference types="node" />
|
||||
export declare function check(buffer: Buffer): boolean;
|
||||
export declare function decode(buffer: Buffer): {
|
||||
r: Buffer;
|
||||
s: Buffer;
|
||||
};
|
||||
export declare function encode(r: Buffer, s: Buffer): Buffer;
|
102
src/bip66.js
Normal file
102
src/bip66.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
'use strict';
|
||||
// Reference https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
|
||||
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
|
||||
// NOTE: SIGHASH byte ignored AND restricted, truncate before use
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.encode = exports.decode = exports.check = void 0;
|
||||
function check(buffer) {
|
||||
if (buffer.length < 8) return false;
|
||||
if (buffer.length > 72) return false;
|
||||
if (buffer[0] !== 0x30) return false;
|
||||
if (buffer[1] !== buffer.length - 2) return false;
|
||||
if (buffer[2] !== 0x02) return false;
|
||||
const lenR = buffer[3];
|
||||
if (lenR === 0) return false;
|
||||
if (5 + lenR >= buffer.length) return false;
|
||||
if (buffer[4 + lenR] !== 0x02) return false;
|
||||
const lenS = buffer[5 + lenR];
|
||||
if (lenS === 0) return false;
|
||||
if (6 + lenR + lenS !== buffer.length) return false;
|
||||
if (buffer[4] & 0x80) return false;
|
||||
if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) return false;
|
||||
if (buffer[lenR + 6] & 0x80) return false;
|
||||
if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
exports.check = check;
|
||||
function decode(buffer) {
|
||||
if (buffer.length < 8) throw new Error('DER sequence length is too short');
|
||||
if (buffer.length > 72) throw new Error('DER sequence length is too long');
|
||||
if (buffer[0] !== 0x30) throw new Error('Expected DER sequence');
|
||||
if (buffer[1] !== buffer.length - 2)
|
||||
throw new Error('DER sequence length is invalid');
|
||||
if (buffer[2] !== 0x02) throw new Error('Expected DER integer');
|
||||
const lenR = buffer[3];
|
||||
if (lenR === 0) throw new Error('R length is zero');
|
||||
if (5 + lenR >= buffer.length) throw new Error('R length is too long');
|
||||
if (buffer[4 + lenR] !== 0x02) throw new Error('Expected DER integer (2)');
|
||||
const lenS = buffer[5 + lenR];
|
||||
if (lenS === 0) throw new Error('S length is zero');
|
||||
if (6 + lenR + lenS !== buffer.length) throw new Error('S length is invalid');
|
||||
if (buffer[4] & 0x80) throw new Error('R value is negative');
|
||||
if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80))
|
||||
throw new Error('R value excessively padded');
|
||||
if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative');
|
||||
if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
|
||||
throw new Error('S value excessively padded');
|
||||
// non-BIP66 - extract R, S values
|
||||
return {
|
||||
r: buffer.slice(4, 4 + lenR),
|
||||
s: buffer.slice(6 + lenR),
|
||||
};
|
||||
}
|
||||
exports.decode = decode;
|
||||
/*
|
||||
* Expects r and s to be positive DER integers.
|
||||
*
|
||||
* The DER format uses the most significant bit as a sign bit (& 0x80).
|
||||
* If the significant bit is set AND the integer is positive, a 0x00 is prepended.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* 0 => 0x00
|
||||
* 1 => 0x01
|
||||
* -1 => 0xff
|
||||
* 127 => 0x7f
|
||||
* -127 => 0x81
|
||||
* 128 => 0x0080
|
||||
* -128 => 0x80
|
||||
* 255 => 0x00ff
|
||||
* -255 => 0xff01
|
||||
* 16300 => 0x3fac
|
||||
* -16300 => 0xc054
|
||||
* 62300 => 0x00f35c
|
||||
* -62300 => 0xff0ca4
|
||||
*/
|
||||
function encode(r, s) {
|
||||
const lenR = r.length;
|
||||
const lenS = s.length;
|
||||
if (lenR === 0) throw new Error('R length is zero');
|
||||
if (lenS === 0) throw new Error('S length is zero');
|
||||
if (lenR > 33) throw new Error('R length is too long');
|
||||
if (lenS > 33) throw new Error('S length is too long');
|
||||
if (r[0] & 0x80) throw new Error('R value is negative');
|
||||
if (s[0] & 0x80) throw new Error('S value is negative');
|
||||
if (lenR > 1 && r[0] === 0x00 && !(r[1] & 0x80))
|
||||
throw new Error('R value excessively padded');
|
||||
if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80))
|
||||
throw new Error('S value excessively padded');
|
||||
const signature = Buffer.allocUnsafe(6 + lenR + lenS);
|
||||
// 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
|
||||
signature[0] = 0x30;
|
||||
signature[1] = signature.length - 2;
|
||||
signature[2] = 0x02;
|
||||
signature[3] = r.length;
|
||||
r.copy(signature, 4);
|
||||
signature[4 + lenR] = 0x02;
|
||||
signature[5 + lenR] = s.length;
|
||||
s.copy(signature, 6 + lenR);
|
||||
return signature;
|
||||
}
|
||||
exports.encode = encode;
|
30
src/block.d.ts
vendored
Normal file
30
src/block.d.ts
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
/// <reference types="node" />
|
||||
import { Transaction } from './transaction';
|
||||
export declare class Block {
|
||||
static fromBuffer(buffer: Buffer): Block;
|
||||
static fromHex(hex: string): Block;
|
||||
static calculateTarget(bits: number): Buffer;
|
||||
static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Buffer;
|
||||
version: number;
|
||||
prevHash?: Buffer;
|
||||
merkleRoot?: Buffer;
|
||||
timestamp: number;
|
||||
witnessCommit?: Buffer;
|
||||
bits: number;
|
||||
nonce: number;
|
||||
transactions?: Transaction[];
|
||||
getWitnessCommit(): Buffer | null;
|
||||
hasWitnessCommit(): boolean;
|
||||
hasWitness(): boolean;
|
||||
weight(): number;
|
||||
byteLength(headersOnly?: boolean, allowWitness?: boolean): number;
|
||||
getHash(): Buffer;
|
||||
getId(): string;
|
||||
getUTCDate(): Date;
|
||||
toBuffer(headersOnly?: boolean): Buffer;
|
||||
toHex(headersOnly?: boolean): string;
|
||||
checkTxRoots(): boolean;
|
||||
checkProofOfWork(): boolean;
|
||||
private __checkMerkleRoot;
|
||||
private __checkWitnessCommit;
|
||||
}
|
40
src/block.js
40
src/block.js
|
@ -1,12 +1,12 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.Block = void 0;
|
||||
const bufferutils_1 = require('./bufferutils');
|
||||
const bcrypto = require('./crypto');
|
||||
const merkle_1 = require('./merkle');
|
||||
const transaction_1 = require('./transaction');
|
||||
const types = require('./types');
|
||||
const fastMerkleRoot = require('merkle-lib/fastRoot');
|
||||
const typeforce = require('typeforce');
|
||||
const varuint = require('varuint-bitcoin');
|
||||
const { typeforce } = types;
|
||||
const errorMerkleNoTxes = new TypeError(
|
||||
'Cannot compute merkle root for zero transactions',
|
||||
);
|
||||
|
@ -14,16 +14,6 @@ const errorWitnessNotSegwit = new TypeError(
|
|||
'Cannot compute witness commit for non-segwit block',
|
||||
);
|
||||
class Block {
|
||||
constructor() {
|
||||
this.version = 1;
|
||||
this.prevHash = undefined;
|
||||
this.merkleRoot = undefined;
|
||||
this.timestamp = 0;
|
||||
this.witnessCommit = undefined;
|
||||
this.bits = 0;
|
||||
this.nonce = 0;
|
||||
this.transactions = undefined;
|
||||
}
|
||||
static fromBuffer(buffer) {
|
||||
if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)');
|
||||
const bufferReader = new bufferutils_1.BufferReader(buffer);
|
||||
|
@ -72,13 +62,21 @@ class Block {
|
|||
const hashes = transactions.map(transaction =>
|
||||
transaction.getHash(forWitness),
|
||||
);
|
||||
const rootHash = fastMerkleRoot(hashes, bcrypto.hash256);
|
||||
const rootHash = (0, merkle_1.fastMerkleRoot)(hashes, bcrypto.hash256);
|
||||
return forWitness
|
||||
? bcrypto.hash256(
|
||||
Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]),
|
||||
)
|
||||
: rootHash;
|
||||
}
|
||||
version = 1;
|
||||
prevHash = undefined;
|
||||
merkleRoot = undefined;
|
||||
timestamp = 0;
|
||||
witnessCommit = undefined;
|
||||
bits = 0;
|
||||
nonce = 0;
|
||||
transactions = undefined;
|
||||
getWitnessCommit() {
|
||||
if (!txesHaveWitnessCommit(this.transactions)) return null;
|
||||
// The merkle root for the witness data is in an OP_RETURN output.
|
||||
|
@ -117,7 +115,7 @@ class Block {
|
|||
if (headersOnly || !this.transactions) return 80;
|
||||
return (
|
||||
80 +
|
||||
varuint.encodingLength(this.transactions.length) +
|
||||
bufferutils_1.varuint.encodingLength(this.transactions.length) +
|
||||
this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0)
|
||||
);
|
||||
}
|
||||
|
@ -125,7 +123,7 @@ class Block {
|
|||
return bcrypto.hash256(this.toBuffer(true));
|
||||
}
|
||||
getId() {
|
||||
return bufferutils_1.reverseBuffer(this.getHash()).toString('hex');
|
||||
return (0, bufferutils_1.reverseBuffer)(this.getHash()).toString('hex');
|
||||
}
|
||||
getUTCDate() {
|
||||
const date = new Date(0); // epoch
|
||||
|
@ -143,8 +141,12 @@ class Block {
|
|||
bufferWriter.writeUInt32(this.bits);
|
||||
bufferWriter.writeUInt32(this.nonce);
|
||||
if (headersOnly || !this.transactions) return buffer;
|
||||
varuint.encode(this.transactions.length, buffer, bufferWriter.offset);
|
||||
bufferWriter.offset += varuint.encode.bytes;
|
||||
bufferutils_1.varuint.encode(
|
||||
this.transactions.length,
|
||||
buffer,
|
||||
bufferWriter.offset,
|
||||
);
|
||||
bufferWriter.offset += bufferutils_1.varuint.encode.bytes;
|
||||
this.transactions.forEach(tx => {
|
||||
const txSize = tx.byteLength(); // TODO: extract from toBuffer?
|
||||
tx.toBuffer(buffer, bufferWriter.offset);
|
||||
|
@ -166,7 +168,7 @@ class Block {
|
|||
);
|
||||
}
|
||||
checkProofOfWork() {
|
||||
const hash = bufferutils_1.reverseBuffer(this.getHash());
|
||||
const hash = (0, bufferutils_1.reverseBuffer)(this.getHash());
|
||||
const target = Block.calculateTarget(this.bits);
|
||||
return hash.compare(target) <= 0;
|
||||
}
|
||||
|
|
39
src/bufferutils.d.ts
vendored
Normal file
39
src/bufferutils.d.ts
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
/// <reference types="node" />
|
||||
import * as varuint from 'varuint-bitcoin';
|
||||
export { varuint };
|
||||
export declare function readUInt64LE(buffer: Buffer, offset: number): number;
|
||||
export declare function writeUInt64LE(buffer: Buffer, value: number, offset: number): number;
|
||||
export declare function reverseBuffer(buffer: Buffer): Buffer;
|
||||
export declare function cloneBuffer(buffer: Buffer): Buffer;
|
||||
/**
|
||||
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
|
||||
*/
|
||||
export declare class BufferWriter {
|
||||
buffer: Buffer;
|
||||
offset: number;
|
||||
constructor(buffer: Buffer, offset?: number);
|
||||
writeUInt8(i: number): void;
|
||||
writeInt32(i: number): void;
|
||||
writeUInt32(i: number): void;
|
||||
writeUInt64(i: number): void;
|
||||
writeVarInt(i: number): void;
|
||||
writeSlice(slice: Buffer): void;
|
||||
writeVarSlice(slice: Buffer): void;
|
||||
writeVector(vector: Buffer[]): void;
|
||||
}
|
||||
/**
|
||||
* Helper class for reading of bitcoin data types from a buffer.
|
||||
*/
|
||||
export declare class BufferReader {
|
||||
buffer: Buffer;
|
||||
offset: number;
|
||||
constructor(buffer: Buffer, offset?: number);
|
||||
readUInt8(): number;
|
||||
readInt32(): number;
|
||||
readUInt32(): number;
|
||||
readUInt64(): number;
|
||||
readVarInt(): number;
|
||||
readSlice(n: number): Buffer;
|
||||
readVarSlice(): Buffer;
|
||||
readVector(): Buffer[];
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.BufferReader = exports.BufferWriter = exports.cloneBuffer = exports.reverseBuffer = exports.writeUInt64LE = exports.readUInt64LE = exports.varuint = void 0;
|
||||
const types = require('./types');
|
||||
const typeforce = require('typeforce');
|
||||
const { typeforce } = types;
|
||||
const varuint = require('varuint-bitcoin');
|
||||
exports.varuint = varuint;
|
||||
// https://github.com/feross/buffer/blob/master/index.js#L1127
|
||||
function verifuint(value, max) {
|
||||
if (typeof value !== 'number')
|
||||
|
@ -51,6 +53,8 @@ exports.cloneBuffer = cloneBuffer;
|
|||
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
|
||||
*/
|
||||
class BufferWriter {
|
||||
buffer;
|
||||
offset;
|
||||
constructor(buffer, offset = 0) {
|
||||
this.buffer = buffer;
|
||||
this.offset = offset;
|
||||
|
@ -92,6 +96,8 @@ exports.BufferWriter = BufferWriter;
|
|||
* Helper class for reading of bitcoin data types from a buffer.
|
||||
*/
|
||||
class BufferReader {
|
||||
buffer;
|
||||
offset;
|
||||
constructor(buffer, offset = 0) {
|
||||
this.buffer = buffer;
|
||||
this.offset = offset;
|
||||
|
|
6
src/crypto.d.ts
vendored
Normal file
6
src/crypto.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
/// <reference types="node" />
|
||||
export declare function ripemd160(buffer: Buffer): Buffer;
|
||||
export declare function sha1(buffer: Buffer): Buffer;
|
||||
export declare function sha256(buffer: Buffer): Buffer;
|
||||
export declare function hash160(buffer: Buffer): Buffer;
|
||||
export declare function hash256(buffer: Buffer): Buffer;
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.hash256 = exports.hash160 = exports.sha256 = exports.sha1 = exports.ripemd160 = void 0;
|
||||
const createHash = require('create-hash');
|
||||
function ripemd160(buffer) {
|
||||
try {
|
||||
|
|
107
src/ecpair.js
107
src/ecpair.js
|
@ -1,107 +0,0 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
const NETWORKS = require('./networks');
|
||||
const types = require('./types');
|
||||
const ecc = require('tiny-secp256k1');
|
||||
const randomBytes = require('randombytes');
|
||||
const typeforce = require('typeforce');
|
||||
const wif = require('wif');
|
||||
const isOptions = typeforce.maybe(
|
||||
typeforce.compile({
|
||||
compressed: types.maybe(types.Boolean),
|
||||
network: types.maybe(types.Network),
|
||||
}),
|
||||
);
|
||||
class ECPair {
|
||||
constructor(__D, __Q, options) {
|
||||
this.__D = __D;
|
||||
this.__Q = __Q;
|
||||
this.lowR = false;
|
||||
if (options === undefined) options = {};
|
||||
this.compressed =
|
||||
options.compressed === undefined ? true : options.compressed;
|
||||
this.network = options.network || NETWORKS.bitcoin;
|
||||
if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed);
|
||||
}
|
||||
get privateKey() {
|
||||
return this.__D;
|
||||
}
|
||||
get publicKey() {
|
||||
if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed);
|
||||
return this.__Q;
|
||||
}
|
||||
toWIF() {
|
||||
if (!this.__D) throw new Error('Missing private key');
|
||||
return wif.encode(this.network.wif, this.__D, this.compressed);
|
||||
}
|
||||
sign(hash, lowR) {
|
||||
if (!this.__D) throw new Error('Missing private key');
|
||||
if (lowR === undefined) lowR = this.lowR;
|
||||
if (lowR === false) {
|
||||
return ecc.sign(hash, this.__D);
|
||||
} else {
|
||||
let sig = ecc.sign(hash, this.__D);
|
||||
const extraData = Buffer.alloc(32, 0);
|
||||
let counter = 0;
|
||||
// if first try is lowR, skip the loop
|
||||
// for second try and on, add extra entropy counting up
|
||||
while (sig[0] > 0x7f) {
|
||||
counter++;
|
||||
extraData.writeUIntLE(counter, 0, 6);
|
||||
sig = ecc.signWithEntropy(hash, this.__D, extraData);
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
}
|
||||
verify(hash, signature) {
|
||||
return ecc.verify(hash, this.publicKey, signature);
|
||||
}
|
||||
}
|
||||
function fromPrivateKey(buffer, options) {
|
||||
typeforce(types.Buffer256bit, buffer);
|
||||
if (!ecc.isPrivate(buffer))
|
||||
throw new TypeError('Private key not in range [1, n)');
|
||||
typeforce(isOptions, options);
|
||||
return new ECPair(buffer, undefined, options);
|
||||
}
|
||||
exports.fromPrivateKey = fromPrivateKey;
|
||||
function fromPublicKey(buffer, options) {
|
||||
typeforce(ecc.isPoint, buffer);
|
||||
typeforce(isOptions, options);
|
||||
return new ECPair(undefined, buffer, options);
|
||||
}
|
||||
exports.fromPublicKey = fromPublicKey;
|
||||
function fromWIF(wifString, network) {
|
||||
const decoded = wif.decode(wifString);
|
||||
const version = decoded.version;
|
||||
// list of networks?
|
||||
if (types.Array(network)) {
|
||||
network = network
|
||||
.filter(x => {
|
||||
return version === x.wif;
|
||||
})
|
||||
.pop();
|
||||
if (!network) throw new Error('Unknown network version');
|
||||
// otherwise, assume a network object (or default to bitcoin)
|
||||
} else {
|
||||
network = network || NETWORKS.bitcoin;
|
||||
if (version !== network.wif) throw new Error('Invalid network version');
|
||||
}
|
||||
return fromPrivateKey(decoded.privateKey, {
|
||||
compressed: decoded.compressed,
|
||||
network: network,
|
||||
});
|
||||
}
|
||||
exports.fromWIF = fromWIF;
|
||||
function makeRandom(options) {
|
||||
typeforce(isOptions, options);
|
||||
if (options === undefined) options = {};
|
||||
const rng = options.rng || randomBytes;
|
||||
let d;
|
||||
do {
|
||||
d = rng(32);
|
||||
typeforce(types.Buffer256bit, d);
|
||||
} while (!ecc.isPrivate(d));
|
||||
return fromPrivateKey(d, options);
|
||||
}
|
||||
exports.makeRandom = makeRandom;
|
15
src/index.d.ts
vendored
Normal file
15
src/index.d.ts
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
import * as bip32 from 'bip32';
|
||||
import * as address from './address';
|
||||
import * as crypto from './crypto';
|
||||
import * as networks from './networks';
|
||||
import * as payments from './payments';
|
||||
import * as script from './script';
|
||||
export { address, bip32, crypto, networks, payments, script };
|
||||
export { Block } from './block';
|
||||
export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, } from './psbt';
|
||||
export { OPS as opcodes } from './ops';
|
||||
export { Transaction } from './transaction';
|
||||
export { BIP32Interface } from 'bip32';
|
||||
export { Network } from './networks';
|
||||
export { Payment, PaymentCreator, PaymentOpts, Stack, StackElement, } from './payments';
|
||||
export { Input as TxInput, Output as TxOutput } from './transaction';
|
33
src/index.js
33
src/index.js
|
@ -1,13 +1,12 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.bip32 = exports.address = void 0;
|
||||
const bip32 = require('bip32');
|
||||
exports.bip32 = bip32;
|
||||
const address = require('./address');
|
||||
exports.address = address;
|
||||
const crypto = require('./crypto');
|
||||
exports.crypto = crypto;
|
||||
const ECPair = require('./ecpair');
|
||||
exports.ECPair = ECPair;
|
||||
const networks = require('./networks');
|
||||
exports.networks = networks;
|
||||
const payments = require('./payments');
|
||||
|
@ -15,10 +14,30 @@ exports.payments = payments;
|
|||
const script = require('./script');
|
||||
exports.script = script;
|
||||
var block_1 = require('./block');
|
||||
exports.Block = block_1.Block;
|
||||
Object.defineProperty(exports, 'Block', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return block_1.Block;
|
||||
},
|
||||
});
|
||||
var psbt_1 = require('./psbt');
|
||||
exports.Psbt = psbt_1.Psbt;
|
||||
var script_1 = require('./script');
|
||||
exports.opcodes = script_1.OPS;
|
||||
Object.defineProperty(exports, 'Psbt', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return psbt_1.Psbt;
|
||||
},
|
||||
});
|
||||
var ops_1 = require('./ops');
|
||||
Object.defineProperty(exports, 'opcodes', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return ops_1.OPS;
|
||||
},
|
||||
});
|
||||
var transaction_1 = require('./transaction');
|
||||
exports.Transaction = transaction_1.Transaction;
|
||||
Object.defineProperty(exports, 'Transaction', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return transaction_1.Transaction;
|
||||
},
|
||||
});
|
||||
|
|
2
src/merkle.d.ts
vendored
Normal file
2
src/merkle.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// <reference types="node" />
|
||||
export declare function fastMerkleRoot(values: Buffer[], digestFn: (b: Buffer) => Buffer): Buffer;
|
22
src/merkle.js
Normal file
22
src/merkle.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.fastMerkleRoot = void 0;
|
||||
function fastMerkleRoot(values, digestFn) {
|
||||
if (!Array.isArray(values)) throw TypeError('Expected values Array');
|
||||
if (typeof digestFn !== 'function')
|
||||
throw TypeError('Expected digest Function');
|
||||
let length = values.length;
|
||||
const results = values.concat();
|
||||
while (length > 1) {
|
||||
let j = 0;
|
||||
for (let i = 0; i < length; i += 2, ++j) {
|
||||
const left = results[i];
|
||||
const right = i + 1 === length ? left : results[i + 1];
|
||||
const data = Buffer.concat([left, right]);
|
||||
results[j] = digestFn(data);
|
||||
}
|
||||
length = j;
|
||||
}
|
||||
return results[0];
|
||||
}
|
||||
exports.fastMerkleRoot = fastMerkleRoot;
|
16
src/networks.d.ts
vendored
Normal file
16
src/networks.d.ts
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
export interface Network {
|
||||
messagePrefix: string;
|
||||
bech32: string;
|
||||
bip32: Bip32;
|
||||
pubKeyHash: number;
|
||||
scriptHash: number;
|
||||
wif: number;
|
||||
}
|
||||
interface Bip32 {
|
||||
public: number;
|
||||
private: number;
|
||||
}
|
||||
export declare const bitcoin: Network;
|
||||
export declare const regtest: Network;
|
||||
export declare const testnet: Network;
|
||||
export {};
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.testnet = exports.regtest = exports.bitcoin = void 0;
|
||||
exports.bitcoin = {
|
||||
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
||||
bech32: 'bc',
|
||||
|
|
7
src/ops.d.ts
vendored
Normal file
7
src/ops.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
declare const OPS: {
|
||||
[key: string]: number;
|
||||
};
|
||||
declare const REVERSE_OPS: {
|
||||
[key: number]: string;
|
||||
};
|
||||
export { OPS, REVERSE_OPS };
|
130
src/ops.js
Normal file
130
src/ops.js
Normal file
|
@ -0,0 +1,130 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.REVERSE_OPS = exports.OPS = void 0;
|
||||
const OPS = {
|
||||
OP_FALSE: 0,
|
||||
OP_0: 0,
|
||||
OP_PUSHDATA1: 76,
|
||||
OP_PUSHDATA2: 77,
|
||||
OP_PUSHDATA4: 78,
|
||||
OP_1NEGATE: 79,
|
||||
OP_RESERVED: 80,
|
||||
OP_TRUE: 81,
|
||||
OP_1: 81,
|
||||
OP_2: 82,
|
||||
OP_3: 83,
|
||||
OP_4: 84,
|
||||
OP_5: 85,
|
||||
OP_6: 86,
|
||||
OP_7: 87,
|
||||
OP_8: 88,
|
||||
OP_9: 89,
|
||||
OP_10: 90,
|
||||
OP_11: 91,
|
||||
OP_12: 92,
|
||||
OP_13: 93,
|
||||
OP_14: 94,
|
||||
OP_15: 95,
|
||||
OP_16: 96,
|
||||
OP_NOP: 97,
|
||||
OP_VER: 98,
|
||||
OP_IF: 99,
|
||||
OP_NOTIF: 100,
|
||||
OP_VERIF: 101,
|
||||
OP_VERNOTIF: 102,
|
||||
OP_ELSE: 103,
|
||||
OP_ENDIF: 104,
|
||||
OP_VERIFY: 105,
|
||||
OP_RETURN: 106,
|
||||
OP_TOALTSTACK: 107,
|
||||
OP_FROMALTSTACK: 108,
|
||||
OP_2DROP: 109,
|
||||
OP_2DUP: 110,
|
||||
OP_3DUP: 111,
|
||||
OP_2OVER: 112,
|
||||
OP_2ROT: 113,
|
||||
OP_2SWAP: 114,
|
||||
OP_IFDUP: 115,
|
||||
OP_DEPTH: 116,
|
||||
OP_DROP: 117,
|
||||
OP_DUP: 118,
|
||||
OP_NIP: 119,
|
||||
OP_OVER: 120,
|
||||
OP_PICK: 121,
|
||||
OP_ROLL: 122,
|
||||
OP_ROT: 123,
|
||||
OP_SWAP: 124,
|
||||
OP_TUCK: 125,
|
||||
OP_CAT: 126,
|
||||
OP_SUBSTR: 127,
|
||||
OP_LEFT: 128,
|
||||
OP_RIGHT: 129,
|
||||
OP_SIZE: 130,
|
||||
OP_INVERT: 131,
|
||||
OP_AND: 132,
|
||||
OP_OR: 133,
|
||||
OP_XOR: 134,
|
||||
OP_EQUAL: 135,
|
||||
OP_EQUALVERIFY: 136,
|
||||
OP_RESERVED1: 137,
|
||||
OP_RESERVED2: 138,
|
||||
OP_1ADD: 139,
|
||||
OP_1SUB: 140,
|
||||
OP_2MUL: 141,
|
||||
OP_2DIV: 142,
|
||||
OP_NEGATE: 143,
|
||||
OP_ABS: 144,
|
||||
OP_NOT: 145,
|
||||
OP_0NOTEQUAL: 146,
|
||||
OP_ADD: 147,
|
||||
OP_SUB: 148,
|
||||
OP_MUL: 149,
|
||||
OP_DIV: 150,
|
||||
OP_MOD: 151,
|
||||
OP_LSHIFT: 152,
|
||||
OP_RSHIFT: 153,
|
||||
OP_BOOLAND: 154,
|
||||
OP_BOOLOR: 155,
|
||||
OP_NUMEQUAL: 156,
|
||||
OP_NUMEQUALVERIFY: 157,
|
||||
OP_NUMNOTEQUAL: 158,
|
||||
OP_LESSTHAN: 159,
|
||||
OP_GREATERTHAN: 160,
|
||||
OP_LESSTHANOREQUAL: 161,
|
||||
OP_GREATERTHANOREQUAL: 162,
|
||||
OP_MIN: 163,
|
||||
OP_MAX: 164,
|
||||
OP_WITHIN: 165,
|
||||
OP_RIPEMD160: 166,
|
||||
OP_SHA1: 167,
|
||||
OP_SHA256: 168,
|
||||
OP_HASH160: 169,
|
||||
OP_HASH256: 170,
|
||||
OP_CODESEPARATOR: 171,
|
||||
OP_CHECKSIG: 172,
|
||||
OP_CHECKSIGVERIFY: 173,
|
||||
OP_CHECKMULTISIG: 174,
|
||||
OP_CHECKMULTISIGVERIFY: 175,
|
||||
OP_NOP1: 176,
|
||||
OP_NOP2: 177,
|
||||
OP_CHECKLOCKTIMEVERIFY: 177,
|
||||
OP_NOP3: 178,
|
||||
OP_CHECKSEQUENCEVERIFY: 178,
|
||||
OP_NOP4: 179,
|
||||
OP_NOP5: 180,
|
||||
OP_NOP6: 181,
|
||||
OP_NOP7: 182,
|
||||
OP_NOP8: 183,
|
||||
OP_NOP9: 184,
|
||||
OP_NOP10: 185,
|
||||
OP_PUBKEYHASH: 253,
|
||||
OP_PUBKEY: 254,
|
||||
OP_INVALIDOPCODE: 255,
|
||||
};
|
||||
exports.OPS = OPS;
|
||||
const REVERSE_OPS = {};
|
||||
exports.REVERSE_OPS = REVERSE_OPS;
|
||||
for (const op of Object.keys(OPS)) {
|
||||
const code = OPS[op];
|
||||
REVERSE_OPS[code] = op;
|
||||
}
|
2
src/payments/embed.d.ts
vendored
Normal file
2
src/payments/embed.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { Payment, PaymentOpts } from './index';
|
||||
export declare function p2data(a: Payment, opts?: PaymentOpts): Payment;
|
|
@ -1,9 +1,10 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.p2data = void 0;
|
||||
const networks_1 = require('../networks');
|
||||
const bscript = require('../script');
|
||||
const types_1 = require('../types');
|
||||
const lazy = require('./lazy');
|
||||
const typef = require('typeforce');
|
||||
const OPS = bscript.OPS;
|
||||
function stacksEqual(a, b) {
|
||||
if (a.length !== b.length) return false;
|
||||
|
@ -15,11 +16,13 @@ function stacksEqual(a, b) {
|
|||
function p2data(a, opts) {
|
||||
if (!a.data && !a.output) throw new TypeError('Not enough data');
|
||||
opts = Object.assign({ validate: true }, opts || {});
|
||||
typef(
|
||||
(0, types_1.typeforce)(
|
||||
{
|
||||
network: typef.maybe(typef.Object),
|
||||
output: typef.maybe(typef.Buffer),
|
||||
data: typef.maybe(typef.arrayOf(typef.Buffer)),
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
data: types_1.typeforce.maybe(
|
||||
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
|
||||
),
|
||||
},
|
||||
a,
|
||||
);
|
||||
|
@ -38,7 +41,7 @@ function p2data(a, opts) {
|
|||
if (a.output) {
|
||||
const chunks = bscript.decompile(a.output);
|
||||
if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid');
|
||||
if (!chunks.slice(1).every(typef.Buffer))
|
||||
if (!chunks.slice(1).every(types_1.typeforce.Buffer))
|
||||
throw new TypeError('Output is invalid');
|
||||
if (a.data && !stacksEqual(a.data, o.data))
|
||||
throw new TypeError('Data mismatch');
|
||||
|
|
36
src/payments/index.d.ts
vendored
Normal file
36
src/payments/index.d.ts
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
/// <reference types="node" />
|
||||
import { Network } from '../networks';
|
||||
import { p2data as embed } from './embed';
|
||||
import { p2ms } from './p2ms';
|
||||
import { p2pk } from './p2pk';
|
||||
import { p2pkh } from './p2pkh';
|
||||
import { p2sh } from './p2sh';
|
||||
import { p2wpkh } from './p2wpkh';
|
||||
import { p2wsh } from './p2wsh';
|
||||
export interface Payment {
|
||||
name?: string;
|
||||
network?: Network;
|
||||
output?: Buffer;
|
||||
data?: Buffer[];
|
||||
m?: number;
|
||||
n?: number;
|
||||
pubkeys?: Buffer[];
|
||||
input?: Buffer;
|
||||
signatures?: Buffer[];
|
||||
pubkey?: Buffer;
|
||||
signature?: Buffer;
|
||||
address?: string;
|
||||
hash?: Buffer;
|
||||
redeem?: Payment;
|
||||
witness?: Buffer[];
|
||||
}
|
||||
export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
|
||||
export declare type PaymentFunction = () => Payment;
|
||||
export interface PaymentOpts {
|
||||
validate?: boolean;
|
||||
allowIncomplete?: boolean;
|
||||
}
|
||||
export declare type StackElement = Buffer | number;
|
||||
export declare type Stack = StackElement[];
|
||||
export declare type StackFunction = () => Stack;
|
||||
export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh };
|
|
@ -1,18 +1,54 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.p2wsh = exports.p2wpkh = exports.p2sh = exports.p2pkh = exports.p2pk = exports.p2ms = exports.embed = void 0;
|
||||
const embed_1 = require('./embed');
|
||||
exports.embed = embed_1.p2data;
|
||||
Object.defineProperty(exports, 'embed', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return embed_1.p2data;
|
||||
},
|
||||
});
|
||||
const p2ms_1 = require('./p2ms');
|
||||
exports.p2ms = p2ms_1.p2ms;
|
||||
Object.defineProperty(exports, 'p2ms', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return p2ms_1.p2ms;
|
||||
},
|
||||
});
|
||||
const p2pk_1 = require('./p2pk');
|
||||
exports.p2pk = p2pk_1.p2pk;
|
||||
Object.defineProperty(exports, 'p2pk', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return p2pk_1.p2pk;
|
||||
},
|
||||
});
|
||||
const p2pkh_1 = require('./p2pkh');
|
||||
exports.p2pkh = p2pkh_1.p2pkh;
|
||||
Object.defineProperty(exports, 'p2pkh', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return p2pkh_1.p2pkh;
|
||||
},
|
||||
});
|
||||
const p2sh_1 = require('./p2sh');
|
||||
exports.p2sh = p2sh_1.p2sh;
|
||||
Object.defineProperty(exports, 'p2sh', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return p2sh_1.p2sh;
|
||||
},
|
||||
});
|
||||
const p2wpkh_1 = require('./p2wpkh');
|
||||
exports.p2wpkh = p2wpkh_1.p2wpkh;
|
||||
Object.defineProperty(exports, 'p2wpkh', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return p2wpkh_1.p2wpkh;
|
||||
},
|
||||
});
|
||||
const p2wsh_1 = require('./p2wsh');
|
||||
exports.p2wsh = p2wsh_1.p2wsh;
|
||||
Object.defineProperty(exports, 'p2wsh', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return p2wsh_1.p2wsh;
|
||||
},
|
||||
});
|
||||
// TODO
|
||||
// witness commitment
|
||||
|
|
2
src/payments/lazy.d.ts
vendored
Normal file
2
src/payments/lazy.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
export declare function prop(object: {}, name: string, f: () => any): void;
|
||||
export declare function value<T>(f: () => T): () => T;
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.value = exports.prop = void 0;
|
||||
function prop(object, name, f) {
|
||||
Object.defineProperty(object, name, {
|
||||
configurable: true,
|
||||
|
|
2
src/payments/p2ms.d.ts
vendored
Normal file
2
src/payments/p2ms.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { Payment, PaymentOpts } from './index';
|
||||
export declare function p2ms(a: Payment, opts?: PaymentOpts): Payment;
|
|
@ -1,11 +1,11 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.p2ms = void 0;
|
||||
const networks_1 = require('../networks');
|
||||
const bscript = require('../script');
|
||||
const types_1 = require('../types');
|
||||
const lazy = require('./lazy');
|
||||
const OPS = bscript.OPS;
|
||||
const typef = require('typeforce');
|
||||
const ecc = require('tiny-secp256k1');
|
||||
const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
|
||||
function stacksEqual(a, b) {
|
||||
if (a.length !== b.length) return false;
|
||||
|
@ -30,15 +30,19 @@ function p2ms(a, opts) {
|
|||
(opts.allowIncomplete && x === OPS.OP_0) !== undefined
|
||||
);
|
||||
}
|
||||
typef(
|
||||
(0, types_1.typeforce)(
|
||||
{
|
||||
network: typef.maybe(typef.Object),
|
||||
m: typef.maybe(typef.Number),
|
||||
n: typef.maybe(typef.Number),
|
||||
output: typef.maybe(typef.Buffer),
|
||||
pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)),
|
||||
signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)),
|
||||
input: typef.maybe(typef.Buffer),
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
m: types_1.typeforce.maybe(types_1.typeforce.Number),
|
||||
n: types_1.typeforce.maybe(types_1.typeforce.Number),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
pubkeys: types_1.typeforce.maybe(
|
||||
types_1.typeforce.arrayOf(types_1.isPoint),
|
||||
),
|
||||
signatures: types_1.typeforce.maybe(
|
||||
types_1.typeforce.arrayOf(isAcceptableSignature),
|
||||
),
|
||||
input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
},
|
||||
a,
|
||||
);
|
||||
|
@ -101,14 +105,15 @@ function p2ms(a, opts) {
|
|||
if (opts.validate) {
|
||||
if (a.output) {
|
||||
decode(a.output);
|
||||
if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid');
|
||||
if (!typef.Number(chunks[chunks.length - 2]))
|
||||
if (!types_1.typeforce.Number(chunks[0]))
|
||||
throw new TypeError('Output is invalid');
|
||||
if (!types_1.typeforce.Number(chunks[chunks.length - 2]))
|
||||
throw new TypeError('Output is invalid');
|
||||
if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG)
|
||||
throw new TypeError('Output is invalid');
|
||||
if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3)
|
||||
throw new TypeError('Output is invalid');
|
||||
if (!o.pubkeys.every(x => ecc.isPoint(x)))
|
||||
if (!o.pubkeys.every(x => (0, types_1.isPoint)(x)))
|
||||
throw new TypeError('Output is invalid');
|
||||
if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch');
|
||||
if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch');
|
||||
|
|
2
src/payments/p2pk.d.ts
vendored
Normal file
2
src/payments/p2pk.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { Payment, PaymentOpts } from './index';
|
||||
export declare function p2pk(a: Payment, opts?: PaymentOpts): Payment;
|
|
@ -1,24 +1,24 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.p2pk = void 0;
|
||||
const networks_1 = require('../networks');
|
||||
const bscript = require('../script');
|
||||
const types_1 = require('../types');
|
||||
const lazy = require('./lazy');
|
||||
const typef = require('typeforce');
|
||||
const OPS = bscript.OPS;
|
||||
const ecc = require('tiny-secp256k1');
|
||||
// input: {signature}
|
||||
// output: {pubKey} OP_CHECKSIG
|
||||
function p2pk(a, opts) {
|
||||
if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature)
|
||||
throw new TypeError('Not enough data');
|
||||
opts = Object.assign({ validate: true }, opts || {});
|
||||
typef(
|
||||
(0, types_1.typeforce)(
|
||||
{
|
||||
network: typef.maybe(typef.Object),
|
||||
output: typef.maybe(typef.Buffer),
|
||||
pubkey: typef.maybe(ecc.isPoint),
|
||||
signature: typef.maybe(bscript.isCanonicalScriptSignature),
|
||||
input: typef.maybe(typef.Buffer),
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
pubkey: types_1.typeforce.maybe(types_1.isPoint),
|
||||
signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
|
||||
input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
},
|
||||
a,
|
||||
);
|
||||
|
@ -52,7 +52,7 @@ function p2pk(a, opts) {
|
|||
if (a.output) {
|
||||
if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG)
|
||||
throw new TypeError('Output is invalid');
|
||||
if (!ecc.isPoint(o.pubkey))
|
||||
if (!(0, types_1.isPoint)(o.pubkey))
|
||||
throw new TypeError('Output pubkey is invalid');
|
||||
if (a.pubkey && !a.pubkey.equals(o.pubkey))
|
||||
throw new TypeError('Pubkey mismatch');
|
||||
|
|
2
src/payments/p2pkh.d.ts
vendored
Normal file
2
src/payments/p2pkh.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { Payment, PaymentOpts } from './index';
|
||||
export declare function p2pkh(a: Payment, opts?: PaymentOpts): Payment;
|
|
@ -1,28 +1,28 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.p2pkh = void 0;
|
||||
const bcrypto = require('../crypto');
|
||||
const networks_1 = require('../networks');
|
||||
const bscript = require('../script');
|
||||
const types_1 = require('../types');
|
||||
const lazy = require('./lazy');
|
||||
const typef = require('typeforce');
|
||||
const OPS = bscript.OPS;
|
||||
const ecc = require('tiny-secp256k1');
|
||||
const bs58check = require('bs58check');
|
||||
const OPS = bscript.OPS;
|
||||
// input: {signature} {pubkey}
|
||||
// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG
|
||||
function p2pkh(a, opts) {
|
||||
if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input)
|
||||
throw new TypeError('Not enough data');
|
||||
opts = Object.assign({ validate: true }, opts || {});
|
||||
typef(
|
||||
(0, types_1.typeforce)(
|
||||
{
|
||||
network: typef.maybe(typef.Object),
|
||||
address: typef.maybe(typef.String),
|
||||
hash: typef.maybe(typef.BufferN(20)),
|
||||
output: typef.maybe(typef.BufferN(25)),
|
||||
pubkey: typef.maybe(ecc.isPoint),
|
||||
signature: typef.maybe(bscript.isCanonicalScriptSignature),
|
||||
input: typef.maybe(typef.Buffer),
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
address: types_1.typeforce.maybe(types_1.typeforce.String),
|
||||
hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.BufferN(25)),
|
||||
pubkey: types_1.typeforce.maybe(types_1.isPoint),
|
||||
signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
|
||||
input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
},
|
||||
a,
|
||||
);
|
||||
|
@ -116,7 +116,7 @@ function p2pkh(a, opts) {
|
|||
if (chunks.length !== 2) throw new TypeError('Input is invalid');
|
||||
if (!bscript.isCanonicalScriptSignature(chunks[0]))
|
||||
throw new TypeError('Input has invalid signature');
|
||||
if (!ecc.isPoint(chunks[1]))
|
||||
if (!(0, types_1.isPoint)(chunks[1]))
|
||||
throw new TypeError('Input has invalid pubkey');
|
||||
if (a.signature && !a.signature.equals(chunks[0]))
|
||||
throw new TypeError('Signature mismatch');
|
||||
|
|
2
src/payments/p2sh.d.ts
vendored
Normal file
2
src/payments/p2sh.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { Payment, PaymentOpts } from './index';
|
||||
export declare function p2sh(a: Payment, opts?: PaymentOpts): Payment;
|
|
@ -1,12 +1,13 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.p2sh = void 0;
|
||||
const bcrypto = require('../crypto');
|
||||
const networks_1 = require('../networks');
|
||||
const bscript = require('../script');
|
||||
const types_1 = require('../types');
|
||||
const lazy = require('./lazy');
|
||||
const typef = require('typeforce');
|
||||
const OPS = bscript.OPS;
|
||||
const bs58check = require('bs58check');
|
||||
const OPS = bscript.OPS;
|
||||
function stacksEqual(a, b) {
|
||||
if (a.length !== b.length) return false;
|
||||
return a.every((x, i) => {
|
||||
|
@ -20,20 +21,24 @@ function p2sh(a, opts) {
|
|||
if (!a.address && !a.hash && !a.output && !a.redeem && !a.input)
|
||||
throw new TypeError('Not enough data');
|
||||
opts = Object.assign({ validate: true }, opts || {});
|
||||
typef(
|
||||
(0, types_1.typeforce)(
|
||||
{
|
||||
network: typef.maybe(typef.Object),
|
||||
address: typef.maybe(typef.String),
|
||||
hash: typef.maybe(typef.BufferN(20)),
|
||||
output: typef.maybe(typef.BufferN(23)),
|
||||
redeem: typef.maybe({
|
||||
network: typef.maybe(typef.Object),
|
||||
output: typef.maybe(typef.Buffer),
|
||||
input: typef.maybe(typef.Buffer),
|
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
address: types_1.typeforce.maybe(types_1.typeforce.String),
|
||||
hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.BufferN(23)),
|
||||
redeem: types_1.typeforce.maybe({
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
witness: types_1.typeforce.maybe(
|
||||
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
|
||||
),
|
||||
}),
|
||||
input: typef.maybe(typef.Buffer),
|
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
|
||||
input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
witness: types_1.typeforce.maybe(
|
||||
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
|
||||
),
|
||||
},
|
||||
a,
|
||||
);
|
||||
|
|
2
src/payments/p2wpkh.d.ts
vendored
Normal file
2
src/payments/p2wpkh.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { Payment, PaymentOpts } from './index';
|
||||
export declare function p2wpkh(a: Payment, opts?: PaymentOpts): Payment;
|
|
@ -1,13 +1,13 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.p2wpkh = void 0;
|
||||
const bcrypto = require('../crypto');
|
||||
const networks_1 = require('../networks');
|
||||
const bscript = require('../script');
|
||||
const types_1 = require('../types');
|
||||
const lazy = require('./lazy');
|
||||
const typef = require('typeforce');
|
||||
const bech32_1 = require('bech32');
|
||||
const OPS = bscript.OPS;
|
||||
const ecc = require('tiny-secp256k1');
|
||||
const { bech32 } = require('bech32');
|
||||
const EMPTY_BUFFER = Buffer.alloc(0);
|
||||
// witness: {signature} {pubKey}
|
||||
// input: <>
|
||||
|
@ -16,23 +16,25 @@ function p2wpkh(a, opts) {
|
|||
if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness)
|
||||
throw new TypeError('Not enough data');
|
||||
opts = Object.assign({ validate: true }, opts || {});
|
||||
typef(
|
||||
(0, types_1.typeforce)(
|
||||
{
|
||||
address: typef.maybe(typef.String),
|
||||
hash: typef.maybe(typef.BufferN(20)),
|
||||
input: typef.maybe(typef.BufferN(0)),
|
||||
network: typef.maybe(typef.Object),
|
||||
output: typef.maybe(typef.BufferN(22)),
|
||||
pubkey: typef.maybe(ecc.isPoint),
|
||||
signature: typef.maybe(bscript.isCanonicalScriptSignature),
|
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
|
||||
address: types_1.typeforce.maybe(types_1.typeforce.String),
|
||||
hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
|
||||
input: types_1.typeforce.maybe(types_1.typeforce.BufferN(0)),
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.BufferN(22)),
|
||||
pubkey: types_1.typeforce.maybe(types_1.isPoint),
|
||||
signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
|
||||
witness: types_1.typeforce.maybe(
|
||||
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
|
||||
),
|
||||
},
|
||||
a,
|
||||
);
|
||||
const _address = lazy.value(() => {
|
||||
const result = bech32.decode(a.address);
|
||||
const result = bech32_1.bech32.decode(a.address);
|
||||
const version = result.words.shift();
|
||||
const data = bech32.fromWords(result.words);
|
||||
const data = bech32_1.bech32.fromWords(result.words);
|
||||
return {
|
||||
version,
|
||||
prefix: result.prefix,
|
||||
|
@ -43,9 +45,9 @@ function p2wpkh(a, opts) {
|
|||
const o = { name: 'p2wpkh', network };
|
||||
lazy.prop(o, 'address', () => {
|
||||
if (!o.hash) return;
|
||||
const words = bech32.toWords(o.hash);
|
||||
const words = bech32_1.bech32.toWords(o.hash);
|
||||
words.unshift(0x00);
|
||||
return bech32.encode(network.bech32, words);
|
||||
return bech32_1.bech32.encode(network.bech32, words);
|
||||
});
|
||||
lazy.prop(o, 'hash', () => {
|
||||
if (a.output) return a.output.slice(2, 22);
|
||||
|
@ -107,14 +109,14 @@ function p2wpkh(a, opts) {
|
|||
if (hash.length > 0 && !hash.equals(pkh))
|
||||
throw new TypeError('Hash mismatch');
|
||||
else hash = pkh;
|
||||
if (!ecc.isPoint(a.pubkey) || a.pubkey.length !== 33)
|
||||
if (!(0, types_1.isPoint)(a.pubkey) || a.pubkey.length !== 33)
|
||||
throw new TypeError('Invalid pubkey for p2wpkh');
|
||||
}
|
||||
if (a.witness) {
|
||||
if (a.witness.length !== 2) throw new TypeError('Witness is invalid');
|
||||
if (!bscript.isCanonicalScriptSignature(a.witness[0]))
|
||||
throw new TypeError('Witness has invalid signature');
|
||||
if (!ecc.isPoint(a.witness[1]) || a.witness[1].length !== 33)
|
||||
if (!(0, types_1.isPoint)(a.witness[1]) || a.witness[1].length !== 33)
|
||||
throw new TypeError('Witness has invalid pubkey');
|
||||
if (a.signature && !a.signature.equals(a.witness[0]))
|
||||
throw new TypeError('Signature mismatch');
|
||||
|
|
2
src/payments/p2wsh.d.ts
vendored
Normal file
2
src/payments/p2wsh.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { Payment, PaymentOpts } from './index';
|
||||
export declare function p2wsh(a: Payment, opts?: PaymentOpts): Payment;
|
|
@ -1,13 +1,13 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.p2wsh = void 0;
|
||||
const bcrypto = require('../crypto');
|
||||
const networks_1 = require('../networks');
|
||||
const bscript = require('../script');
|
||||
const types_1 = require('../types');
|
||||
const lazy = require('./lazy');
|
||||
const typef = require('typeforce');
|
||||
const bech32_1 = require('bech32');
|
||||
const OPS = bscript.OPS;
|
||||
const ecc = require('tiny-secp256k1');
|
||||
const { bech32 } = require('bech32');
|
||||
const EMPTY_BUFFER = Buffer.alloc(0);
|
||||
function stacksEqual(a, b) {
|
||||
if (a.length !== b.length) return false;
|
||||
|
@ -20,7 +20,7 @@ function chunkHasUncompressedPubkey(chunk) {
|
|||
Buffer.isBuffer(chunk) &&
|
||||
chunk.length === 65 &&
|
||||
chunk[0] === 0x04 &&
|
||||
ecc.isPoint(chunk)
|
||||
(0, types_1.isPoint)(chunk)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
|
@ -34,27 +34,31 @@ function p2wsh(a, opts) {
|
|||
if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness)
|
||||
throw new TypeError('Not enough data');
|
||||
opts = Object.assign({ validate: true }, opts || {});
|
||||
typef(
|
||||
(0, types_1.typeforce)(
|
||||
{
|
||||
network: typef.maybe(typef.Object),
|
||||
address: typef.maybe(typef.String),
|
||||
hash: typef.maybe(typef.BufferN(32)),
|
||||
output: typef.maybe(typef.BufferN(34)),
|
||||
redeem: typef.maybe({
|
||||
input: typef.maybe(typef.Buffer),
|
||||
network: typef.maybe(typef.Object),
|
||||
output: typef.maybe(typef.Buffer),
|
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
address: types_1.typeforce.maybe(types_1.typeforce.String),
|
||||
hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(32)),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.BufferN(34)),
|
||||
redeem: types_1.typeforce.maybe({
|
||||
input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
||||
output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
||||
witness: types_1.typeforce.maybe(
|
||||
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
|
||||
),
|
||||
}),
|
||||
input: typef.maybe(typef.BufferN(0)),
|
||||
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
|
||||
input: types_1.typeforce.maybe(types_1.typeforce.BufferN(0)),
|
||||
witness: types_1.typeforce.maybe(
|
||||
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
|
||||
),
|
||||
},
|
||||
a,
|
||||
);
|
||||
const _address = lazy.value(() => {
|
||||
const result = bech32.decode(a.address);
|
||||
const result = bech32_1.bech32.decode(a.address);
|
||||
const version = result.words.shift();
|
||||
const data = bech32.fromWords(result.words);
|
||||
const data = bech32_1.bech32.fromWords(result.words);
|
||||
return {
|
||||
version,
|
||||
prefix: result.prefix,
|
||||
|
@ -71,9 +75,9 @@ function p2wsh(a, opts) {
|
|||
const o = { network };
|
||||
lazy.prop(o, 'address', () => {
|
||||
if (!o.hash) return;
|
||||
const words = bech32.toWords(o.hash);
|
||||
const words = bech32_1.bech32.toWords(o.hash);
|
||||
words.unshift(0x00);
|
||||
return bech32.encode(network.bech32, words);
|
||||
return bech32_1.bech32.encode(network.bech32, words);
|
||||
});
|
||||
lazy.prop(o, 'hash', () => {
|
||||
if (a.output) return a.output.slice(2);
|
||||
|
|
182
src/psbt.d.ts
vendored
Normal file
182
src/psbt.d.ts
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
/// <reference types="node" />
|
||||
import { Psbt as PsbtBase } from 'bip174';
|
||||
import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174/src/lib/interfaces';
|
||||
import { Network } from './networks';
|
||||
import { Transaction } from './transaction';
|
||||
export interface TransactionInput {
|
||||
hash: string | Buffer;
|
||||
index: number;
|
||||
sequence?: number;
|
||||
}
|
||||
export interface PsbtTxInput extends TransactionInput {
|
||||
hash: Buffer;
|
||||
}
|
||||
export interface TransactionOutput {
|
||||
script: Buffer;
|
||||
value: number;
|
||||
}
|
||||
export interface PsbtTxOutput extends TransactionOutput {
|
||||
address: string | undefined;
|
||||
}
|
||||
export declare type ValidateSigFunction = (pubkey: Buffer, msghash: Buffer, signature: Buffer) => boolean;
|
||||
/**
|
||||
* Psbt class can parse and generate a PSBT binary based off of the BIP174.
|
||||
* There are 6 roles that this class fulfills. (Explained in BIP174)
|
||||
*
|
||||
* Creator: This can be done with `new Psbt()`
|
||||
* Updater: This can be done with `psbt.addInput(input)`, `psbt.addInputs(inputs)`,
|
||||
* `psbt.addOutput(output)`, `psbt.addOutputs(outputs)` when you are looking to
|
||||
* add new inputs and outputs to the PSBT, and `psbt.updateGlobal(itemObject)`,
|
||||
* `psbt.updateInput(itemObject)`, `psbt.updateOutput(itemObject)`
|
||||
* addInput requires hash: Buffer | string; and index: number; as attributes
|
||||
* and can also include any attributes that are used in updateInput method.
|
||||
* addOutput requires script: Buffer; and value: number; and likewise can include
|
||||
* data for updateOutput.
|
||||
* For a list of what attributes should be what types. Check the bip174 library.
|
||||
* Also, check the integration tests for some examples of usage.
|
||||
* Signer: There are a few methods. signAllInputs and signAllInputsAsync, which will search all input
|
||||
* information for your pubkey or pubkeyhash, and only sign inputs where it finds
|
||||
* your info. Or you can explicitly sign a specific input with signInput and
|
||||
* signInputAsync. For the async methods you can create a SignerAsync object
|
||||
* and use something like a hardware wallet to sign with. (You must implement this)
|
||||
* Combiner: psbts can be combined easily with `psbt.combine(psbt2, psbt3, psbt4 ...)`
|
||||
* the psbt calling combine will always have precedence when a conflict occurs.
|
||||
* Combine checks if the internal bitcoin transaction is the same, so be sure that
|
||||
* all sequences, version, locktime, etc. are the same before combining.
|
||||
* Input Finalizer: This role is fairly important. Not only does it need to construct
|
||||
* the input scriptSigs and witnesses, but it SHOULD verify the signatures etc.
|
||||
* Before running `psbt.finalizeAllInputs()` please run `psbt.validateSignaturesOfAllInputs()`
|
||||
* Running any finalize method will delete any data in the input(s) that are no longer
|
||||
* needed due to the finalized scripts containing the information.
|
||||
* Transaction Extractor: This role will perform some checks before returning a
|
||||
* Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
|
||||
*/
|
||||
export declare class Psbt {
|
||||
readonly data: PsbtBase;
|
||||
static fromBase64(data: string, opts?: PsbtOptsOptional): Psbt;
|
||||
static fromHex(data: string, opts?: PsbtOptsOptional): Psbt;
|
||||
static fromBuffer(buffer: Buffer, opts?: PsbtOptsOptional): Psbt;
|
||||
private __CACHE;
|
||||
private opts;
|
||||
constructor(opts?: PsbtOptsOptional, data?: PsbtBase);
|
||||
get inputCount(): number;
|
||||
get version(): number;
|
||||
set version(version: number);
|
||||
get locktime(): number;
|
||||
set locktime(locktime: number);
|
||||
get txInputs(): PsbtTxInput[];
|
||||
get txOutputs(): PsbtTxOutput[];
|
||||
combine(...those: Psbt[]): this;
|
||||
clone(): Psbt;
|
||||
setMaximumFeeRate(satoshiPerByte: number): void;
|
||||
setVersion(version: number): this;
|
||||
setLocktime(locktime: number): this;
|
||||
setInputSequence(inputIndex: number, sequence: number): this;
|
||||
addInputs(inputDatas: PsbtInputExtended[]): this;
|
||||
addInput(inputData: PsbtInputExtended): this;
|
||||
addOutputs(outputDatas: PsbtOutputExtended[]): this;
|
||||
addOutput(outputData: PsbtOutputExtended): this;
|
||||
extractTransaction(disableFeeCheck?: boolean): Transaction;
|
||||
getFeeRate(): number;
|
||||
getFee(): number;
|
||||
finalizeAllInputs(): this;
|
||||
finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc): this;
|
||||
getInputType(inputIndex: number): AllScriptType;
|
||||
inputHasPubkey(inputIndex: number, pubkey: Buffer): boolean;
|
||||
inputHasHDKey(inputIndex: number, root: HDSigner): boolean;
|
||||
outputHasPubkey(outputIndex: number, pubkey: Buffer): boolean;
|
||||
outputHasHDKey(outputIndex: number, root: HDSigner): boolean;
|
||||
validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean;
|
||||
validateSignaturesOfInput(inputIndex: number, validator: ValidateSigFunction, pubkey?: Buffer): boolean;
|
||||
signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this;
|
||||
signAllInputsHDAsync(hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise<void>;
|
||||
signInputHD(inputIndex: number, hdKeyPair: HDSigner, sighashTypes?: number[]): this;
|
||||
signInputHDAsync(inputIndex: number, hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise<void>;
|
||||
signAllInputs(keyPair: Signer, sighashTypes?: number[]): this;
|
||||
signAllInputsAsync(keyPair: Signer | SignerAsync, sighashTypes?: number[]): Promise<void>;
|
||||
signInput(inputIndex: number, keyPair: Signer, sighashTypes?: number[]): this;
|
||||
signInputAsync(inputIndex: number, keyPair: Signer | SignerAsync, sighashTypes?: number[]): Promise<void>;
|
||||
toBuffer(): Buffer;
|
||||
toHex(): string;
|
||||
toBase64(): string;
|
||||
updateGlobal(updateData: PsbtGlobalUpdate): this;
|
||||
updateInput(inputIndex: number, updateData: PsbtInputUpdate): this;
|
||||
updateOutput(outputIndex: number, updateData: PsbtOutputUpdate): this;
|
||||
addUnknownKeyValToGlobal(keyVal: KeyValue): this;
|
||||
addUnknownKeyValToInput(inputIndex: number, keyVal: KeyValue): this;
|
||||
addUnknownKeyValToOutput(outputIndex: number, keyVal: KeyValue): this;
|
||||
clearFinalizedInput(inputIndex: number): this;
|
||||
}
|
||||
interface PsbtOptsOptional {
|
||||
network?: Network;
|
||||
maximumFeeRate?: number;
|
||||
}
|
||||
interface PsbtInputExtended extends PsbtInput, TransactionInput {
|
||||
}
|
||||
declare type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
|
||||
interface PsbtOutputExtendedAddress extends PsbtOutput {
|
||||
address: string;
|
||||
value: number;
|
||||
}
|
||||
interface PsbtOutputExtendedScript extends PsbtOutput {
|
||||
script: Buffer;
|
||||
value: number;
|
||||
}
|
||||
interface HDSignerBase {
|
||||
/**
|
||||
* DER format compressed publicKey buffer
|
||||
*/
|
||||
publicKey: Buffer;
|
||||
/**
|
||||
* The first 4 bytes of the sha256-ripemd160 of the publicKey
|
||||
*/
|
||||
fingerprint: Buffer;
|
||||
}
|
||||
export interface HDSigner extends HDSignerBase {
|
||||
/**
|
||||
* The path string must match /^m(\/\d+'?)+$/
|
||||
* ex. m/44'/0'/0'/1/23 levels with ' must be hard derivations
|
||||
*/
|
||||
derivePath(path: string): HDSigner;
|
||||
/**
|
||||
* Input hash (the "message digest") for the signature algorithm
|
||||
* Return a 64 byte signature (32 byte r and 32 byte s in that order)
|
||||
*/
|
||||
sign(hash: Buffer): Buffer;
|
||||
}
|
||||
/**
|
||||
* Same as above but with async sign method
|
||||
*/
|
||||
export interface HDSignerAsync extends HDSignerBase {
|
||||
derivePath(path: string): HDSignerAsync;
|
||||
sign(hash: Buffer): Promise<Buffer>;
|
||||
}
|
||||
export interface Signer {
|
||||
publicKey: Buffer;
|
||||
network?: any;
|
||||
sign(hash: Buffer, lowR?: boolean): Buffer;
|
||||
getPublicKey?(): Buffer;
|
||||
}
|
||||
export interface SignerAsync {
|
||||
publicKey: Buffer;
|
||||
network?: any;
|
||||
sign(hash: Buffer, lowR?: boolean): Promise<Buffer>;
|
||||
getPublicKey?(): Buffer;
|
||||
}
|
||||
/**
|
||||
* This function must do two things:
|
||||
* 1. Check if the `input` can be finalized. If it can not be finalized, throw.
|
||||
* ie. `Can not finalize input #${inputIndex}`
|
||||
* 2. Create the finalScriptSig and finalScriptWitness Buffers.
|
||||
*/
|
||||
declare type FinalScriptsFunc = (inputIndex: number, // Which input is it?
|
||||
input: PsbtInput, // The PSBT input contents
|
||||
script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
|
||||
isSegwit: boolean, // Is it segwit?
|
||||
isP2SH: boolean, // Is it P2SH?
|
||||
isP2WSH: boolean) => {
|
||||
finalScriptSig: Buffer | undefined;
|
||||
finalScriptWitness: Buffer | undefined;
|
||||
};
|
||||
declare type AllScriptType = 'witnesspubkeyhash' | 'pubkeyhash' | 'multisig' | 'pubkey' | 'nonstandard' | 'p2sh-witnesspubkeyhash' | 'p2sh-pubkeyhash' | 'p2sh-multisig' | 'p2sh-pubkey' | 'p2sh-nonstandard' | 'p2wsh-pubkeyhash' | 'p2wsh-multisig' | 'p2wsh-pubkey' | 'p2wsh-nonstandard' | 'p2sh-p2wsh-pubkeyhash' | 'p2sh-p2wsh-multisig' | 'p2sh-p2wsh-pubkey' | 'p2sh-p2wsh-nonstandard';
|
||||
export {};
|
101
src/psbt.js
101
src/psbt.js
|
@ -1,12 +1,12 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.Psbt = void 0;
|
||||
const bip174_1 = require('bip174');
|
||||
const varuint = require('bip174/src/lib/converter/varint');
|
||||
const utils_1 = require('bip174/src/lib/utils');
|
||||
const address_1 = require('./address');
|
||||
const bufferutils_1 = require('./bufferutils');
|
||||
const crypto_1 = require('./crypto');
|
||||
const ecpair_1 = require('./ecpair');
|
||||
const networks_1 = require('./networks');
|
||||
const payments = require('./payments');
|
||||
const bscript = require('./script');
|
||||
|
@ -25,7 +25,7 @@ const DEFAULT_OPTS = {
|
|||
* THIS IS NOT TO BE RELIED ON.
|
||||
* It is only here as a last ditch effort to prevent sending a 500 BTC fee etc.
|
||||
*/
|
||||
maximumFeeRate: 5000,
|
||||
maximumFeeRate: 5000, // satoshi per byte
|
||||
};
|
||||
/**
|
||||
* Psbt class can parse and generate a PSBT binary based off of the BIP174.
|
||||
|
@ -60,6 +60,23 @@ const DEFAULT_OPTS = {
|
|||
* Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
|
||||
*/
|
||||
class Psbt {
|
||||
data;
|
||||
static fromBase64(data, opts = {}) {
|
||||
const buffer = Buffer.from(data, 'base64');
|
||||
return this.fromBuffer(buffer, opts);
|
||||
}
|
||||
static fromHex(data, opts = {}) {
|
||||
const buffer = Buffer.from(data, 'hex');
|
||||
return this.fromBuffer(buffer, opts);
|
||||
}
|
||||
static fromBuffer(buffer, opts = {}) {
|
||||
const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
|
||||
const psbt = new Psbt(opts, psbtBase);
|
||||
checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
|
||||
return psbt;
|
||||
}
|
||||
__CACHE;
|
||||
opts;
|
||||
constructor(opts = {}, data = new bip174_1.Psbt(new PsbtTransaction())) {
|
||||
this.data = data;
|
||||
// set defaults
|
||||
|
@ -69,6 +86,8 @@ class Psbt {
|
|||
__NON_WITNESS_UTXO_BUF_CACHE: [],
|
||||
__TX_IN_CACHE: {},
|
||||
__TX: this.data.globalMap.unsignedTx.tx,
|
||||
// Psbt's predecesor (TransactionBuilder - now removed) behavior
|
||||
// was to not confirm input values before signing.
|
||||
// Even though we highly encourage people to get
|
||||
// the full parent transaction to verify values, the ability to
|
||||
// sign non-segwit inputs without the full transaction was often
|
||||
|
@ -87,20 +106,6 @@ class Psbt {
|
|||
dpew(this, '__CACHE', false, true);
|
||||
dpew(this, 'opts', false, true);
|
||||
}
|
||||
static fromBase64(data, opts = {}) {
|
||||
const buffer = Buffer.from(data, 'base64');
|
||||
return this.fromBuffer(buffer, opts);
|
||||
}
|
||||
static fromHex(data, opts = {}) {
|
||||
const buffer = Buffer.from(data, 'hex');
|
||||
return this.fromBuffer(buffer, opts);
|
||||
}
|
||||
static fromBuffer(buffer, opts = {}) {
|
||||
const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
|
||||
const psbt = new Psbt(opts, psbtBase);
|
||||
checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
|
||||
return psbt;
|
||||
}
|
||||
get inputCount() {
|
||||
return this.data.inputs.length;
|
||||
}
|
||||
|
@ -118,7 +123,7 @@ class Psbt {
|
|||
}
|
||||
get txInputs() {
|
||||
return this.__CACHE.__TX.ins.map(input => ({
|
||||
hash: bufferutils_1.cloneBuffer(input.hash),
|
||||
hash: (0, bufferutils_1.cloneBuffer)(input.hash),
|
||||
index: input.index,
|
||||
sequence: input.sequence,
|
||||
}));
|
||||
|
@ -127,10 +132,13 @@ class Psbt {
|
|||
return this.__CACHE.__TX.outs.map(output => {
|
||||
let address;
|
||||
try {
|
||||
address = address_1.fromOutputScript(output.script, this.opts.network);
|
||||
address = (0, address_1.fromOutputScript)(
|
||||
output.script,
|
||||
this.opts.network,
|
||||
);
|
||||
} catch (_) {}
|
||||
return {
|
||||
script: bufferutils_1.cloneBuffer(output.script),
|
||||
script: (0, bufferutils_1.cloneBuffer)(output.script),
|
||||
value: output.value,
|
||||
address,
|
||||
};
|
||||
|
@ -229,7 +237,7 @@ class Psbt {
|
|||
const { address } = outputData;
|
||||
if (typeof address === 'string') {
|
||||
const { network } = this.opts;
|
||||
const script = address_1.toOutputScript(address, network);
|
||||
const script = (0, address_1.toOutputScript)(address, network);
|
||||
outputData = Object.assign(outputData, { script });
|
||||
}
|
||||
const c = this.__CACHE;
|
||||
|
@ -262,12 +270,12 @@ class Psbt {
|
|||
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
|
||||
}
|
||||
finalizeAllInputs() {
|
||||
utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
|
||||
(0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one
|
||||
range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
|
||||
return this;
|
||||
}
|
||||
finalizeInput(inputIndex, finalScriptsFunc = getFinalScripts) {
|
||||
const input = utils_1.checkForInput(this.data.inputs, inputIndex);
|
||||
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
|
||||
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
|
||||
inputIndex,
|
||||
input,
|
||||
|
@ -292,7 +300,7 @@ class Psbt {
|
|||
return this;
|
||||
}
|
||||
getInputType(inputIndex) {
|
||||
const input = utils_1.checkForInput(this.data.inputs, inputIndex);
|
||||
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
|
||||
const script = getScriptFromUtxo(inputIndex, input, this.__CACHE);
|
||||
const result = getMeaningfulScript(
|
||||
script,
|
||||
|
@ -307,39 +315,41 @@ class Psbt {
|
|||
return type + mainType;
|
||||
}
|
||||
inputHasPubkey(inputIndex, pubkey) {
|
||||
const input = utils_1.checkForInput(this.data.inputs, inputIndex);
|
||||
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
|
||||
return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE);
|
||||
}
|
||||
inputHasHDKey(inputIndex, root) {
|
||||
const input = utils_1.checkForInput(this.data.inputs, inputIndex);
|
||||
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
|
||||
const derivationIsMine = bip32DerivationIsMine(root);
|
||||
return (
|
||||
!!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine)
|
||||
);
|
||||
}
|
||||
outputHasPubkey(outputIndex, pubkey) {
|
||||
const output = utils_1.checkForOutput(this.data.outputs, outputIndex);
|
||||
const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex);
|
||||
return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE);
|
||||
}
|
||||
outputHasHDKey(outputIndex, root) {
|
||||
const output = utils_1.checkForOutput(this.data.outputs, outputIndex);
|
||||
const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex);
|
||||
const derivationIsMine = bip32DerivationIsMine(root);
|
||||
return (
|
||||
!!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine)
|
||||
);
|
||||
}
|
||||
validateSignaturesOfAllInputs() {
|
||||
utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
|
||||
validateSignaturesOfAllInputs(validator) {
|
||||
(0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one
|
||||
const results = range(this.data.inputs.length).map(idx =>
|
||||
this.validateSignaturesOfInput(idx),
|
||||
this.validateSignaturesOfInput(idx, validator),
|
||||
);
|
||||
return results.reduce((final, res) => res === true && final, true);
|
||||
}
|
||||
validateSignaturesOfInput(inputIndex, pubkey) {
|
||||
validateSignaturesOfInput(inputIndex, validator, pubkey) {
|
||||
const input = this.data.inputs[inputIndex];
|
||||
const partialSig = (input || {}).partialSig;
|
||||
if (!input || !partialSig || partialSig.length < 1)
|
||||
throw new Error('No signatures to validate');
|
||||
if (typeof validator !== 'function')
|
||||
throw new Error('Need validator function to validate signatures');
|
||||
const mySigs = pubkey
|
||||
? partialSig.filter(sig => sig.pubkey.equals(pubkey))
|
||||
: partialSig;
|
||||
|
@ -363,8 +373,7 @@ class Psbt {
|
|||
hashCache = hash;
|
||||
scriptCache = script;
|
||||
checkScriptForPubkey(pSig.pubkey, script, 'verify');
|
||||
const keypair = ecpair_1.fromPublicKey(pSig.pubkey);
|
||||
results.push(keypair.verify(hash, sig.signature));
|
||||
results.push(validator(pSig.pubkey, hash, sig.signature));
|
||||
}
|
||||
return results.every(res => res === true);
|
||||
}
|
||||
|
@ -616,6 +625,7 @@ const transactionFromBuffer = buffer => new PsbtTransaction(buffer);
|
|||
* It contains a bitcoinjs-lib Transaction object.
|
||||
*/
|
||||
class PsbtTransaction {
|
||||
tx;
|
||||
constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) {
|
||||
this.tx = transaction_1.Transaction.fromBuffer(buffer);
|
||||
checkTxEmpty(this.tx);
|
||||
|
@ -641,7 +651,7 @@ class PsbtTransaction {
|
|||
}
|
||||
const hash =
|
||||
typeof input.hash === 'string'
|
||||
? bufferutils_1.reverseBuffer(Buffer.from(input.hash, 'hex'))
|
||||
? (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash, 'hex'))
|
||||
: input.hash;
|
||||
this.tx.addInput(hash, input.index, input.sequence);
|
||||
}
|
||||
|
@ -684,8 +694,7 @@ function hasSigs(neededSigs, partialSig, pubkeys) {
|
|||
if (pubkeys) {
|
||||
sigs = pubkeys
|
||||
.map(pkey => {
|
||||
const pubkey = ecpair_1.fromPublicKey(pkey, { compressed: true })
|
||||
.publicKey;
|
||||
const pubkey = compressPubkey(pkey);
|
||||
return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
|
||||
})
|
||||
.filter(v => !!v);
|
||||
|
@ -816,7 +825,7 @@ function checkTxForDupeIns(tx, cache) {
|
|||
}
|
||||
function checkTxInputCache(cache, input) {
|
||||
const key =
|
||||
bufferutils_1.reverseBuffer(Buffer.from(input.hash)).toString('hex') +
|
||||
(0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash)).toString('hex') +
|
||||
':' +
|
||||
input.index;
|
||||
if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.');
|
||||
|
@ -911,7 +920,7 @@ function getHashAndSighashType(
|
|||
cache,
|
||||
sighashTypes,
|
||||
) {
|
||||
const input = utils_1.checkForInput(inputs, inputIndex);
|
||||
const input = (0, utils_1.checkForInput)(inputs, inputIndex);
|
||||
const { hash, sighashType, script } = getHashForSig(
|
||||
inputIndex,
|
||||
input,
|
||||
|
@ -997,7 +1006,8 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
|
|||
console.warn(
|
||||
'Warning: Signing non-segwit inputs without the full parent transaction ' +
|
||||
'means there is a chance that a miner could feed you incorrect information ' +
|
||||
'to trick you into paying large fees. You are not ' +
|
||||
"to trick you into paying large fees. This behavior is the same as Psbt's predecesor " +
|
||||
'(TransactionBuilder - now removed) when signing non-segwit scripts. You are not ' +
|
||||
'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
|
||||
'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
|
||||
'*********************',
|
||||
|
@ -1094,7 +1104,7 @@ function getScriptFromInput(inputIndex, input, cache) {
|
|||
return res;
|
||||
}
|
||||
function getSignersFromHD(inputIndex, inputs, hdKeyPair) {
|
||||
const input = utils_1.checkForInput(inputs, inputIndex);
|
||||
const input = (0, utils_1.checkForInput)(inputs, inputIndex);
|
||||
if (!input.bip32Derivation || input.bip32Derivation.length === 0) {
|
||||
throw new Error('Need bip32Derivation to sign with HD');
|
||||
}
|
||||
|
@ -1321,6 +1331,15 @@ function redeemFromFinalWitnessScript(finalScript) {
|
|||
if (!sDecomp) return;
|
||||
return lastItem;
|
||||
}
|
||||
function compressPubkey(pubkey) {
|
||||
if (pubkey.length === 65) {
|
||||
const parity = pubkey[64] & 1;
|
||||
const newKey = pubkey.slice(0, 33);
|
||||
newKey[0] = 2 | parity;
|
||||
return newKey;
|
||||
}
|
||||
return pubkey.slice();
|
||||
}
|
||||
function isPubkeyLike(buf) {
|
||||
return buf.length === 33 && bscript.isCanonicalPubKey(buf);
|
||||
}
|
||||
|
@ -1376,7 +1395,7 @@ function checkInvalidP2WSH(script) {
|
|||
}
|
||||
}
|
||||
function pubkeyInScript(pubkey, script) {
|
||||
const pubkeyHash = crypto_1.hash160(pubkey);
|
||||
const pubkeyHash = (0, crypto_1.hash160)(pubkey);
|
||||
const decompiled = bscript.decompile(script);
|
||||
if (decompiled === null) throw new Error('Unknown script error');
|
||||
return decompiled.some(element => {
|
||||
|
|
8
src/push_data.d.ts
vendored
Normal file
8
src/push_data.d.ts
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
/// <reference types="node" />
|
||||
export declare function encodingLength(i: number): number;
|
||||
export declare function encode(buffer: Buffer, num: number, offset: number): number;
|
||||
export declare function decode(buffer: Buffer, offset: number): {
|
||||
opcode: number;
|
||||
number: number;
|
||||
size: number;
|
||||
} | null;
|
61
src/push_data.js
Normal file
61
src/push_data.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.decode = exports.encode = exports.encodingLength = void 0;
|
||||
const ops_1 = require('./ops');
|
||||
function encodingLength(i) {
|
||||
return i < ops_1.OPS.OP_PUSHDATA1 ? 1 : i <= 0xff ? 2 : i <= 0xffff ? 3 : 5;
|
||||
}
|
||||
exports.encodingLength = encodingLength;
|
||||
function encode(buffer, num, offset) {
|
||||
const size = encodingLength(num);
|
||||
// ~6 bit
|
||||
if (size === 1) {
|
||||
buffer.writeUInt8(num, offset);
|
||||
// 8 bit
|
||||
} else if (size === 2) {
|
||||
buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA1, offset);
|
||||
buffer.writeUInt8(num, offset + 1);
|
||||
// 16 bit
|
||||
} else if (size === 3) {
|
||||
buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA2, offset);
|
||||
buffer.writeUInt16LE(num, offset + 1);
|
||||
// 32 bit
|
||||
} else {
|
||||
buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA4, offset);
|
||||
buffer.writeUInt32LE(num, offset + 1);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
exports.encode = encode;
|
||||
function decode(buffer, offset) {
|
||||
const opcode = buffer.readUInt8(offset);
|
||||
let num;
|
||||
let size;
|
||||
// ~6 bit
|
||||
if (opcode < ops_1.OPS.OP_PUSHDATA1) {
|
||||
num = opcode;
|
||||
size = 1;
|
||||
// 8 bit
|
||||
} else if (opcode === ops_1.OPS.OP_PUSHDATA1) {
|
||||
if (offset + 2 > buffer.length) return null;
|
||||
num = buffer.readUInt8(offset + 1);
|
||||
size = 2;
|
||||
// 16 bit
|
||||
} else if (opcode === ops_1.OPS.OP_PUSHDATA2) {
|
||||
if (offset + 3 > buffer.length) return null;
|
||||
num = buffer.readUInt16LE(offset + 1);
|
||||
size = 3;
|
||||
// 32 bit
|
||||
} else {
|
||||
if (offset + 5 > buffer.length) return null;
|
||||
if (opcode !== ops_1.OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode');
|
||||
num = buffer.readUInt32LE(offset + 1);
|
||||
size = 5;
|
||||
}
|
||||
return {
|
||||
opcode,
|
||||
number: num,
|
||||
size,
|
||||
};
|
||||
}
|
||||
exports.decode = decode;
|
17
src/script.d.ts
vendored
Normal file
17
src/script.d.ts
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
/// <reference types="node" />
|
||||
import { OPS } from './ops';
|
||||
import { Stack } from './payments';
|
||||
import * as scriptNumber from './script_number';
|
||||
import * as scriptSignature from './script_signature';
|
||||
export { OPS };
|
||||
export declare function isPushOnly(value: Stack): boolean;
|
||||
export declare function compile(chunks: Buffer | Stack): Buffer;
|
||||
export declare function decompile(buffer: Buffer | Array<number | Buffer>): Array<number | Buffer> | null;
|
||||
export declare function toASM(chunks: Buffer | Array<number | Buffer>): string;
|
||||
export declare function fromASM(asm: string): Buffer;
|
||||
export declare function toStack(chunks: Buffer | Array<number | Buffer>): Buffer[];
|
||||
export declare function isCanonicalPubKey(buffer: Buffer): boolean;
|
||||
export declare function isDefinedHashType(hashType: number): boolean;
|
||||
export declare function isCanonicalScriptSignature(buffer: Buffer): boolean;
|
||||
export declare const number: typeof scriptNumber;
|
||||
export declare const signature: typeof scriptSignature;
|
|
@ -1,21 +1,26 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.signature = exports.number = exports.isCanonicalScriptSignature = exports.isDefinedHashType = exports.isCanonicalPubKey = exports.toStack = exports.fromASM = exports.toASM = exports.decompile = exports.compile = exports.isPushOnly = exports.OPS = void 0;
|
||||
const bip66 = require('./bip66');
|
||||
const ops_1 = require('./ops');
|
||||
Object.defineProperty(exports, 'OPS', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return ops_1.OPS;
|
||||
},
|
||||
});
|
||||
const pushdata = require('./push_data');
|
||||
const scriptNumber = require('./script_number');
|
||||
const scriptSignature = require('./script_signature');
|
||||
const types = require('./types');
|
||||
const bip66 = require('bip66');
|
||||
const ecc = require('tiny-secp256k1');
|
||||
const pushdata = require('pushdata-bitcoin');
|
||||
const typeforce = require('typeforce');
|
||||
exports.OPS = require('bitcoin-ops');
|
||||
const REVERSE_OPS = require('bitcoin-ops/map');
|
||||
const OP_INT_BASE = exports.OPS.OP_RESERVED; // OP_1 - 1
|
||||
const { typeforce } = types;
|
||||
const OP_INT_BASE = ops_1.OPS.OP_RESERVED; // OP_1 - 1
|
||||
function isOPInt(value) {
|
||||
return (
|
||||
types.Number(value) &&
|
||||
(value === exports.OPS.OP_0 ||
|
||||
(value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) ||
|
||||
value === exports.OPS.OP_1NEGATE)
|
||||
(value === ops_1.OPS.OP_0 ||
|
||||
(value >= ops_1.OPS.OP_1 && value <= ops_1.OPS.OP_16) ||
|
||||
value === ops_1.OPS.OP_1NEGATE)
|
||||
);
|
||||
}
|
||||
function isPushOnlyChunk(value) {
|
||||
|
@ -26,10 +31,10 @@ function isPushOnly(value) {
|
|||
}
|
||||
exports.isPushOnly = isPushOnly;
|
||||
function asMinimalOP(buffer) {
|
||||
if (buffer.length === 0) return exports.OPS.OP_0;
|
||||
if (buffer.length === 0) return ops_1.OPS.OP_0;
|
||||
if (buffer.length !== 1) return;
|
||||
if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0];
|
||||
if (buffer[0] === 0x81) return exports.OPS.OP_1NEGATE;
|
||||
if (buffer[0] === 0x81) return ops_1.OPS.OP_1NEGATE;
|
||||
}
|
||||
function chunksIsBuffer(buf) {
|
||||
return Buffer.isBuffer(buf);
|
||||
|
@ -90,7 +95,7 @@ function decompile(buffer) {
|
|||
while (i < buffer.length) {
|
||||
const opcode = buffer[i];
|
||||
// data chunk
|
||||
if (opcode > exports.OPS.OP_0 && opcode <= exports.OPS.OP_PUSHDATA4) {
|
||||
if (opcode > ops_1.OPS.OP_0 && opcode <= ops_1.OPS.OP_PUSHDATA4) {
|
||||
const d = pushdata.decode(buffer, i);
|
||||
// did reading a pushDataInt fail?
|
||||
if (d === null) return null;
|
||||
|
@ -128,7 +133,7 @@ function toASM(chunks) {
|
|||
chunk = op;
|
||||
}
|
||||
// opcode!
|
||||
return REVERSE_OPS[chunk];
|
||||
return ops_1.REVERSE_OPS[chunk];
|
||||
})
|
||||
.join(' ');
|
||||
}
|
||||
|
@ -138,7 +143,7 @@ function fromASM(asm) {
|
|||
return compile(
|
||||
asm.split(' ').map(chunkStr => {
|
||||
// opcode?
|
||||
if (exports.OPS[chunkStr] !== undefined) return exports.OPS[chunkStr];
|
||||
if (ops_1.OPS[chunkStr] !== undefined) return ops_1.OPS[chunkStr];
|
||||
typeforce(types.Hex, chunkStr);
|
||||
// data!
|
||||
return Buffer.from(chunkStr, 'hex');
|
||||
|
@ -151,13 +156,13 @@ function toStack(chunks) {
|
|||
typeforce(isPushOnly, chunks);
|
||||
return chunks.map(op => {
|
||||
if (singleChunkIsBuffer(op)) return op;
|
||||
if (op === exports.OPS.OP_0) return Buffer.allocUnsafe(0);
|
||||
if (op === ops_1.OPS.OP_0) return Buffer.allocUnsafe(0);
|
||||
return scriptNumber.encode(op - OP_INT_BASE);
|
||||
});
|
||||
}
|
||||
exports.toStack = toStack;
|
||||
function isCanonicalPubKey(buffer) {
|
||||
return ecc.isPoint(buffer);
|
||||
return types.isPoint(buffer);
|
||||
}
|
||||
exports.isCanonicalPubKey = isCanonicalPubKey;
|
||||
function isDefinedHashType(hashType) {
|
||||
|
|
3
src/script_number.d.ts
vendored
Normal file
3
src/script_number.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/// <reference types="node" />
|
||||
export declare function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number;
|
||||
export declare function encode(_number: number): Buffer;
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.encode = exports.decode = void 0;
|
||||
function decode(buffer, maxLength, minimal) {
|
||||
maxLength = maxLength || 4;
|
||||
minimal = minimal === undefined ? true : minimal;
|
||||
|
|
8
src/script_signature.d.ts
vendored
Normal file
8
src/script_signature.d.ts
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
/// <reference types="node" />
|
||||
interface ScriptSignature {
|
||||
signature: Buffer;
|
||||
hashType: number;
|
||||
}
|
||||
export declare function decode(buffer: Buffer): ScriptSignature;
|
||||
export declare function encode(signature: Buffer, hashType: number): Buffer;
|
||||
export {};
|
|
@ -1,8 +1,9 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.encode = exports.decode = void 0;
|
||||
const bip66 = require('./bip66');
|
||||
const types = require('./types');
|
||||
const bip66 = require('bip66');
|
||||
const typeforce = require('typeforce');
|
||||
const { typeforce } = types;
|
||||
const ZERO = Buffer.alloc(1, 0);
|
||||
function toDER(x) {
|
||||
let i = 0;
|
||||
|
|
53
src/transaction.d.ts
vendored
Normal file
53
src/transaction.d.ts
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
/// <reference types="node" />
|
||||
export interface Output {
|
||||
script: Buffer;
|
||||
value: number;
|
||||
}
|
||||
export interface Input {
|
||||
hash: Buffer;
|
||||
index: number;
|
||||
script: Buffer;
|
||||
sequence: number;
|
||||
witness: Buffer[];
|
||||
}
|
||||
export declare class Transaction {
|
||||
static readonly DEFAULT_SEQUENCE = 4294967295;
|
||||
static readonly SIGHASH_ALL = 1;
|
||||
static readonly SIGHASH_NONE = 2;
|
||||
static readonly SIGHASH_SINGLE = 3;
|
||||
static readonly SIGHASH_ANYONECANPAY = 128;
|
||||
static readonly ADVANCED_TRANSACTION_MARKER = 0;
|
||||
static readonly ADVANCED_TRANSACTION_FLAG = 1;
|
||||
static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction;
|
||||
static fromHex(hex: string): Transaction;
|
||||
static isCoinbaseHash(buffer: Buffer): boolean;
|
||||
version: number;
|
||||
locktime: number;
|
||||
ins: Input[];
|
||||
outs: Output[];
|
||||
isCoinbase(): boolean;
|
||||
addInput(hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number;
|
||||
addOutput(scriptPubKey: Buffer, value: number): number;
|
||||
hasWitnesses(): boolean;
|
||||
weight(): number;
|
||||
virtualSize(): number;
|
||||
byteLength(_ALLOW_WITNESS?: boolean): number;
|
||||
clone(): Transaction;
|
||||
/**
|
||||
* Hash transaction for signing a specific input.
|
||||
*
|
||||
* Bitcoin uses a different hash for each signed transaction input.
|
||||
* This method copies the transaction, makes the necessary changes based on the
|
||||
* hashType, and then hashes the result.
|
||||
* This hash can then be used to sign the provided transaction input.
|
||||
*/
|
||||
hashForSignature(inIndex: number, prevOutScript: Buffer, hashType: number): Buffer;
|
||||
hashForWitnessV0(inIndex: number, prevOutScript: Buffer, value: number, hashType: number): Buffer;
|
||||
getHash(forWitness?: boolean): Buffer;
|
||||
getId(): string;
|
||||
toBuffer(buffer?: Buffer, initialOffset?: number): Buffer;
|
||||
toHex(): string;
|
||||
setInputScript(index: number, scriptSig: Buffer): void;
|
||||
setWitness(index: number, witness: Buffer[]): void;
|
||||
private __toBuffer;
|
||||
}
|
|
@ -1,20 +1,20 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.Transaction = void 0;
|
||||
const bufferutils_1 = require('./bufferutils');
|
||||
const bcrypto = require('./crypto');
|
||||
const bscript = require('./script');
|
||||
const script_1 = require('./script');
|
||||
const types = require('./types');
|
||||
const typeforce = require('typeforce');
|
||||
const varuint = require('varuint-bitcoin');
|
||||
const { typeforce } = types;
|
||||
function varSliceSize(someScript) {
|
||||
const length = someScript.length;
|
||||
return varuint.encodingLength(length) + length;
|
||||
return bufferutils_1.varuint.encodingLength(length) + length;
|
||||
}
|
||||
function vectorSize(someVector) {
|
||||
const length = someVector.length;
|
||||
return (
|
||||
varuint.encodingLength(length) +
|
||||
bufferutils_1.varuint.encodingLength(length) +
|
||||
someVector.reduce((sum, witness) => {
|
||||
return sum + varSliceSize(witness);
|
||||
}, 0)
|
||||
|
@ -39,12 +39,13 @@ function isOutput(out) {
|
|||
return out.value !== undefined;
|
||||
}
|
||||
class Transaction {
|
||||
constructor() {
|
||||
this.version = 1;
|
||||
this.locktime = 0;
|
||||
this.ins = [];
|
||||
this.outs = [];
|
||||
}
|
||||
static DEFAULT_SEQUENCE = 0xffffffff;
|
||||
static SIGHASH_ALL = 0x01;
|
||||
static SIGHASH_NONE = 0x02;
|
||||
static SIGHASH_SINGLE = 0x03;
|
||||
static SIGHASH_ANYONECANPAY = 0x80;
|
||||
static ADVANCED_TRANSACTION_MARKER = 0x00;
|
||||
static ADVANCED_TRANSACTION_FLAG = 0x01;
|
||||
static fromBuffer(buffer, _NO_STRICT) {
|
||||
const bufferReader = new bufferutils_1.BufferReader(buffer);
|
||||
const tx = new Transaction();
|
||||
|
@ -101,6 +102,10 @@ class Transaction {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
version = 1;
|
||||
locktime = 0;
|
||||
ins = [];
|
||||
outs = [];
|
||||
isCoinbase() {
|
||||
return (
|
||||
this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)
|
||||
|
@ -157,8 +162,8 @@ class Transaction {
|
|||
const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses();
|
||||
return (
|
||||
(hasWitnesses ? 10 : 8) +
|
||||
varuint.encodingLength(this.ins.length) +
|
||||
varuint.encodingLength(this.outs.length) +
|
||||
bufferutils_1.varuint.encodingLength(this.ins.length) +
|
||||
bufferutils_1.varuint.encodingLength(this.outs.length) +
|
||||
this.ins.reduce((sum, input) => {
|
||||
return sum + 40 + varSliceSize(input.script);
|
||||
}, 0) +
|
||||
|
@ -336,7 +341,9 @@ class Transaction {
|
|||
}
|
||||
getId() {
|
||||
// transaction hash's are displayed in reverse order
|
||||
return bufferutils_1.reverseBuffer(this.getHash(false)).toString('hex');
|
||||
return (0, bufferutils_1.reverseBuffer)(this.getHash(false)).toString(
|
||||
'hex',
|
||||
);
|
||||
}
|
||||
toBuffer(buffer, initialOffset) {
|
||||
return this.__toBuffer(buffer, initialOffset, true);
|
||||
|
@ -392,11 +399,4 @@ class Transaction {
|
|||
return buffer;
|
||||
}
|
||||
}
|
||||
Transaction.DEFAULT_SEQUENCE = 0xffffffff;
|
||||
Transaction.SIGHASH_ALL = 0x01;
|
||||
Transaction.SIGHASH_NONE = 0x02;
|
||||
Transaction.SIGHASH_SINGLE = 0x03;
|
||||
Transaction.SIGHASH_ANYONECANPAY = 0x80;
|
||||
Transaction.ADVANCED_TRANSACTION_MARKER = 0x00;
|
||||
Transaction.ADVANCED_TRANSACTION_FLAG = 0x01;
|
||||
exports.Transaction = Transaction;
|
||||
|
|
29
src/types.d.ts
vendored
Normal file
29
src/types.d.ts
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
/// <reference types="node" />
|
||||
export declare const typeforce: any;
|
||||
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
|
||||
export declare function UInt31(value: number): boolean;
|
||||
export declare function BIP32Path(value: string): boolean;
|
||||
export declare namespace BIP32Path {
|
||||
var toJSON: () => string;
|
||||
}
|
||||
export declare function Signer(obj: any): boolean;
|
||||
export declare function Satoshi(value: number): boolean;
|
||||
export declare const ECPoint: any;
|
||||
export declare const Network: any;
|
||||
export declare const Buffer256bit: any;
|
||||
export declare const Hash160bit: any;
|
||||
export declare const Hash256bit: any;
|
||||
export declare const Number: any;
|
||||
export declare const Array: any;
|
||||
export declare const Boolean: any;
|
||||
export declare const String: any;
|
||||
export declare const Buffer: any;
|
||||
export declare const Hex: any;
|
||||
export declare const maybe: any;
|
||||
export declare const tuple: any;
|
||||
export declare const UInt8: any;
|
||||
export declare const UInt32: any;
|
||||
export declare const Function: any;
|
||||
export declare const BufferN: any;
|
||||
export declare const Null: any;
|
||||
export declare const oneOf: any;
|
89
src/types.js
89
src/types.js
|
@ -1,13 +1,39 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
const typeforce = require('typeforce');
|
||||
exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.typeforce = void 0;
|
||||
const buffer_1 = require('buffer');
|
||||
exports.typeforce = require('typeforce');
|
||||
const ZERO32 = buffer_1.Buffer.alloc(32, 0);
|
||||
const EC_P = buffer_1.Buffer.from(
|
||||
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
|
||||
'hex',
|
||||
);
|
||||
function isPoint(p) {
|
||||
if (!buffer_1.Buffer.isBuffer(p)) return false;
|
||||
if (p.length < 33) return false;
|
||||
const t = p[0];
|
||||
const x = p.slice(1, 33);
|
||||
if (x.compare(ZERO32) === 0) return false;
|
||||
if (x.compare(EC_P) >= 0) return false;
|
||||
if ((t === 0x02 || t === 0x03) && p.length === 33) {
|
||||
return true;
|
||||
}
|
||||
const y = p.slice(33);
|
||||
if (y.compare(ZERO32) === 0) return false;
|
||||
if (y.compare(EC_P) >= 0) return false;
|
||||
if (t === 0x04 && p.length === 65) return true;
|
||||
return false;
|
||||
}
|
||||
exports.isPoint = isPoint;
|
||||
const UINT31_MAX = Math.pow(2, 31) - 1;
|
||||
function UInt31(value) {
|
||||
return typeforce.UInt32(value) && value <= UINT31_MAX;
|
||||
return exports.typeforce.UInt32(value) && value <= UINT31_MAX;
|
||||
}
|
||||
exports.UInt31 = UInt31;
|
||||
function BIP32Path(value) {
|
||||
return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/);
|
||||
return (
|
||||
exports.typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/)
|
||||
);
|
||||
}
|
||||
exports.BIP32Path = BIP32Path;
|
||||
BIP32Path.toJSON = () => {
|
||||
|
@ -15,7 +41,7 @@ BIP32Path.toJSON = () => {
|
|||
};
|
||||
function Signer(obj) {
|
||||
return (
|
||||
(typeforce.Buffer(obj.publicKey) ||
|
||||
(exports.typeforce.Buffer(obj.publicKey) ||
|
||||
typeof obj.getPublicKey === 'function') &&
|
||||
typeof obj.sign === 'function'
|
||||
);
|
||||
|
@ -23,36 +49,39 @@ function Signer(obj) {
|
|||
exports.Signer = Signer;
|
||||
const SATOSHI_MAX = 21 * 1e14;
|
||||
function Satoshi(value) {
|
||||
return typeforce.UInt53(value) && value <= SATOSHI_MAX;
|
||||
return exports.typeforce.UInt53(value) && value <= SATOSHI_MAX;
|
||||
}
|
||||
exports.Satoshi = Satoshi;
|
||||
// external dependent types
|
||||
exports.ECPoint = typeforce.quacksLike('Point');
|
||||
exports.ECPoint = exports.typeforce.quacksLike('Point');
|
||||
// exposed, external API
|
||||
exports.Network = typeforce.compile({
|
||||
messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String),
|
||||
exports.Network = exports.typeforce.compile({
|
||||
messagePrefix: exports.typeforce.oneOf(
|
||||
exports.typeforce.Buffer,
|
||||
exports.typeforce.String,
|
||||
),
|
||||
bip32: {
|
||||
public: typeforce.UInt32,
|
||||
private: typeforce.UInt32,
|
||||
public: exports.typeforce.UInt32,
|
||||
private: exports.typeforce.UInt32,
|
||||
},
|
||||
pubKeyHash: typeforce.UInt8,
|
||||
scriptHash: typeforce.UInt8,
|
||||
wif: typeforce.UInt8,
|
||||
pubKeyHash: exports.typeforce.UInt8,
|
||||
scriptHash: exports.typeforce.UInt8,
|
||||
wif: exports.typeforce.UInt8,
|
||||
});
|
||||
exports.Buffer256bit = typeforce.BufferN(32);
|
||||
exports.Hash160bit = typeforce.BufferN(20);
|
||||
exports.Hash256bit = typeforce.BufferN(32);
|
||||
exports.Number = typeforce.Number; // tslint:disable-line variable-name
|
||||
exports.Array = typeforce.Array;
|
||||
exports.Boolean = typeforce.Boolean; // tslint:disable-line variable-name
|
||||
exports.String = typeforce.String; // tslint:disable-line variable-name
|
||||
exports.Buffer = typeforce.Buffer;
|
||||
exports.Hex = typeforce.Hex;
|
||||
exports.maybe = typeforce.maybe;
|
||||
exports.tuple = typeforce.tuple;
|
||||
exports.UInt8 = typeforce.UInt8;
|
||||
exports.UInt32 = typeforce.UInt32;
|
||||
exports.Function = typeforce.Function;
|
||||
exports.BufferN = typeforce.BufferN;
|
||||
exports.Null = typeforce.Null;
|
||||
exports.oneOf = typeforce.oneOf;
|
||||
exports.Buffer256bit = exports.typeforce.BufferN(32);
|
||||
exports.Hash160bit = exports.typeforce.BufferN(20);
|
||||
exports.Hash256bit = exports.typeforce.BufferN(32);
|
||||
exports.Number = exports.typeforce.Number; // tslint:disable-line variable-name
|
||||
exports.Array = exports.typeforce.Array;
|
||||
exports.Boolean = exports.typeforce.Boolean; // tslint:disable-line variable-name
|
||||
exports.String = exports.typeforce.String; // tslint:disable-line variable-name
|
||||
exports.Buffer = exports.typeforce.Buffer;
|
||||
exports.Hex = exports.typeforce.Hex;
|
||||
exports.maybe = exports.typeforce.maybe;
|
||||
exports.tuple = exports.typeforce.tuple;
|
||||
exports.UInt8 = exports.typeforce.UInt8;
|
||||
exports.UInt32 = exports.typeforce.UInt32;
|
||||
exports.Function = exports.typeforce.Function;
|
||||
exports.BufferN = exports.typeforce.BufferN;
|
||||
exports.Null = exports.typeforce.Null;
|
||||
exports.oneOf = exports.typeforce.oneOf;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue