Comparing version 0.0.15 to 1.0.0
{ | ||
"name": "bip174", | ||
"version": "0.0.15", | ||
"version": "1.0.0", | ||
"description": "", | ||
@@ -35,3 +35,4 @@ "main": "src/lib/psbt.js", | ||
"@types/tape": "4.2.33", | ||
"json-buffer": "^3.0.1", | ||
"bitcoinjs-lib": "^5.0.5", | ||
"buffer-json": "^2.0.0", | ||
"nyc": "^14.1.1", | ||
@@ -38,0 +39,0 @@ "prettier": "^1.18.2", |
@@ -9,7 +9,7 @@ # bip174 | ||
## Under heavy development | ||
## Bitcoin users, use bitcoinjs-lib's Psbt class. | ||
TODO: Increase coverage. Squish bugs. | ||
This library is separate as an attempt to separate Bitcoin specific logic from the encoding format. | ||
WARNING: Until v1.0.0 release, this library will be in flux and have many bugs. Be warned. | ||
I apologize if this library is hard to use. Removing Bitcoin specific logic from "Partially Signed BITCOIN Transaction" format was kind of hard. | ||
@@ -32,7 +32,6 @@ ## Responsibilities Covered | ||
## Static methods and addInput / addOutput require function parameters | ||
## Static methods and addInput / addOutput require an abstract Transaction object | ||
* Static methods: They require a Transaction input/output count getter. The function is `(txBuffer: Buffer) => { inputCount: number; outputCount: number; }` and takes in the Buffer of the value in the 0x00 key of the globalMap. | ||
* addInput/addOutput methods: They require a function to modify the Buffer of the Transaction and return it. `(input: T, txBuffer: Buffer) => Buffer` where T is the same type you passed in the first argument. | ||
* **WARNING** If `T` type has attributes that are named the same as any corresponding input or output types (`witnessUtxo` etc.) the addOutput and addInput functions will try to add them. This allows you to add the input/output attributes to your `T` type and it will automatically add them all in one try. | ||
* Static methods: You must pass a `TransactionFromBuffer` typed function. See `ts_src/lib/interfaces.ts` for info on the `Transaction` interface and the `TransactionFromBuffer` function. | ||
* addInput/addOutput methods: The constructor takes a `Transaction` abstract interface that has an addInput/addOutput method which will be called. | ||
@@ -42,15 +41,29 @@ ## Example | ||
const { Psbt } = require('bip174') | ||
const { inputAdder, outputAdder } = require('./someImplementation') | ||
// See tests/utils/txTools file for an example of a simple Bitcoin Transaction parser. | ||
const { PsbtTransaction , pTxFromBuffer } = require('./someImplementation') | ||
// Psbt requires a Transaction interface to create an instance, as well as | ||
// A function that turns a buffer into that interface. See Transaction and TransactionFromBuffer | ||
// in ts_src/lib/interfaces.ts ... | ||
// See tests/utils/txTools file for an example of a simple Bitcoin Transaction. | ||
// Also see BitcoinJS-lib for an extended class that uses the Transaction class internally. | ||
// Anyone using this library for Bitcoin specifically should use bitcoinjs-lib | ||
const psbt = new Psbt() | ||
// Your PsbtTransaction will have a toBuffer function to allow for serialization | ||
const tx = pTxFromBuffer(someTransactionBuffer); | ||
const psbt = new Psbt(tx) | ||
// OR | ||
// This will parse the PSBT, and use the function you pass to parse the Transaction part | ||
// the function should throw if the scriptSig section is not empty | ||
const psbt = Psbt.fromBuffer(somePsbtBuffer, pTxFromBuffer) | ||
psbt.addInput({ | ||
hash: '865dce988413971fd812d0e81a3395ed916a87ea533e1a16c0f4e15df96fa7d4', | ||
index: 3, | ||
}, inputAdder) | ||
}) | ||
psbt.addInput({ | ||
hash: 'ff5dce988413971fd812d0e81a3395ed916a87ea533e1a16c0f4e15df96fa7d4', | ||
index: 1, | ||
}, inputAdder) | ||
}) | ||
psbt.addOutput({ | ||
@@ -62,3 +75,3 @@ script: Buffer.from( | ||
value: 1234567890, | ||
}, outputAdder) | ||
}) | ||
psbt.addOutput({ | ||
@@ -70,3 +83,3 @@ script: Buffer.from( | ||
value: 987654321, | ||
}, outputAdder) | ||
}) | ||
psbt.addRedeemScriptToInput(0, Buffer.from( | ||
@@ -73,0 +86,0 @@ '00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903', |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
const parser_1 = require('../parser'); | ||
/* | ||
Possible outcomes: | ||
1. Update TX with new inputs or outputs. Keep as much as possible never remove. | ||
- Check sigs and sighashes on self, depending on state, reject merge (Don't want to invalidate sigs) | ||
- New inputs must have WITNESS_TXOUT or NON_WITNESS_TXOUT | ||
- If prevoutScript is PS2H must have RedeemScript, P2WSH must have WitnessScript | ||
- If Redeemscript is P2WSH, must have WitnessScript | ||
- If no sighashType is explicitly shown, add SIGHASH_ALL | ||
- New outputs are copied over as-is | ||
- Before adding | ||
2. | ||
TODO: | ||
1. Create self input and output indexes where key is txid:vout for input and scriptPubkey for output. | ||
2. For each input in self: | ||
1. Get all partialSig | ||
2. Get SigHashType | ||
3. If no sigs, inputs and outputs can be added. | ||
4. If all inputs with sig(s) have SIGHASH_ANYONECANPAY, inputs can be added. | ||
5. If all inputs with sig(s) have SIGHASH_NONE, outputs can be added. | ||
6. If any inputs with sig(s) have SIGHASH_SINGLE, | ||
*/ | ||
function combine(psbts) { | ||
@@ -42,3 +20,6 @@ const self = psbts[0]; | ||
const otherTx = getTx(other); | ||
if (otherTx === undefined || !otherTx.equals(selfTx)) { | ||
if ( | ||
otherTx === undefined || | ||
!otherTx.toBuffer().equals(selfTx.toBuffer()) | ||
) { | ||
throw new Error( | ||
@@ -82,3 +63,3 @@ 'Combine: One of the Psbts does not have the same transaction.', | ||
} | ||
return parser_1.psbtFromKeyVals({ | ||
return parser_1.psbtFromKeyVals(selfTx, { | ||
globalMapKeyVals: selfKeyVals.globalKeyVals, | ||
@@ -95,2 +76,3 @@ inputKeyVals: selfKeyVals.inputKeyVals, | ||
selfKeyVals.push(newKv); | ||
selfSet.add(key); | ||
}; | ||
@@ -97,0 +79,0 @@ } |
import { GlobalXpub, KeyValue } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): GlobalXpub; | ||
export declare function encode(data: GlobalXpub): KeyValue; | ||
export declare const expected = "{ masterFingerprint: Buffer; extendedPubkey: Buffer; path: string; }"; | ||
export declare function check(data: any): data is GlobalXpub; | ||
export declare function canAddToArray(array: GlobalXpub[], item: GlobalXpub, dupeSet: Set<string>): boolean; |
@@ -58,1 +58,27 @@ 'use strict'; | ||
exports.encode = encode; | ||
exports.expected = | ||
'{ masterFingerprint: Buffer; extendedPubkey: Buffer; path: string; }'; | ||
function check(data) { | ||
const epk = data.extendedPubkey; | ||
const mfp = data.masterFingerprint; | ||
const p = data.path; | ||
return ( | ||
Buffer.isBuffer(epk) && | ||
epk.length === 78 && | ||
[2, 3].indexOf(epk[45]) > -1 && | ||
Buffer.isBuffer(mfp) && | ||
mfp.length === 4 && | ||
typeof p === 'string' && | ||
!!p.match(/^m(\/\d+'?)+$/) | ||
); | ||
} | ||
exports.check = check; | ||
function canAddToArray(array, item, dupeSet) { | ||
const dupeString = item.extendedPubkey.toString('hex'); | ||
if (dupeSet.has(dupeString)) return false; | ||
dupeSet.add(dupeString); | ||
return ( | ||
array.filter(v => v.extendedPubkey.equals(item.extendedPubkey)).length === 0 | ||
); | ||
} | ||
exports.canAddToArray = canAddToArray; |
@@ -1,3 +0,2 @@ | ||
import { KeyValue, UnsignedTx } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): UnsignedTx; | ||
export declare function encode(data: UnsignedTx): KeyValue; | ||
import { KeyValue, Transaction } from '../../interfaces'; | ||
export declare function encode(data: Transaction): KeyValue; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
const typeFields_1 = require('../../typeFields'); | ||
function decode(keyVal) { | ||
if (keyVal.key[0] !== typeFields_1.GlobalTypes.UNSIGNED_TX) { | ||
throw new Error( | ||
'Decode Error: could not decode unsignedTx with key 0x' + | ||
keyVal.key.toString('hex'), | ||
); | ||
} | ||
return keyVal.value; | ||
} | ||
exports.decode = decode; | ||
function encode(data) { | ||
const key = Buffer.from([typeFields_1.GlobalTypes.UNSIGNED_TX]); | ||
return { | ||
key, | ||
value: data, | ||
key: Buffer.from([typeFields_1.GlobalTypes.UNSIGNED_TX]), | ||
value: data.toBuffer(), | ||
}; | ||
} | ||
exports.encode = encode; |
@@ -27,2 +27,5 @@ /// <reference types="node" /> | ||
encode: (data: import("../interfaces").Bip32Derivation) => import("../interfaces").KeyValue; | ||
check: (data: any) => data is import("../interfaces").Bip32Derivation; | ||
expected: string; | ||
canAddToArray: (array: import("../interfaces").Bip32Derivation[], item: import("../interfaces").Bip32Derivation, dupeSet: Set<string>) => boolean; | ||
}; | ||
@@ -32,2 +35,5 @@ redeemScript: { | ||
encode: (data: Buffer) => import("../interfaces").KeyValue; | ||
check: (data: any) => data is Buffer; | ||
expected: string; | ||
canAdd: (currentData: any, newData: any) => boolean; | ||
}; | ||
@@ -37,2 +43,5 @@ witnessScript: { | ||
encode: (data: Buffer) => import("../interfaces").KeyValue; | ||
check: (data: any) => data is Buffer; | ||
expected: string; | ||
canAdd: (currentData: any, newData: any) => boolean; | ||
}; | ||
@@ -45,2 +54,5 @@ checkPubkey: (keyVal: import("../interfaces").KeyValue) => Buffer | undefined; | ||
encode: (data: import("../interfaces").Bip32Derivation) => import("../interfaces").KeyValue; | ||
check: (data: any) => data is import("../interfaces").Bip32Derivation; | ||
expected: string; | ||
canAddToArray: (array: import("../interfaces").Bip32Derivation[], item: import("../interfaces").Bip32Derivation, dupeSet: Set<string>) => boolean; | ||
}; | ||
@@ -50,2 +62,5 @@ redeemScript: { | ||
encode: (data: Buffer) => import("../interfaces").KeyValue; | ||
check: (data: any) => data is Buffer; | ||
expected: string; | ||
canAdd: (currentData: any, newData: any) => boolean; | ||
}; | ||
@@ -55,2 +70,5 @@ witnessScript: { | ||
encode: (data: Buffer) => import("../interfaces").KeyValue; | ||
check: (data: any) => data is Buffer; | ||
expected: string; | ||
canAdd: (currentData: any, newData: any) => boolean; | ||
}; | ||
@@ -57,0 +75,0 @@ checkPubkey: (keyVal: import("../interfaces").KeyValue) => Buffer | undefined; |
import { FinalScriptSig, KeyValue } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): FinalScriptSig; | ||
export declare function encode(data: FinalScriptSig): KeyValue; | ||
export declare const expected = "Buffer"; | ||
export declare function check(data: any): data is FinalScriptSig; | ||
export declare function canAdd(currentData: any, newData: any): boolean; |
@@ -22,1 +22,10 @@ 'use strict'; | ||
exports.encode = encode; | ||
exports.expected = 'Buffer'; | ||
function check(data) { | ||
return Buffer.isBuffer(data); | ||
} | ||
exports.check = check; | ||
function canAdd(currentData, newData) { | ||
return !!currentData && !!newData && currentData.finalScriptSig === undefined; | ||
} | ||
exports.canAdd = canAdd; |
import { FinalScriptWitness, KeyValue } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): FinalScriptWitness; | ||
export declare function encode(data: FinalScriptWitness): KeyValue; | ||
export declare const expected = "Buffer"; | ||
export declare function check(data: any): data is FinalScriptWitness; | ||
export declare function canAdd(currentData: any, newData: any): boolean; |
@@ -22,1 +22,12 @@ 'use strict'; | ||
exports.encode = encode; | ||
exports.expected = 'Buffer'; | ||
function check(data) { | ||
return Buffer.isBuffer(data); | ||
} | ||
exports.check = check; | ||
function canAdd(currentData, newData) { | ||
return ( | ||
!!currentData && !!newData && currentData.finalScriptWitness === undefined | ||
); | ||
} | ||
exports.canAdd = canAdd; |
import { KeyValue, NonWitnessUtxo } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): NonWitnessUtxo; | ||
export declare function encode(data: NonWitnessUtxo): KeyValue; | ||
export declare const expected = "Buffer"; | ||
export declare function check(data: any): data is NonWitnessUtxo; | ||
export declare function canAdd(currentData: any, newData: any): boolean; |
@@ -21,1 +21,15 @@ 'use strict'; | ||
exports.encode = encode; | ||
exports.expected = 'Buffer'; | ||
function check(data) { | ||
return Buffer.isBuffer(data); | ||
} | ||
exports.check = check; | ||
function canAdd(currentData, newData) { | ||
return ( | ||
!!currentData && | ||
!!newData && | ||
currentData.witnessUtxo === undefined && | ||
currentData.nonWitnessUtxo === undefined | ||
); | ||
} | ||
exports.canAdd = canAdd; |
import { KeyValue, PartialSig } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): PartialSig; | ||
export declare function encode(pSig: PartialSig): KeyValue; | ||
export declare const expected = "{ pubkey: Buffer; signature: Buffer; }"; | ||
export declare function check(data: any): data is PartialSig; | ||
export declare function canAddToArray(array: PartialSig[], item: PartialSig, dupeSet: Set<string>): boolean; |
@@ -35,1 +35,32 @@ 'use strict'; | ||
exports.encode = encode; | ||
exports.expected = '{ pubkey: Buffer; signature: Buffer; }'; | ||
function check(data) { | ||
return ( | ||
Buffer.isBuffer(data.pubkey) && | ||
Buffer.isBuffer(data.signature) && | ||
[33, 65].includes(data.pubkey.length) && | ||
[2, 3, 4].includes(data.pubkey[0]) && | ||
isDerSigWithSighash(data.signature) | ||
); | ||
} | ||
exports.check = check; | ||
function isDerSigWithSighash(buf) { | ||
if (!Buffer.isBuffer(buf) || buf.length < 9) return false; | ||
if (buf[0] !== 0x30) return false; | ||
if (buf.length !== buf[1] + 3) return false; | ||
if (buf[2] !== 0x02) return false; | ||
const rLen = buf[3]; | ||
if (rLen > 33 || rLen < 1) return false; | ||
if (buf[3 + rLen + 1] !== 0x02) return false; | ||
const sLen = buf[3 + rLen + 2]; | ||
if (sLen > 33 || sLen < 1) return false; | ||
if (buf.length !== 3 + rLen + 2 + sLen + 2) return false; | ||
return true; | ||
} | ||
function canAddToArray(array, item, dupeSet) { | ||
const dupeString = item.pubkey.toString('hex'); | ||
if (dupeSet.has(dupeString)) return false; | ||
dupeSet.add(dupeString); | ||
return array.filter(v => v.pubkey.equals(item.pubkey)).length === 0; | ||
} | ||
exports.canAddToArray = canAddToArray; |
import { KeyValue, PorCommitment } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): PorCommitment; | ||
export declare function encode(data: PorCommitment): KeyValue; | ||
export declare const expected = "string"; | ||
export declare function check(data: any): data is PorCommitment; | ||
export declare function canAdd(currentData: any, newData: any): boolean; |
@@ -22,1 +22,10 @@ 'use strict'; | ||
exports.encode = encode; | ||
exports.expected = 'string'; | ||
function check(data) { | ||
return typeof data === 'string'; | ||
} | ||
exports.check = check; | ||
function canAdd(currentData, newData) { | ||
return !!currentData && !!newData && currentData.porCommitment === undefined; | ||
} | ||
exports.canAdd = canAdd; |
import { KeyValue, SighashType } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): SighashType; | ||
export declare function encode(data: SighashType): KeyValue; | ||
export declare const expected = "number"; | ||
export declare function check(data: any): data is SighashType; | ||
export declare function canAdd(currentData: any, newData: any): boolean; |
@@ -24,1 +24,10 @@ 'use strict'; | ||
exports.encode = encode; | ||
exports.expected = 'number'; | ||
function check(data) { | ||
return typeof data === 'number'; | ||
} | ||
exports.check = check; | ||
function canAdd(currentData, newData) { | ||
return !!currentData && !!newData && currentData.sighashType === undefined; | ||
} | ||
exports.canAdd = canAdd; |
import { KeyValue, WitnessUtxo } from '../../interfaces'; | ||
export declare function decode(keyVal: KeyValue): WitnessUtxo; | ||
export declare function encode(data: WitnessUtxo): KeyValue; | ||
export declare const expected = "{ script: Buffer; value: number; }"; | ||
export declare function check(data: any): data is WitnessUtxo; | ||
export declare function canAdd(currentData: any, newData: any): boolean; |
@@ -40,1 +40,15 @@ 'use strict'; | ||
exports.encode = encode; | ||
exports.expected = '{ script: Buffer; value: number; }'; | ||
function check(data) { | ||
return Buffer.isBuffer(data.script) && typeof data.value === 'number'; | ||
} | ||
exports.check = check; | ||
function canAdd(currentData, newData) { | ||
return ( | ||
!!currentData && | ||
!!newData && | ||
currentData.witnessUtxo === undefined && | ||
currentData.nonWitnessUtxo === undefined | ||
); | ||
} | ||
exports.canAdd = canAdd; |
@@ -5,2 +5,5 @@ import { Bip32Derivation, KeyValue } from '../../interfaces'; | ||
encode: (data: Bip32Derivation) => KeyValue; | ||
check: (data: any) => data is Bip32Derivation; | ||
expected: string; | ||
canAddToArray: (array: Bip32Derivation[], item: Bip32Derivation, dupeSet: Set<string>) => boolean; | ||
}; |
@@ -5,6 +5,2 @@ 'use strict'; | ||
function makeConverter(TYPE_BYTE) { | ||
return { | ||
decode, | ||
encode, | ||
}; | ||
function decode(keyVal) { | ||
@@ -64,3 +60,28 @@ if (keyVal.key[0] !== TYPE_BYTE) { | ||
} | ||
const expected = | ||
'{ masterFingerprint: Buffer; pubkey: Buffer; path: string; }'; | ||
function check(data) { | ||
return ( | ||
Buffer.isBuffer(data.pubkey) && | ||
Buffer.isBuffer(data.masterFingerprint) && | ||
typeof data.path === 'string' && | ||
[33, 65].includes(data.pubkey.length) && | ||
[2, 3, 4].includes(data.pubkey[0]) && | ||
data.masterFingerprint.length === 4 | ||
); | ||
} | ||
function canAddToArray(array, item, dupeSet) { | ||
const dupeString = item.pubkey.toString('hex'); | ||
if (dupeSet.has(dupeString)) return false; | ||
dupeSet.add(dupeString); | ||
return array.filter(v => v.pubkey.equals(item.pubkey)).length === 0; | ||
} | ||
return { | ||
decode, | ||
encode, | ||
check, | ||
expected, | ||
canAddToArray, | ||
}; | ||
} | ||
exports.makeConverter = makeConverter; |
@@ -5,2 +5,5 @@ import { KeyValue, RedeemScript } from '../../interfaces'; | ||
encode: (data: RedeemScript) => KeyValue; | ||
check: (data: any) => data is RedeemScript; | ||
expected: string; | ||
canAdd: (currentData: any, newData: any) => boolean; | ||
}; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
function makeConverter(TYPE_BYTE) { | ||
return { | ||
decode, | ||
encode, | ||
}; | ||
function decode(keyVal) { | ||
@@ -24,3 +20,17 @@ if (keyVal.key[0] !== TYPE_BYTE) { | ||
} | ||
const expected = 'Buffer'; | ||
function check(data) { | ||
return Buffer.isBuffer(data); | ||
} | ||
function canAdd(currentData, newData) { | ||
return !!currentData && !!newData && currentData.redeemScript === undefined; | ||
} | ||
return { | ||
decode, | ||
encode, | ||
check, | ||
expected, | ||
canAdd, | ||
}; | ||
} | ||
exports.makeConverter = makeConverter; |
@@ -5,2 +5,5 @@ import { KeyValue, WitnessScript } from '../../interfaces'; | ||
encode: (data: WitnessScript) => KeyValue; | ||
check: (data: any) => data is WitnessScript; | ||
expected: string; | ||
canAdd: (currentData: any, newData: any) => boolean; | ||
}; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
function makeConverter(TYPE_BYTE) { | ||
return { | ||
decode, | ||
encode, | ||
}; | ||
function decode(keyVal) { | ||
@@ -24,3 +20,19 @@ if (keyVal.key[0] !== TYPE_BYTE) { | ||
} | ||
const expected = 'Buffer'; | ||
function check(data) { | ||
return Buffer.isBuffer(data); | ||
} | ||
function canAdd(currentData, newData) { | ||
return ( | ||
!!currentData && !!newData && currentData.witnessScript === undefined | ||
); | ||
} | ||
return { | ||
decode, | ||
encode, | ||
check, | ||
expected, | ||
canAdd, | ||
}; | ||
} | ||
exports.makeConverter = makeConverter; |
/// <reference types="node" /> | ||
export declare type TransactionFromBuffer = (buffer: Buffer) => Transaction; | ||
export interface Transaction { | ||
getInputOutputCounts(): { | ||
inputCount: number; | ||
outputCount: number; | ||
}; | ||
addInput(objectArg: any): void; | ||
addOutput(objectArg: any): void; | ||
toBuffer(): Buffer; | ||
} | ||
export interface KeyValue { | ||
@@ -6,9 +16,13 @@ key: Buffer; | ||
} | ||
export interface PsbtGlobal { | ||
unknownKeyVals: KeyValue[]; | ||
unsignedTx?: UnsignedTx; | ||
globalXpub?: GlobalXpub; | ||
export interface PsbtGlobal extends PsbtGlobalUpdate { | ||
unsignedTx: Transaction; | ||
unknownKeyVals?: KeyValue[]; | ||
} | ||
export interface PsbtInput { | ||
unknownKeyVals: KeyValue[]; | ||
export interface PsbtGlobalUpdate { | ||
globalXpub?: GlobalXpub[]; | ||
} | ||
export interface PsbtInput extends PsbtInputUpdate { | ||
unknownKeyVals?: KeyValue[]; | ||
} | ||
export interface PsbtInputUpdate { | ||
partialSig?: PartialSig[]; | ||
@@ -25,4 +39,9 @@ nonWitnessUtxo?: NonWitnessUtxo; | ||
} | ||
export interface PsbtOutput { | ||
unknownKeyVals: KeyValue[]; | ||
export interface PsbtInputExtended extends PsbtInput { | ||
[index: string]: any; | ||
} | ||
export interface PsbtOutput extends PsbtOutputUpdate { | ||
unknownKeyVals?: KeyValue[]; | ||
} | ||
export interface PsbtOutputUpdate { | ||
redeemScript?: RedeemScript; | ||
@@ -32,3 +51,5 @@ witnessScript?: WitnessScript; | ||
} | ||
export declare type UnsignedTx = Buffer; | ||
export interface PsbtOutputExtended extends PsbtOutput { | ||
[index: string]: any; | ||
} | ||
export interface GlobalXpub { | ||
@@ -39,3 +60,2 @@ extendedPubkey: Buffer; | ||
} | ||
export declare function isGlobalXpub(data: any): data is GlobalXpub; | ||
export interface PartialSig { | ||
@@ -45,3 +65,2 @@ pubkey: Buffer; | ||
} | ||
export declare function isPartialSig(data: any): data is PartialSig; | ||
export interface Bip32Derivation { | ||
@@ -52,3 +71,2 @@ masterFingerprint: Buffer; | ||
} | ||
export declare function isBip32Derivation(data: any): data is Bip32Derivation; | ||
export interface WitnessUtxo { | ||
@@ -58,3 +76,2 @@ script: Buffer; | ||
} | ||
export declare function isWitnessUtxo(data: any): data is WitnessUtxo; | ||
export declare type NonWitnessUtxo = Buffer; | ||
@@ -75,32 +92,10 @@ export declare type SighashType = number; | ||
sequence?: number; | ||
unknownKeyVals?: KeyValue[]; | ||
partialSig?: PartialSig[]; | ||
nonWitnessUtxo?: NonWitnessUtxo; | ||
witnessUtxo?: WitnessUtxo; | ||
sighashType?: SighashType; | ||
redeemScript?: RedeemScript; | ||
witnessScript?: WitnessScript; | ||
bip32Derivation?: Bip32Derivation[]; | ||
finalScriptSig?: FinalScriptSig; | ||
finalScriptWitness?: FinalScriptWitness; | ||
porCommitment?: PorCommitment; | ||
} | ||
export declare type TransactionInputAdder = (input: TransactionInput, txBuffer: Buffer) => Buffer; | ||
interface TransactionOutputBase { | ||
export interface TransactionOutput { | ||
script: Buffer; | ||
value: number; | ||
unknownKeyVals?: KeyValue[]; | ||
redeemScript?: RedeemScript; | ||
witnessScript?: WitnessScript; | ||
bip32Derivation?: Bip32Derivation[]; | ||
} | ||
export interface TransactionOutputAddress extends TransactionOutputBase { | ||
address: string; | ||
} | ||
export interface TransactionOutputScript extends TransactionOutputBase { | ||
script: Buffer; | ||
} | ||
export declare type TransactionOutput = TransactionOutputAddress | TransactionOutputScript; | ||
export declare type TransactionOutputAdder = (output: TransactionOutput, txBuffer: Buffer) => Buffer; | ||
export declare type TransactionVersionSetter = (version: number, txBuffer: Buffer) => Buffer; | ||
export declare type TransactionLocktimeSetter = (locktime: number, txBuffer: Buffer) => Buffer; | ||
export {}; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
function isGlobalXpub(data) { | ||
return ( | ||
Buffer.isBuffer(data.extendedPubkey) && | ||
Buffer.isBuffer(data.masterFingerprint) && | ||
typeof data.path === 'string' && | ||
data.extendedPubkey.length === 78 && | ||
[2, 3].includes(data.extendedPubkey[45]) && | ||
data.masterFingerprint.length === 4 | ||
); | ||
} | ||
exports.isGlobalXpub = isGlobalXpub; | ||
function isPartialSig(data) { | ||
return ( | ||
Buffer.isBuffer(data.pubkey) && | ||
Buffer.isBuffer(data.signature) && | ||
[33, 65].includes(data.pubkey.length) && | ||
[2, 3, 4].includes(data.pubkey[0]) && | ||
isDerSigWithSighash(data.signature) | ||
); | ||
} | ||
exports.isPartialSig = isPartialSig; | ||
function isDerSigWithSighash(buf) { | ||
if (!Buffer.isBuffer(buf) || buf.length < 9) return false; | ||
if (buf[0] !== 0x30) return false; | ||
if (buf.length !== buf[1] + 3) return false; | ||
if (buf[2] !== 0x02) return false; | ||
const rLen = buf[3]; | ||
if (rLen > 33 || rLen < 1) return false; | ||
if (buf[3 + rLen + 1] !== 0x02) return false; | ||
const sLen = buf[3 + rLen + 2]; | ||
if (sLen > 33 || sLen < 1) return false; | ||
if (buf.length !== 3 + rLen + 2 + sLen + 2) return false; | ||
return true; | ||
} | ||
function isBip32Derivation(data) { | ||
return ( | ||
Buffer.isBuffer(data.pubkey) && | ||
Buffer.isBuffer(data.masterFingerprint) && | ||
typeof data.path === 'string' && | ||
[33, 65].includes(data.pubkey.length) && | ||
[2, 3, 4].includes(data.pubkey[0]) && | ||
data.masterFingerprint.length === 4 | ||
); | ||
} | ||
exports.isBip32Derivation = isBip32Derivation; | ||
function isWitnessUtxo(data) { | ||
return Buffer.isBuffer(data.script) && typeof data.value === 'number'; | ||
} | ||
exports.isWitnessUtxo = isWitnessUtxo; |
/// <reference types="node" /> | ||
import { KeyValue, TransactionIOCountGetter } from '../interfaces'; | ||
import { KeyValue, Transaction, TransactionFromBuffer } from '../interfaces'; | ||
import { PsbtAttributes } from './index'; | ||
export declare function psbtFromBuffer(buffer: Buffer, txCountGetter: TransactionIOCountGetter): PsbtAttributes; | ||
export declare function psbtFromBuffer(buffer: Buffer, txGetter: TransactionFromBuffer): PsbtAttributes; | ||
interface PsbtFromKeyValsArg { | ||
@@ -11,3 +11,3 @@ globalMapKeyVals: KeyValue[]; | ||
export declare function checkKeyBuffer(type: string, keyBuf: Buffer, keyNum: number): void; | ||
export declare function psbtFromKeyVals({ globalMapKeyVals, inputKeyVals, outputKeyVals, }: PsbtFromKeyValsArg): PsbtAttributes; | ||
export declare function psbtFromKeyVals(unsignedTx: Transaction, { globalMapKeyVals, inputKeyVals, outputKeyVals }: PsbtFromKeyValsArg): PsbtAttributes; | ||
export {}; |
@@ -7,3 +7,3 @@ 'use strict'; | ||
const typeFields_1 = require('../typeFields'); | ||
function psbtFromBuffer(buffer, txCountGetter) { | ||
function psbtFromBuffer(buffer, txGetter) { | ||
let offset = 0; | ||
@@ -72,6 +72,5 @@ function varSlice() { | ||
} | ||
const unsignedTx = txCountGetter(unsignedTxMaps[0].value); | ||
const unsignedTx = txGetter(unsignedTxMaps[0].value); | ||
// Get input and output counts to loop the respective fields | ||
const inputCount = unsignedTx.inputCount; | ||
const outputCount = unsignedTx.outputCount; | ||
const { inputCount, outputCount } = unsignedTx.getInputOutputCounts(); | ||
const inputKeyVals = []; | ||
@@ -120,3 +119,7 @@ const outputKeyVals = []; | ||
} | ||
return psbtFromKeyVals({ globalMapKeyVals, inputKeyVals, outputKeyVals }); | ||
return psbtFromKeyVals(unsignedTx, { | ||
globalMapKeyVals, | ||
inputKeyVals, | ||
outputKeyVals, | ||
}); | ||
} | ||
@@ -132,7 +135,11 @@ exports.psbtFromBuffer = psbtFromBuffer; | ||
exports.checkKeyBuffer = checkKeyBuffer; | ||
function psbtFromKeyVals({ globalMapKeyVals, inputKeyVals, outputKeyVals }) { | ||
function psbtFromKeyVals( | ||
unsignedTx, | ||
{ globalMapKeyVals, inputKeyVals, outputKeyVals }, | ||
) { | ||
// That was easy :-) | ||
const globalMap = { | ||
unknownKeyVals: [], | ||
unsignedTx, | ||
}; | ||
let txCount = 0; | ||
for (const keyVal of globalMapKeyVals) { | ||
@@ -148,12 +155,16 @@ // If a globalMap item needs pubkey, uncomment | ||
); | ||
if (globalMap.unsignedTx !== undefined) { | ||
if (txCount > 0) { | ||
throw new Error('Format Error: GlobalMap has multiple UNSIGNED_TX'); | ||
} | ||
globalMap.unsignedTx = convert.globals.unsignedTx.decode(keyVal); | ||
txCount++; | ||
break; | ||
case typeFields_1.GlobalTypes.GLOBAL_XPUB: | ||
globalMap.globalXpub = convert.globals.globalXpub.decode(keyVal); | ||
if (globalMap.globalXpub === undefined) { | ||
globalMap.globalXpub = []; | ||
} | ||
globalMap.globalXpub.push(convert.globals.globalXpub.decode(keyVal)); | ||
break; | ||
default: | ||
// This will allow inclusion during serialization. | ||
if (!globalMap.unknownKeyVals) globalMap.unknownKeyVals = []; | ||
globalMap.unknownKeyVals.push(keyVal); | ||
@@ -169,5 +180,3 @@ } | ||
for (const index of tools_1.range(inputCount)) { | ||
const input = { | ||
unknownKeyVals: [], | ||
}; | ||
const input = {}; | ||
for (const keyVal of inputKeyVals[index]) { | ||
@@ -283,2 +292,3 @@ convert.inputs.checkPubkey(keyVal); | ||
// This will allow inclusion during serialization. | ||
if (!input.unknownKeyVals) input.unknownKeyVals = []; | ||
input.unknownKeyVals.push(keyVal); | ||
@@ -290,5 +300,3 @@ } | ||
for (const index of tools_1.range(outputCount)) { | ||
const output = { | ||
unknownKeyVals: [], | ||
}; | ||
const output = {}; | ||
for (const keyVal of outputKeyVals[index]) { | ||
@@ -328,2 +336,3 @@ convert.outputs.checkPubkey(keyVal); | ||
default: | ||
if (!output.unknownKeyVals) output.unknownKeyVals = []; | ||
output.unknownKeyVals.push(keyVal); | ||
@@ -330,0 +339,0 @@ } |
@@ -12,12 +12,8 @@ 'use strict'; | ||
const globalBuffer = tools_1.keyValsToBuffer(globalKeyVals); | ||
const inputBuffers = []; | ||
const outputBuffers = []; | ||
inputKeyVals.forEach(input => { | ||
inputBuffers.push(tools_1.keyValsToBuffer(input)); | ||
}); | ||
outputKeyVals.forEach(output => { | ||
outputBuffers.push(tools_1.keyValsToBuffer(output)); | ||
}); | ||
if (inputBuffers.length === 0) inputBuffers.push(Buffer.from([0])); | ||
if (outputBuffers.length === 0) outputBuffers.push(Buffer.from([0])); | ||
const keyValsOrEmptyToBuffer = keyVals => | ||
keyVals.length === 0 | ||
? [Buffer.from([0])] | ||
: keyVals.map(tools_1.keyValsToBuffer); | ||
const inputBuffers = keyValsOrEmptyToBuffer(inputKeyVals); | ||
const outputBuffers = keyValsOrEmptyToBuffer(outputKeyVals); | ||
const header = Buffer.allocUnsafe(5); | ||
@@ -64,5 +60,7 @@ header.writeUIntBE(0x70736274ff, 0, 5); | ||
// Get other keyVals that have not yet been gotten | ||
const otherKeyVals = keyValMap.unknownKeyVals.filter(keyVal => { | ||
return !keyHexes.has(keyVal.key.toString('hex')); | ||
}); | ||
const otherKeyVals = keyValMap.unknownKeyVals | ||
? keyValMap.unknownKeyVals.filter(keyVal => { | ||
return !keyHexes.has(keyVal.key.toString('hex')); | ||
}) | ||
: []; | ||
return keyVals.concat(otherKeyVals).sort(sortKeyVals); | ||
@@ -69,0 +67,0 @@ } |
/// <reference types="node" /> | ||
import { Bip32Derivation, FinalScriptSig, FinalScriptWitness, GlobalXpub, KeyValue, NonWitnessUtxo, PartialSig, PorCommitment, PsbtGlobal, PsbtInput, PsbtOutput, RedeemScript, SighashType, TransactionIOCountGetter, TransactionLocktimeSetter, TransactionVersionSetter, WitnessScript, WitnessUtxo } from './interfaces'; | ||
import { KeyValue, PsbtGlobal, PsbtGlobalUpdate, PsbtInput, PsbtInputExtended, PsbtInputUpdate, PsbtOutput, PsbtOutputExtended, PsbtOutputUpdate, Transaction, TransactionFromBuffer } from './interfaces'; | ||
export declare class Psbt { | ||
static fromTransaction<T extends typeof Psbt>(this: T, txBuf: Buffer, txCountGetter: TransactionIOCountGetter): InstanceType<T>; | ||
static fromBase64<T extends typeof Psbt>(this: T, data: string, txCountGetter: TransactionIOCountGetter): InstanceType<T>; | ||
static fromHex<T extends typeof Psbt>(this: T, data: string, txCountGetter: TransactionIOCountGetter): InstanceType<T>; | ||
static fromBuffer<T extends typeof Psbt>(this: T, buffer: Buffer, txCountGetter: TransactionIOCountGetter): InstanceType<T>; | ||
static fromBase64<T extends typeof Psbt>(this: T, data: string, txFromBuffer: TransactionFromBuffer): InstanceType<T>; | ||
static fromHex<T extends typeof Psbt>(this: T, data: string, txFromBuffer: TransactionFromBuffer): InstanceType<T>; | ||
static fromBuffer<T extends typeof Psbt>(this: T, buffer: Buffer, txFromBuffer: TransactionFromBuffer): InstanceType<T>; | ||
readonly inputs: PsbtInput[]; | ||
readonly outputs: PsbtOutput[]; | ||
readonly globalMap: PsbtGlobal; | ||
constructor(tx: Transaction); | ||
toBase64(): string; | ||
toHex(): string; | ||
toBuffer(): Buffer; | ||
setVersion(version: number, transactionVersionSetter?: TransactionVersionSetter): this; | ||
setLocktime(locktime: number, transactionLocktimeSetter?: TransactionLocktimeSetter): this; | ||
addGlobalXpubToGlobal(globalXpub: GlobalXpub): this; | ||
addNonWitnessUtxoToInput(inputIndex: number, nonWitnessUtxo: NonWitnessUtxo): this; | ||
addWitnessUtxoToInput(inputIndex: number, witnessUtxo: WitnessUtxo): this; | ||
addPartialSigToInput(inputIndex: number, partialSig: PartialSig): this; | ||
addSighashTypeToInput(inputIndex: number, sighashType: SighashType): this; | ||
addRedeemScriptToInput(inputIndex: number, redeemScript: RedeemScript): this; | ||
addWitnessScriptToInput(inputIndex: number, witnessScript: WitnessScript): this; | ||
addBip32DerivationToInput(inputIndex: number, bip32Derivation: Bip32Derivation): this; | ||
addFinalScriptSigToInput(inputIndex: number, finalScriptSig: FinalScriptSig): this; | ||
addFinalScriptWitnessToInput(inputIndex: number, finalScriptWitness: FinalScriptWitness): this; | ||
addPorCommitmentToInput(inputIndex: number, porCommitment: PorCommitment): this; | ||
addRedeemScriptToOutput(outputIndex: number, redeemScript: RedeemScript): this; | ||
addWitnessScriptToOutput(outputIndex: number, witnessScript: WitnessScript): this; | ||
addBip32DerivationToOutput(outputIndex: number, bip32Derivation: Bip32Derivation): this; | ||
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; | ||
addInput<T>(inputData: T, transactionInputAdder: (input: T, txBuffer: Buffer) => Buffer): this; | ||
addOutput<T>(outputData: T, transactionOutputAdder: (output: T, txBuffer: Buffer) => Buffer, allowNoInput?: boolean): this; | ||
addInput(inputData: PsbtInputExtended): this; | ||
addOutput(outputData: PsbtOutputExtended): this; | ||
clearFinalizedInput(inputIndex: number): this; | ||
@@ -36,0 +23,0 @@ combine(...those: this[]): this; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
const combiner_1 = require('./combiner'); | ||
const interfaces_1 = require('./interfaces'); | ||
const parser_1 = require('./parser'); | ||
const typeFields_1 = require('./typeFields'); | ||
const utils_1 = require('./utils'); | ||
// version 1, locktime 0, 0 ins, 0 outs | ||
const DEFAULT_UNSIGNED_TX = Buffer.from('01000000000000000000', 'hex'); | ||
class Psbt { | ||
constructor() { | ||
constructor(tx) { | ||
this.inputs = []; | ||
this.outputs = []; | ||
this.globalMap = { | ||
unknownKeyVals: [], | ||
unsignedTx: Buffer.from(DEFAULT_UNSIGNED_TX), | ||
unsignedTx: tx, | ||
}; | ||
} | ||
static fromTransaction(txBuf, txCountGetter) { | ||
const result = txCountGetter(txBuf); | ||
const psbt = new this(); | ||
psbt.globalMap.unsignedTx = txBuf; | ||
while (result.inputCount > 0) { | ||
psbt.inputs.push({ | ||
unknownKeyVals: [], | ||
}); | ||
result.inputCount--; | ||
} | ||
while (result.outputCount > 0) { | ||
psbt.outputs.push({ | ||
unknownKeyVals: [], | ||
}); | ||
result.outputCount--; | ||
} | ||
return psbt; | ||
} | ||
static fromBase64(data, txCountGetter) { | ||
static fromBase64(data, txFromBuffer) { | ||
const buffer = Buffer.from(data, 'base64'); | ||
return this.fromBuffer(buffer, txCountGetter); | ||
return this.fromBuffer(buffer, txFromBuffer); | ||
} | ||
static fromHex(data, txCountGetter) { | ||
static fromHex(data, txFromBuffer) { | ||
const buffer = Buffer.from(data, 'hex'); | ||
return this.fromBuffer(buffer, txCountGetter); | ||
return this.fromBuffer(buffer, txFromBuffer); | ||
} | ||
static fromBuffer(buffer, txCountGetter) { | ||
const psbt = new this(); | ||
const results = parser_1.psbtFromBuffer(buffer, txCountGetter); | ||
static fromBuffer(buffer, txFromBuffer) { | ||
const results = parser_1.psbtFromBuffer(buffer, txFromBuffer); | ||
const psbt = new this(results.globalMap.unsignedTx); | ||
Object.assign(psbt, results); | ||
@@ -62,157 +40,16 @@ return psbt; | ||
} | ||
setVersion(version, transactionVersionSetter) { | ||
let func; | ||
if (transactionVersionSetter !== undefined) { | ||
func = transactionVersionSetter; | ||
} else { | ||
func = utils_1.defaultVersionSetter; | ||
} | ||
const updated = func(version, this.globalMap.unsignedTx); | ||
utils_1.insertTxInGlobalMap(updated, this.globalMap); | ||
updateGlobal(updateData) { | ||
utils_1.updateGlobal(updateData, this.globalMap); | ||
return this; | ||
} | ||
setLocktime(locktime, transactionLocktimeSetter) { | ||
let func; | ||
if (transactionLocktimeSetter !== undefined) { | ||
func = transactionLocktimeSetter; | ||
} else { | ||
func = utils_1.defaultLocktimeSetter; | ||
} | ||
const updated = func(locktime, this.globalMap.unsignedTx); | ||
utils_1.insertTxInGlobalMap(updated, this.globalMap); | ||
return this; | ||
} | ||
addGlobalXpubToGlobal(globalXpub) { | ||
if (!interfaces_1.isGlobalXpub(globalXpub)) { | ||
throw new Error( | ||
'globalXpub should be { masterFingerprint: Buffer; extendedPubkey: ' + | ||
'Buffer; path: string; }', | ||
); | ||
} | ||
this.globalMap.globalXpub = globalXpub; | ||
return this; | ||
} | ||
addNonWitnessUtxoToInput(inputIndex, nonWitnessUtxo) { | ||
updateInput(inputIndex, updateData) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (input.nonWitnessUtxo || input.witnessUtxo) { | ||
throw new Error(`Input #${inputIndex} already has a Utxo attribute`); | ||
} | ||
if (!Buffer.isBuffer(nonWitnessUtxo)) { | ||
throw new Error('nonWitnessUtxo should be a Buffer of a Transaction'); | ||
} | ||
input.nonWitnessUtxo = nonWitnessUtxo; | ||
utils_1.updateInput(updateData, input); | ||
return this; | ||
} | ||
addWitnessUtxoToInput(inputIndex, witnessUtxo) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (input.nonWitnessUtxo || input.witnessUtxo) { | ||
throw new Error(`Input #${inputIndex} already has a Utxo attribute`); | ||
} | ||
if (!interfaces_1.isWitnessUtxo(witnessUtxo)) { | ||
throw new Error( | ||
'witnessUtxo should be { script: Buffer; value: number; }', | ||
); | ||
} | ||
input.witnessUtxo = witnessUtxo; | ||
return this; | ||
} | ||
addPartialSigToInput(inputIndex, partialSig) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (!interfaces_1.isPartialSig(partialSig)) { | ||
throw new Error( | ||
'partialSig should be { pubkey: Buffer; signature: Buffer; }', | ||
); | ||
} | ||
if (input.partialSig === undefined) input.partialSig = []; | ||
input.partialSig.push(partialSig); | ||
return this; | ||
} | ||
addSighashTypeToInput(inputIndex, sighashType) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (typeof sighashType !== 'number') { | ||
throw new Error('sighashType should be a number'); | ||
} | ||
input.sighashType = sighashType; | ||
return this; | ||
} | ||
addRedeemScriptToInput(inputIndex, redeemScript) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (!Buffer.isBuffer(redeemScript)) { | ||
throw new Error('redeemScript should be a Buffer'); | ||
} | ||
input.redeemScript = redeemScript; | ||
return this; | ||
} | ||
addWitnessScriptToInput(inputIndex, witnessScript) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (!Buffer.isBuffer(witnessScript)) { | ||
throw new Error('witnessScript should be a Buffer'); | ||
} | ||
input.witnessScript = witnessScript; | ||
return this; | ||
} | ||
addBip32DerivationToInput(inputIndex, bip32Derivation) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (!interfaces_1.isBip32Derivation(bip32Derivation)) { | ||
throw new Error( | ||
'bip32Derivation should be { masterFingerprint: Buffer; pubkey: ' + | ||
'Buffer; path: string; }', | ||
); | ||
} | ||
if (input.bip32Derivation === undefined) input.bip32Derivation = []; | ||
input.bip32Derivation.push(bip32Derivation); | ||
return this; | ||
} | ||
addFinalScriptSigToInput(inputIndex, finalScriptSig) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (!Buffer.isBuffer(finalScriptSig)) { | ||
throw new Error('finalScriptSig should be a Buffer'); | ||
} | ||
input.finalScriptSig = finalScriptSig; | ||
return this; | ||
} | ||
addFinalScriptWitnessToInput(inputIndex, finalScriptWitness) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (!Buffer.isBuffer(finalScriptWitness)) { | ||
throw new Error('finalScriptWitness should be a Buffer'); | ||
} | ||
input.finalScriptWitness = finalScriptWitness; | ||
return this; | ||
} | ||
addPorCommitmentToInput(inputIndex, porCommitment) { | ||
const input = utils_1.checkForInput(this.inputs, inputIndex); | ||
if (typeof porCommitment !== 'string') { | ||
throw new Error('porCommitment should be a string'); | ||
} | ||
input.porCommitment = porCommitment; | ||
return this; | ||
} | ||
addRedeemScriptToOutput(outputIndex, redeemScript) { | ||
updateOutput(outputIndex, updateData) { | ||
const output = utils_1.checkForOutput(this.outputs, outputIndex); | ||
if (!Buffer.isBuffer(redeemScript)) { | ||
throw new Error('redeemScript should be a Buffer'); | ||
} | ||
output.redeemScript = redeemScript; | ||
utils_1.updateOutput(updateData, output); | ||
return this; | ||
} | ||
addWitnessScriptToOutput(outputIndex, witnessScript) { | ||
const output = utils_1.checkForOutput(this.outputs, outputIndex); | ||
if (!Buffer.isBuffer(witnessScript)) { | ||
throw new Error('witnessScript should be a Buffer'); | ||
} | ||
output.witnessScript = witnessScript; | ||
return this; | ||
} | ||
addBip32DerivationToOutput(outputIndex, bip32Derivation) { | ||
const output = utils_1.checkForOutput(this.outputs, outputIndex); | ||
if (!interfaces_1.isBip32Derivation(bip32Derivation)) { | ||
throw new Error( | ||
'bip32Derivation should be { masterFingerprint: Buffer; pubkey: ' + | ||
'Buffer; path: string; }', | ||
); | ||
} | ||
if (output.bip32Derivation === undefined) output.bip32Derivation = []; | ||
output.bip32Derivation.push(bip32Derivation); | ||
return this; | ||
} | ||
addUnknownKeyValToGlobal(keyVal) { | ||
@@ -224,2 +61,3 @@ utils_1.checkHasKey( | ||
); | ||
if (!this.globalMap.unknownKeyVals) this.globalMap.unknownKeyVals = []; | ||
this.globalMap.unknownKeyVals.push(keyVal); | ||
@@ -235,2 +73,3 @@ return this; | ||
); | ||
if (!input.unknownKeyVals) input.unknownKeyVals = []; | ||
input.unknownKeyVals.push(keyVal); | ||
@@ -246,13 +85,8 @@ return this; | ||
); | ||
if (!output.unknownKeyVals) output.unknownKeyVals = []; | ||
output.unknownKeyVals.push(keyVal); | ||
return this; | ||
} | ||
addInput(inputData, transactionInputAdder) { | ||
if (transactionInputAdder === undefined) { | ||
throw new Error('You must pass a function to handle the input.'); | ||
} | ||
const txBuf = this.getTransaction(); | ||
let newTxBuf; | ||
newTxBuf = transactionInputAdder(inputData, txBuf); | ||
utils_1.insertTxInGlobalMap(newTxBuf, this.globalMap); | ||
addInput(inputData) { | ||
this.globalMap.unsignedTx.addInput(inputData); | ||
this.inputs.push({ | ||
@@ -269,18 +103,7 @@ unknownKeyVals: [], | ||
); | ||
utils_1.addInputAttributes(this, inputData); | ||
utils_1.addInputAttributes(this.inputs, inputData); | ||
return this; | ||
} | ||
addOutput(outputData, transactionOutputAdder, allowNoInput) { | ||
if (!allowNoInput && this.inputs.length === 0) { | ||
throw new Error( | ||
'Add Output: can not add an output before adding an input.', | ||
); | ||
} | ||
if (transactionOutputAdder === undefined) { | ||
throw new Error('You must pass a function to handle the output.'); | ||
} | ||
const txBuf = this.getTransaction(); | ||
let newTxBuf; | ||
newTxBuf = transactionOutputAdder(outputData, txBuf); | ||
utils_1.insertTxInGlobalMap(newTxBuf, this.globalMap); | ||
addOutput(outputData) { | ||
this.globalMap.unsignedTx.addOutput(outputData); | ||
this.outputs.push({ | ||
@@ -297,3 +120,3 @@ unknownKeyVals: [], | ||
); | ||
utils_1.addOutputAttributes(this, outputData); | ||
utils_1.addOutputAttributes(this.outputs, outputData); | ||
return this; | ||
@@ -328,5 +151,5 @@ } | ||
getTransaction() { | ||
return utils_1.getTransactionFromGlobalMap(this.globalMap); | ||
return this.globalMap.unsignedTx.toBuffer(); | ||
} | ||
} | ||
exports.Psbt = Psbt; |
/// <reference types="node" /> | ||
import { KeyValue, PsbtGlobal, PsbtInput, PsbtOutput } from './interfaces'; | ||
import { Psbt } from './psbt'; | ||
import { KeyValue, PsbtGlobal, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from './interfaces'; | ||
export declare function checkForInput(inputs: PsbtInput[], inputIndex: number): PsbtInput; | ||
export declare function checkForOutput(outputs: PsbtOutput[], outputIndex: number): PsbtOutput; | ||
export declare function checkHasKey(checkKeyVal: KeyValue, keyVals: KeyValue[], enumLength: number): void; | ||
export declare function checkHasKey(checkKeyVal: KeyValue, keyVals: KeyValue[] | undefined, enumLength: number): void; | ||
export declare function getEnumLength(myenum: any): number; | ||
export declare function getTransactionFromGlobalMap(globalMap: PsbtGlobal): Buffer; | ||
export declare function inputCheckUncleanFinalized(inputIndex: number, input: PsbtInput): void; | ||
export declare function insertTxInGlobalMap(txBuf: Buffer, globalMap: PsbtGlobal): void; | ||
export declare function addInputAttributes<T extends typeof Psbt>(psbt: InstanceType<T>, data: any): void; | ||
export declare function addOutputAttributes<T extends typeof Psbt>(psbt: InstanceType<T>, data: any): void; | ||
export declare const updateGlobal: (updateData: PsbtGlobalUpdate, mainData: PsbtGlobal) => void; | ||
export declare const updateInput: (updateData: PsbtInputUpdate, mainData: PsbtInput) => void; | ||
export declare const updateOutput: (updateData: PsbtOutputUpdate, mainData: PsbtOutput) => void; | ||
export declare function addInputAttributes(inputs: PsbtInput[], data: any): void; | ||
export declare function addOutputAttributes(outputs: PsbtOutput[], data: any): void; | ||
export declare function defaultVersionSetter(version: number, txBuf: Buffer): Buffer; | ||
export declare function defaultLocktimeSetter(locktime: number, txBuf: Buffer): Buffer; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
const typeFields_1 = require('./typeFields'); | ||
const converter = require('./converter'); | ||
function checkForInput(inputs, inputIndex) { | ||
@@ -22,3 +22,6 @@ const input = inputs[inputIndex]; | ||
} | ||
if (keyVals.filter(kv => kv.key.equals(checkKeyVal.key)).length !== 0) { | ||
if ( | ||
keyVals && | ||
keyVals.filter(kv => kv.key.equals(checkKeyVal.key)).length !== 0 | ||
) { | ||
throw new Error(`Duplicate Key: ${checkKeyVal.key.toString('hex')}`); | ||
@@ -38,17 +41,2 @@ } | ||
exports.getEnumLength = getEnumLength; | ||
function getTransactionFromGlobalMap(globalMap) { | ||
const txKeyVals = globalMap.unknownKeyVals.filter( | ||
kv => kv.key[0] === typeFields_1.GlobalTypes.UNSIGNED_TX, | ||
); | ||
const len = txKeyVals.length; | ||
const tx = globalMap.unsignedTx; | ||
const hasTx = tx !== undefined ? 1 : 0; | ||
if (len + hasTx !== 1) { | ||
throw new Error( | ||
`Extract Transaction: Expected one Transaction, got ${len + hasTx}`, | ||
); | ||
} | ||
return tx !== undefined ? tx : txKeyVals[0].value; | ||
} | ||
exports.getTransactionFromGlobalMap = getTransactionFromGlobalMap; | ||
function inputCheckUncleanFinalized(inputIndex, input) { | ||
@@ -74,40 +62,66 @@ let result = false; | ||
exports.inputCheckUncleanFinalized = inputCheckUncleanFinalized; | ||
function insertTxInGlobalMap(txBuf, globalMap) { | ||
const txKeyVals = globalMap.unknownKeyVals.filter( | ||
kv => kv.key[0] === typeFields_1.GlobalTypes.UNSIGNED_TX, | ||
function throwForUpdateMaker(typeName, name, expected, data) { | ||
throw new Error( | ||
`Data for ${typeName} key ${name} is incorrect: Expected ` + | ||
`${expected} and got ${JSON.stringify(data)}`, | ||
); | ||
const len = txKeyVals.length; | ||
const tx = globalMap.unsignedTx; | ||
const hasTx = tx !== undefined ? 1 : 0; | ||
if (len + hasTx !== 1) { | ||
throw new Error( | ||
`Extract Transaction: Expected one Transaction, got ${len + hasTx}`, | ||
); | ||
} | ||
if (tx !== undefined) globalMap.unsignedTx = txBuf; | ||
else txKeyVals[0].value = txBuf; | ||
} | ||
exports.insertTxInGlobalMap = insertTxInGlobalMap; | ||
function addInputAttributes(psbt, data) { | ||
const inputIndex = psbt.inputs.length - 1; | ||
for (const name of typeFields_1.INPUT_TYPE_NAMES) { | ||
const item = data[name]; | ||
if (item) { | ||
const nameUpper = name.replace(/^\S/, s => s.toUpperCase()); | ||
function updateMaker(typeName) { | ||
return (updateData, mainData) => { | ||
for (const name of Object.keys(updateData)) { | ||
// @ts-ignore | ||
psbt[`add${nameUpper}ToInput`](inputIndex, item); | ||
const data = updateData[name]; | ||
// @ts-ignore | ||
const { canAdd, canAddToArray, check, expected } = | ||
// @ts-ignore | ||
converter[typeName + 's'][name] || {}; | ||
const isArray = !!canAddToArray; | ||
// If unknown data. ignore and do not add | ||
if (check) { | ||
if (isArray) { | ||
if ( | ||
!Array.isArray(data) || | ||
// @ts-ignore | ||
(mainData[name] && !Array.isArray(mainData[name])) | ||
) { | ||
throw new Error(`Key type ${name} must be an array`); | ||
} | ||
if (!data.every(v => check(v))) { | ||
throwForUpdateMaker(typeName, name, expected, data); | ||
} | ||
// @ts-ignore | ||
const arr = mainData[name] || []; | ||
const dupeCheckSet = new Set(); | ||
if (!data.every(v => canAddToArray(arr, v, dupeCheckSet))) { | ||
throw new Error('Can not add duplicate data to array'); | ||
} | ||
// @ts-ignore | ||
mainData[name] = arr.concat(data); | ||
} else { | ||
if (!check(data)) { | ||
throwForUpdateMaker(typeName, name, expected, data); | ||
} | ||
if (!canAdd(mainData, data)) { | ||
throw new Error(`Can not add duplicate data to ${typeName}`); | ||
} | ||
// @ts-ignore | ||
mainData[name] = data; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
exports.updateGlobal = updateMaker('global'); | ||
exports.updateInput = updateMaker('input'); | ||
exports.updateOutput = updateMaker('output'); | ||
function addInputAttributes(inputs, data) { | ||
const index = inputs.length - 1; | ||
const input = checkForInput(inputs, index); | ||
exports.updateInput(data, input); | ||
} | ||
exports.addInputAttributes = addInputAttributes; | ||
function addOutputAttributes(psbt, data) { | ||
const outputIndex = psbt.outputs.length - 1; | ||
for (const name of typeFields_1.OUTPUT_TYPE_NAMES) { | ||
const item = data[name]; | ||
if (item) { | ||
const nameUpper = name.replace(/^\S/, s => s.toUpperCase()); | ||
// @ts-ignore | ||
psbt[`add${nameUpper}ToOutput`](outputIndex, item); | ||
} | ||
} | ||
function addOutputAttributes(outputs, data) { | ||
const index = outputs.length - 1; | ||
const output = checkForInput(outputs, index); | ||
exports.updateOutput(data, output); | ||
} | ||
@@ -114,0 +128,0 @@ exports.addOutputAttributes = addOutputAttributes; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
110
74261
10
1950