Socket
Socket
Sign inDemoInstall

bitcoinjs-lib

Package Overview
Dependencies
Maintainers
3
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bitcoinjs-lib - npm Package Compare versions

Comparing version 5.0.5 to 5.1.0

src/psbt.js

13

CHANGELOG.md

@@ -0,1 +1,14 @@

# 5.1.0
__added__
- A new `Psbt` class for creating, distributing, combining, signing, and compiling Transactions (#1425)
- A `name` attribute to the Payment interface. P2SH and P2WSH are nested with `'-'` as separator, and p2ms is in the format of `'p2ms(m of n)''` all others are just hard coded. (#1433)
__changed__
- `TransactionBuilder`: Migrate to stricter type checks during sign by switching to a single object parameter (#1416)
- `tests`: Use regtest-client as separate library (#1421)
# 5.0.5
__added__
- Added `ECPairInterface` `Stack` and `StackElement` interfaces to the main index.ts export (TypeScript only affected)
# 5.0.4

@@ -2,0 +15,0 @@ __added__

4

package.json
{
"name": "bitcoinjs-lib",
"version": "5.0.5",
"version": "5.1.0",
"description": "Client-side Bitcoin JavaScript library",

@@ -50,2 +50,3 @@ "main": "./src/index.js",

"bech32": "^1.1.2",
"bip174": "^1.0.0",
"bip32": "^2.0.3",

@@ -78,2 +79,3 @@ "bip66": "^1.1.0",

"proxyquire": "^2.0.1",
"regtest-client": "0.1.0",
"rimraf": "^2.6.3",

@@ -80,0 +82,0 @@ "tslint": "^5.16.0",

@@ -88,2 +88,10 @@ # BitcoinJS (bitcoinjs-lib)

### Warning: Currently the tests use TransactionBuilder, which will be removed in the future (v6.x.x or higher)
We will move towards replacing all instances of TransactionBuilder in the tests with the new Psbt.
Currently we have a few examples on how to use the newer Psbt class at the following link:
- [Psbt examples](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions-psbt.js)
The rest of the examples are below (using TransactionBuilder for Transaction creation)
- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js)

@@ -90,0 +98,0 @@ - [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js)

@@ -19,2 +19,4 @@ 'use strict';

exports.Block = block_1.Block;
var psbt_1 = require('./psbt');
exports.Psbt = psbt_1.Psbt;
var script_1 = require('./script');

@@ -21,0 +23,0 @@ exports.opcodes = script_1.OPS;

@@ -27,3 +27,3 @@ 'use strict';

const network = a.network || networks_1.bitcoin;
const o = { network };
const o = { name: 'embed', network };
lazy.prop(o, 'output', () => {

@@ -30,0 +30,0 @@ if (!a.data) return;

@@ -96,2 +96,6 @@ 'use strict';

});
lazy.prop(o, 'name', () => {
if (!o.m || !o.n) return;
return `p2ms(${o.m} of ${o.n})`;
});
// extended validation

@@ -98,0 +102,0 @@ if (opts.validate) {

@@ -29,3 +29,3 @@ 'use strict';

const network = a.network || networks_1.bitcoin;
const o = { network };
const o = { name: 'p2pk', network };
lazy.prop(o, 'output', () => {

@@ -32,0 +32,0 @@ if (!a.pubkey) return;

@@ -39,3 +39,3 @@ 'use strict';

const network = a.network || networks_1.bitcoin;
const o = { network };
const o = { name: 'p2pkh', network };
lazy.prop(o, 'address', () => {

@@ -42,0 +42,0 @@ if (!o.hash) return;

@@ -96,2 +96,7 @@ 'use strict';

});
lazy.prop(o, 'name', () => {
const nameParts = ['p2sh'];
if (o.redeem !== undefined) nameParts.push(o.redeem.name);
return nameParts.join('-');
});
if (opts.validate) {

@@ -98,0 +103,0 @@ let hash = Buffer.from([]);

@@ -43,3 +43,3 @@ 'use strict';

const network = a.network || networks_1.bitcoin;
const o = { network };
const o = { name: 'p2wpkh', network };
lazy.prop(o, 'address', () => {

@@ -46,0 +46,0 @@ if (!o.hash) return;

@@ -106,2 +106,7 @@ 'use strict';

});
lazy.prop(o, 'name', () => {
const nameParts = ['p2wsh'];
if (o.redeem !== undefined) nameParts.push(o.redeem.name);
return nameParts.join('-');
});
// extended validation

@@ -108,0 +113,0 @@ if (opts.validate) {

@@ -16,2 +16,29 @@ 'use strict';

const SCRIPT_TYPES = classify.types;
const PREVOUT_TYPES = new Set([
// Raw
'p2pkh',
'p2pk',
'p2wpkh',
'p2ms',
// P2SH wrapped
'p2sh-p2pkh',
'p2sh-p2pk',
'p2sh-p2wpkh',
'p2sh-p2ms',
// P2WSH wrapped
'p2wsh-p2pkh',
'p2wsh-p2pk',
'p2wsh-p2ms',
// P2SH-P2WSH wrapper
'p2sh-p2wsh-p2pkh',
'p2sh-p2wsh-p2pk',
'p2sh-p2wsh-p2ms',
]);
function tfMessage(type, value, message) {
try {
typeforce(type, value);
} catch (err) {
throw new Error(message);
}
}
function txIsString(tx) {

@@ -34,2 +61,9 @@ return typeof tx === 'string' || tx instanceof String;

this.__USE_LOW_R = false;
console.warn(
'Deprecation Warning: TransactionBuilder will be removed in the future. ' +
'(v6.x.x or later) Please use the Psbt class instead. Examples of usage ' +
'are available in the transactions-psbt.js integration test file on our ' +
'Github. A high level explanation is available in the psbt.ts and psbt.js ' +
'files as well.',
);
}

@@ -123,70 +157,25 @@ static fromTransaction(transaction, network) {

}
sign(vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) {
// TODO: remove keyPair.network matching in 4.0.0
if (keyPair.network && keyPair.network !== this.network)
throw new TypeError('Inconsistent network');
if (!this.__INPUTS[vin]) throw new Error('No input at index: ' + vin);
hashType = hashType || transaction_1.Transaction.SIGHASH_ALL;
if (this.__needsOutputs(hashType))
throw new Error('Transaction needs outputs');
const input = this.__INPUTS[vin];
// if redeemScript was previously provided, enforce consistency
if (
input.redeemScript !== undefined &&
redeemScript &&
!input.redeemScript.equals(redeemScript)
) {
throw new Error('Inconsistent redeemScript');
}
const ourPubKey = keyPair.publicKey || keyPair.getPublicKey();
if (!canSign(input)) {
if (witnessValue !== undefined) {
if (input.value !== undefined && input.value !== witnessValue)
throw new Error('Input did not match witnessValue');
typeforce(types.Satoshi, witnessValue);
input.value = witnessValue;
}
if (!canSign(input)) {
const prepared = prepareInput(
input,
ourPubKey,
redeemScript,
witnessScript,
);
// updates inline
Object.assign(input, prepared);
}
if (!canSign(input)) throw Error(input.prevOutType + ' not supported');
}
// ready to sign
let signatureHash;
if (input.hasWitness) {
signatureHash = this.__TX.hashForWitnessV0(
vin,
input.signScript,
input.value,
sign(
signParams,
keyPair,
redeemScript,
hashType,
witnessValue,
witnessScript,
) {
trySign(
getSigningData(
this.network,
this.__INPUTS,
this.__needsOutputs.bind(this),
this.__TX,
signParams,
keyPair,
redeemScript,
hashType,
);
} else {
signatureHash = this.__TX.hashForSignature(
vin,
input.signScript,
hashType,
);
}
// enforce in order signing of public keys
const signed = input.pubkeys.some((pubKey, i) => {
if (!ourPubKey.equals(pubKey)) return false;
if (input.signatures[i]) throw new Error('Signature already exists');
// TODO: add tests
if (ourPubKey.length !== 33 && input.hasWitness) {
throw new Error(
'BIP143 rejects uncompressed public keys in P2WPKH or P2WSH',
);
}
const signature = keyPair.sign(signatureHash, this.__USE_LOW_R);
input.signatures[i] = bscript.signature.encode(signature, hashType);
return true;
});
if (!signed) throw new Error('Key pair cannot sign for this input');
witnessValue,
witnessScript,
this.__USE_LOW_R,
),
);
}

@@ -752,1 +741,329 @@ __addInputUnsafe(txHash, vout, options) {

}
function checkSignArgs(inputs, signParams) {
if (!PREVOUT_TYPES.has(signParams.prevOutScriptType)) {
throw new TypeError(
`Unknown prevOutScriptType "${signParams.prevOutScriptType}"`,
);
}
tfMessage(
typeforce.Number,
signParams.vin,
`sign must include vin parameter as Number (input index)`,
);
tfMessage(
types.Signer,
signParams.keyPair,
`sign must include keyPair parameter as Signer interface`,
);
tfMessage(
typeforce.maybe(typeforce.Number),
signParams.hashType,
`sign hashType parameter must be a number`,
);
const prevOutType = (inputs[signParams.vin] || []).prevOutType;
const posType = signParams.prevOutScriptType;
switch (posType) {
case 'p2pkh':
if (prevOutType && prevOutType !== 'pubkeyhash') {
throw new TypeError(
`input #${signParams.vin} is not of type p2pkh: ${prevOutType}`,
);
}
tfMessage(
typeforce.value(undefined),
signParams.witnessScript,
`${posType} requires NO witnessScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.redeemScript,
`${posType} requires NO redeemScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.witnessValue,
`${posType} requires NO witnessValue`,
);
break;
case 'p2pk':
if (prevOutType && prevOutType !== 'pubkey') {
throw new TypeError(
`input #${signParams.vin} is not of type p2pk: ${prevOutType}`,
);
}
tfMessage(
typeforce.value(undefined),
signParams.witnessScript,
`${posType} requires NO witnessScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.redeemScript,
`${posType} requires NO redeemScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.witnessValue,
`${posType} requires NO witnessValue`,
);
break;
case 'p2wpkh':
if (prevOutType && prevOutType !== 'witnesspubkeyhash') {
throw new TypeError(
`input #${signParams.vin} is not of type p2wpkh: ${prevOutType}`,
);
}
tfMessage(
typeforce.value(undefined),
signParams.witnessScript,
`${posType} requires NO witnessScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.redeemScript,
`${posType} requires NO redeemScript`,
);
tfMessage(
types.Satoshi,
signParams.witnessValue,
`${posType} requires witnessValue`,
);
break;
case 'p2ms':
if (prevOutType && prevOutType !== 'multisig') {
throw new TypeError(
`input #${signParams.vin} is not of type p2ms: ${prevOutType}`,
);
}
tfMessage(
typeforce.value(undefined),
signParams.witnessScript,
`${posType} requires NO witnessScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.redeemScript,
`${posType} requires NO redeemScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.witnessValue,
`${posType} requires NO witnessValue`,
);
break;
case 'p2sh-p2wpkh':
if (prevOutType && prevOutType !== 'scripthash') {
throw new TypeError(
`input #${signParams.vin} is not of type p2sh-p2wpkh: ${prevOutType}`,
);
}
tfMessage(
typeforce.value(undefined),
signParams.witnessScript,
`${posType} requires NO witnessScript`,
);
tfMessage(
typeforce.Buffer,
signParams.redeemScript,
`${posType} requires redeemScript`,
);
tfMessage(
types.Satoshi,
signParams.witnessValue,
`${posType} requires witnessValue`,
);
break;
case 'p2sh-p2ms':
case 'p2sh-p2pk':
case 'p2sh-p2pkh':
if (prevOutType && prevOutType !== 'scripthash') {
throw new TypeError(
`input #${signParams.vin} is not of type ${posType}: ${prevOutType}`,
);
}
tfMessage(
typeforce.value(undefined),
signParams.witnessScript,
`${posType} requires NO witnessScript`,
);
tfMessage(
typeforce.Buffer,
signParams.redeemScript,
`${posType} requires redeemScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.witnessValue,
`${posType} requires NO witnessValue`,
);
break;
case 'p2wsh-p2ms':
case 'p2wsh-p2pk':
case 'p2wsh-p2pkh':
if (prevOutType && prevOutType !== 'witnessscripthash') {
throw new TypeError(
`input #${signParams.vin} is not of type ${posType}: ${prevOutType}`,
);
}
tfMessage(
typeforce.Buffer,
signParams.witnessScript,
`${posType} requires witnessScript`,
);
tfMessage(
typeforce.value(undefined),
signParams.redeemScript,
`${posType} requires NO redeemScript`,
);
tfMessage(
types.Satoshi,
signParams.witnessValue,
`${posType} requires witnessValue`,
);
break;
case 'p2sh-p2wsh-p2ms':
case 'p2sh-p2wsh-p2pk':
case 'p2sh-p2wsh-p2pkh':
if (prevOutType && prevOutType !== 'scripthash') {
throw new TypeError(
`input #${signParams.vin} is not of type ${posType}: ${prevOutType}`,
);
}
tfMessage(
typeforce.Buffer,
signParams.witnessScript,
`${posType} requires witnessScript`,
);
tfMessage(
typeforce.Buffer,
signParams.redeemScript,
`${posType} requires witnessScript`,
);
tfMessage(
types.Satoshi,
signParams.witnessValue,
`${posType} requires witnessScript`,
);
break;
}
}
function trySign({
input,
ourPubKey,
keyPair,
signatureHash,
hashType,
useLowR,
}) {
// enforce in order signing of public keys
let signed = false;
for (const [i, pubKey] of input.pubkeys.entries()) {
if (!ourPubKey.equals(pubKey)) continue;
if (input.signatures[i]) throw new Error('Signature already exists');
// TODO: add tests
if (ourPubKey.length !== 33 && input.hasWitness) {
throw new Error(
'BIP143 rejects uncompressed public keys in P2WPKH or P2WSH',
);
}
const signature = keyPair.sign(signatureHash, useLowR);
input.signatures[i] = bscript.signature.encode(signature, hashType);
signed = true;
}
if (!signed) throw new Error('Key pair cannot sign for this input');
}
function getSigningData(
network,
inputs,
needsOutputs,
tx,
signParams,
keyPair,
redeemScript,
hashType,
witnessValue,
witnessScript,
useLowR,
) {
let vin;
if (typeof signParams === 'number') {
console.warn(
'DEPRECATED: TransactionBuilder sign method arguments ' +
'will change in v6, please use the TxbSignArg interface',
);
vin = signParams;
} else if (typeof signParams === 'object') {
checkSignArgs(inputs, signParams);
({
vin,
keyPair,
redeemScript,
hashType,
witnessValue,
witnessScript,
} = signParams);
} else {
throw new TypeError(
'TransactionBuilder sign first arg must be TxbSignArg or number',
);
}
if (keyPair === undefined) {
throw new Error('sign requires keypair');
}
// TODO: remove keyPair.network matching in 4.0.0
if (keyPair.network && keyPair.network !== network)
throw new TypeError('Inconsistent network');
if (!inputs[vin]) throw new Error('No input at index: ' + vin);
hashType = hashType || transaction_1.Transaction.SIGHASH_ALL;
if (needsOutputs(hashType)) throw new Error('Transaction needs outputs');
const input = inputs[vin];
// if redeemScript was previously provided, enforce consistency
if (
input.redeemScript !== undefined &&
redeemScript &&
!input.redeemScript.equals(redeemScript)
) {
throw new Error('Inconsistent redeemScript');
}
const ourPubKey =
keyPair.publicKey || (keyPair.getPublicKey && keyPair.getPublicKey());
if (!canSign(input)) {
if (witnessValue !== undefined) {
if (input.value !== undefined && input.value !== witnessValue)
throw new Error('Input did not match witnessValue');
typeforce(types.Satoshi, witnessValue);
input.value = witnessValue;
}
if (!canSign(input)) {
const prepared = prepareInput(
input,
ourPubKey,
redeemScript,
witnessScript,
);
// updates inline
Object.assign(input, prepared);
}
if (!canSign(input)) throw Error(input.prevOutType + ' not supported');
}
// ready to sign
let signatureHash;
if (input.hasWitness) {
signatureHash = tx.hashForWitnessV0(
vin,
input.signScript,
input.value,
hashType,
);
} else {
signatureHash = tx.hashForSignature(vin, input.signScript, hashType);
}
return {
input,
ourPubKey,
keyPair,
signatureHash,
hashType,
useLowR: !!useLowR,
};
}

@@ -16,2 +16,10 @@ 'use strict';

};
function Signer(obj) {
return (
(typeforce.Buffer(obj.publicKey) ||
typeof obj.getPublicKey === 'function') &&
typeof obj.sign === 'function'
);
}
exports.Signer = Signer;
const SATOSHI_MAX = 21 * 1e14;

@@ -18,0 +26,0 @@ function Satoshi(value) {

@@ -8,11 +8,20 @@ /// <reference types="node" />

}
export interface ECPairInterface {
export interface Signer {
publicKey: Buffer;
network?: Network;
sign(hash: Buffer, lowR?: boolean): Buffer;
getPublicKey?(): Buffer;
}
export interface SignerAsync {
publicKey: Buffer;
network?: Network;
sign(hash: Buffer, lowR?: boolean): Promise<Buffer>;
getPublicKey?(): Buffer;
}
export interface ECPairInterface extends Signer {
compressed: boolean;
network: Network;
publicKey: Buffer;
privateKey?: Buffer;
toWIF(): string;
sign(hash: Buffer, lowR?: boolean): Buffer;
verify(hash: Buffer, signature: Buffer): boolean;
getPublicKey?(): Buffer;
}

@@ -19,0 +28,0 @@ declare class ECPair implements ECPairInterface {

@@ -10,2 +10,3 @@ import * as bip32 from 'bip32';

export { Block } from './block';
export { Psbt } from './psbt';
export { OPS as opcodes } from './script';

@@ -15,3 +16,3 @@ export { Transaction } from './transaction';

export { BIP32Interface } from 'bip32';
export { ECPairInterface } from './ecpair';
export { ECPairInterface, Signer, SignerAsync } from './ecpair';
export { Network } from './networks';

@@ -18,0 +19,0 @@ export { Payment, PaymentOpts, Stack, StackElement } from './payments';

@@ -11,2 +11,3 @@ /// <reference types="node" />

export interface Payment {
name?: string;
network?: Network;

@@ -13,0 +14,0 @@ output?: Buffer;

/// <reference types="node" />
import { ECPairInterface } from './ecpair';
import { Signer } from './ecpair';
import { Network } from './networks';
import { Transaction } from './transaction';
interface TxbSignArg {
prevOutScriptType: string;
vin: number;
keyPair: Signer;
redeemScript?: Buffer;
hashType?: number;
witnessValue?: number;
witnessScript?: Buffer;
}
export declare class TransactionBuilder {

@@ -21,3 +30,3 @@ network: Network;

buildIncomplete(): Transaction;
sign(vin: number, keyPair: ECPairInterface, redeemScript?: Buffer, hashType?: number, witnessValue?: number, witnessScript?: Buffer): void;
sign(signParams: number | TxbSignArg, keyPair?: Signer, redeemScript?: Buffer, hashType?: number, witnessValue?: number, witnessScript?: Buffer): void;
private __addInputUnsafe;

@@ -30,1 +39,2 @@ private __build;

}
export {};

@@ -6,2 +6,3 @@ export declare function UInt31(value: number): boolean;

}
export declare function Signer(obj: any): boolean;
export declare function Satoshi(value: number): boolean;

@@ -8,0 +9,0 @@ export declare const ECPoint: any;

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc