@secux/app-btc
Advanced tools
Comparing version 3.2.4 to 3.2.5
@@ -1,392 +0,1 @@ | ||
"use strict"; | ||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
}; | ||
var SecuxBTC_1; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SecuxBTC = exports.ScriptType = exports.CoinType = void 0; | ||
const secp256k1 = require('secp256k1/elliptic'); | ||
const varuint = require("varuint-bitcoin"); | ||
const utility_1 = require("@secux/utility"); | ||
const xpub_1 = require("@secux/utility/lib/xpub"); | ||
const ow_1 = require("ow"); | ||
const protocol_transaction_1 = require("@secux/protocol-transaction"); | ||
const communication_1 = require("@secux/utility/lib/communication"); | ||
const interface_1 = require("@secux/protocol-transaction/lib/interface"); | ||
const interface_2 = require("./interface"); | ||
Object.defineProperty(exports, "CoinType", { enumerable: true, get: function () { return interface_2.CoinType; } }); | ||
Object.defineProperty(exports, "ScriptType", { enumerable: true, get: function () { return interface_2.ScriptType; } }); | ||
const psbt_1 = require("./psbt"); | ||
const utils_1 = require("./utils"); | ||
const transport_1 = require("@secux/transport"); | ||
/** | ||
* BTC package for SecuX device | ||
*/ | ||
let SecuxBTC = SecuxBTC_1 = class SecuxBTC { | ||
/** | ||
* Convert publickey to BTC address. | ||
* @param {string | Buffer} publickey secp256k1 publickey (hex string or buffer) | ||
* @param {string | PathObject} path BIP32 path, ex: m/44'/0'/0'/0/0 | ||
* @returns {string} address | ||
*/ | ||
static addressConvert(publickey, path) { | ||
const pk = (0, utils_1.getPublickey)(publickey); | ||
(0, ow_1.default)(path, ow_1.default.any(interface_2.ow_path, interface_2.ow_PathObject)); | ||
const compressed = Buffer.from(secp256k1.publicKeyConvert(pk, true)); | ||
const coin = (typeof path === "string") ? (0, utils_1.getCoinType)(path) : path.coin; | ||
const script = (typeof path === "string") ? (0, utils_1.getDefaultScript)(path) : path.script; | ||
const payment = (0, utils_1.getPayment)(coin); | ||
switch (script) { | ||
case interface_2.ScriptType.P2SH_P2WPKH: | ||
const p2wpkh = payment.p2wpkh(coin, { publickey: compressed }); | ||
return payment.p2sh(coin, p2wpkh.redeemHash).address; | ||
case interface_2.ScriptType.P2SH_P2PKH: | ||
const p2pkh = payment.p2pkh(coin, { publickey: compressed }); | ||
return payment.p2sh(coin, p2pkh.redeemHash).address; | ||
case interface_2.ScriptType.P2PKH: | ||
return payment.p2pkh(coin, { publickey: compressed }).address; | ||
case interface_2.ScriptType.P2WPKH: | ||
return payment.p2wpkh(coin, { publickey: compressed }).address; | ||
case interface_2.ScriptType.P2TR: | ||
return payment.p2tr(coin, { publickey: compressed }).address; | ||
default: | ||
throw Error(`Invalid or unsupported ScriptType, got ${script} of ${coin}`); | ||
} | ||
} | ||
/** | ||
* Prepare data for address generation. | ||
* @param {string} path BIP32 path, ex: m/44'/0'/0'/0/0 | ||
* @param {AddressOption} [option] for path validation | ||
* @returns {communicationData} data for sending to device | ||
*/ | ||
static prepareAddress(path, option) { | ||
return this.preparePublickey(path, option); | ||
} | ||
/** | ||
* Generate address from response data. | ||
* @param {communicationData} response data from device | ||
* @param {string | PathObject} path BIP32 path, ex: m/44'/0'/0'/0/0 | ||
* @returns {string} address | ||
*/ | ||
static resolveAddress(response, path) { | ||
const pk = SecuxBTC_1.resolvePublickey(response); | ||
return SecuxBTC_1.addressConvert(pk, path); | ||
} | ||
/** | ||
* Prepare data for secp256k1 publickey. | ||
* @param {string} path BIP32 path, ex: m/44'/0'/0'/0/0 | ||
* @param {AddressOption} [option] for path validation | ||
* @returns {communicationData} data for sending to device | ||
*/ | ||
static preparePublickey(path, option) { | ||
var _a; | ||
(0, ow_1.default)(path, interface_2.ow_path); | ||
if (option) | ||
(0, ow_1.default)(option, interface_2.ow_AddressOption); | ||
const coin = (_a = option === null || option === void 0 ? void 0 : option.coin) !== null && _a !== void 0 ? _a : (0, utils_1.getCoinType)(path); | ||
const cointype = interface_2.coinmap[coin].coinType; | ||
const purpose = ((option === null || option === void 0 ? void 0 : option.script) === undefined) ? undefined : (0, utils_1.getPurpose)(option === null || option === void 0 ? void 0 : option.script); | ||
(0, ow_1.default)(path, (0, utility_1.ow_strictPath)(cointype, purpose)); | ||
return protocol_transaction_1.SecuxTransactionTool.getPublickey(path, interface_1.EllipticCurve.SECP256K1); | ||
} | ||
/** | ||
* Resolve secp256k1 publickey from response data. | ||
* @param {communicationData} response data from device | ||
* @returns {string} secp256k1 publickey (hex string) | ||
*/ | ||
static resolvePublickey(response) { | ||
const pk = protocol_transaction_1.SecuxTransactionTool.resolvePublickey(response, interface_1.EllipticCurve.SECP256K1, true); | ||
return Buffer.from(pk, "base64").toString("hex"); | ||
} | ||
/** | ||
* Prepare data for extended publickey generation. | ||
* @param {string} path BIP32 path, ex: m/44'/0'/0'/0/0 | ||
* @returns {communicationData} data for sending to device | ||
*/ | ||
static prepareXPublickey(path) { | ||
(0, ow_1.default)(path, interface_2.ow_accountPath); | ||
return protocol_transaction_1.SecuxTransactionTool.getXPublickey(path); | ||
} | ||
/** | ||
* Generate extended publickey from response data. | ||
* @param {communicationData} response data from device | ||
* @param {string} path BIP32 path, ex: m/44'/0'/0'/0/0 | ||
* @returns {string} extended publickey (xpub, ypub or zpub) | ||
*/ | ||
static resolveXPublickey(response, path) { | ||
(0, ow_1.default)(path, interface_2.ow_accountPath); | ||
return protocol_transaction_1.SecuxTransactionTool.resolveXPublickey(response, path); | ||
} | ||
/** | ||
* Prepare data for signing. | ||
* @param {txInput} inputs array of utxo object | ||
* @param {txOutput} outputs output object | ||
* @param {SignOption} [option] | ||
* @returns {prepared} | ||
*/ | ||
static prepareSign(inputs, outputs, option) { | ||
var _a; | ||
(0, ow_1.default)(inputs, ow_1.default.array.ofType(interface_2.ow_txInput).minLength(1)); | ||
(0, ow_1.default)(option, ow_1.default.any(ow_1.default.undefined, interface_2.ow_SignOption)); | ||
const coin = (_a = option === null || option === void 0 ? void 0 : option.coin) !== null && _a !== void 0 ? _a : (0, utils_1.getCoinType)(inputs[0].path); | ||
(0, ow_1.default)(outputs, interface_2.ow_txOutput); | ||
inputs.map(input => { | ||
const purpose = (input.script) ? (0, utils_1.getPurpose)(input.script) : interface_2.btcPurposes; | ||
//@ts-ignore | ||
(0, ow_1.default)(input.path, (0, utility_1.ow_strictPath)(interface_2.coinmap[coin].coinType, purpose)); | ||
}); | ||
let _ = (0, interface_2.isOutuptScriptExtended)(outputs.to); | ||
if (_) { | ||
const purpose = (_.script) ? (0, utils_1.getPurpose)(_.script) : interface_2.btcPurposes; | ||
//@ts-ignore | ||
(0, ow_1.default)(_.path, (0, utility_1.ow_strictPath)(interface_2.coinmap[coin].coinType, purpose)); | ||
} | ||
if (outputs.utxo) { | ||
const purpose = (outputs.utxo.script) ? (0, utils_1.getPurpose)(outputs.utxo.script) : interface_2.btcPurposes; | ||
//@ts-ignore | ||
(0, ow_1.default)(outputs.utxo.path, (0, utility_1.ow_strictPath)(interface_2.coinmap[coin].coinType, purpose)); | ||
} | ||
const psbt = new psbt_1.SecuxPsbt(coin, option === null || option === void 0 ? void 0 : option.isRBF); | ||
psbt.AddInputs(inputs); | ||
psbt.AddOutputs(outputs.utxo ? [outputs.to, outputs.utxo] : [outputs.to]); | ||
return (0, communication_1.wrapResult)(psbt.PrepareSign(option === null || option === void 0 ? void 0 : option.feeRate)); | ||
} | ||
/** | ||
* Reslove signature from response data. | ||
* @param {communicationData} response data from device | ||
* @returns {Array<string>} signature array of hex string | ||
*/ | ||
static resolveSignatureList(response) { | ||
const sigBufList = protocol_transaction_1.SecuxTransactionTool.resolveSignatureList(response).map(x => Buffer.from(x, "base64")); | ||
const sigList = sigBufList.map(x => utility_1.Signature.fromSignature(x)); | ||
return sigList.map(x => Buffer.concat([x.r, x.s]).toString("hex")); | ||
} | ||
/** | ||
* Serialize transaction wtih signature for broadcasting. | ||
* @param {communicationData|Array<communicationData>} response data from device | ||
* @param {TransactionObject} params | ||
* @returns {string} signed raw transaction | ||
*/ | ||
static resolveTransaction(response, params) { | ||
var _a; | ||
(0, ow_1.default)(response, ow_1.default.any(communication_1.ow_communicationData, ow_1.default.array.ofType(communication_1.ow_communicationData))); | ||
(0, ow_1.default)(params, interface_2.ow_TransactionObject); | ||
response = Array.isArray(response) ? response : [response]; | ||
const signatures = []; | ||
for (const rsp of response) { | ||
const sigList = SecuxBTC_1.resolveSignatureList(rsp).map(x => Buffer.from(x, "hex")); | ||
signatures.push(...sigList); | ||
} | ||
const pks = params.publickeys.map(x => (0, utils_1.getPublickey)(x)); | ||
const psbt = psbt_1.SecuxPsbt.FromBuffer(Buffer.from(params.rawTx, "hex"), (_a = params.coin) !== null && _a !== void 0 ? _a : interface_2.CoinType.BITCOIN); | ||
const tx = psbt.appendSignature(signatures, pks) | ||
.finalizeAllInputs() | ||
.extractTransaction() | ||
.toHex(); | ||
return tx; | ||
} | ||
static async getAddress(path, option) { | ||
var _a, _b; | ||
const data = SecuxBTC_1.prepareAddress(path, option); | ||
const rsp = await this.Exchange((0, communication_1.getBuffer)(data)); | ||
const address = SecuxBTC_1.resolveAddress(rsp, { | ||
coin: (_a = option === null || option === void 0 ? void 0 : option.coin) !== null && _a !== void 0 ? _a : (0, utils_1.getCoinType)(path), | ||
script: (_b = option === null || option === void 0 ? void 0 : option.script) !== null && _b !== void 0 ? _b : (0, utils_1.getDefaultScript)(path) | ||
}); | ||
return address; | ||
} | ||
static async getPublickey(path, option) { | ||
const data = SecuxBTC_1.preparePublickey(path, option); | ||
const rsp = await this.Exchange((0, communication_1.getBuffer)(data)); | ||
const publickey = SecuxBTC_1.resolvePublickey(rsp); | ||
return publickey; | ||
} | ||
static async getXPublickey(path) { | ||
const data = SecuxBTC_1.prepareXPublickey(path); | ||
const rsp = await this.Exchange((0, communication_1.getBuffer)(data)); | ||
const xpub = SecuxBTC_1.resolveXPublickey(rsp, path); | ||
return xpub; | ||
} | ||
static async sign(inputs, outputs, option) { | ||
var _a, _b; | ||
const cache = {}; | ||
const getPK = async (path) => { | ||
if (cache[path] !== undefined) | ||
return cache[path]; | ||
const publickey = await SecuxBTC_1.getPublickey.call(this, path, { coin }); | ||
const pk = Buffer.from(publickey, "hex"); | ||
cache[path] = pk; | ||
return pk; | ||
}; | ||
const coin = (_a = option === null || option === void 0 ? void 0 : option.coin) !== null && _a !== void 0 ? _a : (0, utils_1.getCoinType)(inputs[0].path); | ||
for (const txIn of inputs) { | ||
if (txIn.publickey !== undefined) | ||
continue; | ||
txIn.publickey = await getPK(txIn.path); | ||
} | ||
//@ts-ignore | ||
if (outputs.to.path && outputs.to.publickey === undefined) { | ||
//@ts-ignore | ||
outputs.to.publickey = await getPK(outputs.to.path); | ||
} | ||
if (((_b = outputs.utxo) === null || _b === void 0 ? void 0 : _b.path) && outputs.utxo.publickey === undefined) { | ||
outputs.utxo.publickey = await getPK(outputs.utxo.path); | ||
} | ||
const { commands, rawTx } = SecuxBTC_1.prepareSign(inputs, outputs, Object.assign(Object.assign({}, option), { coin })); | ||
return { | ||
multi_command: commands, | ||
rawTx, | ||
publickeys: inputs.map(x => x.publickey), | ||
coin | ||
}; | ||
} | ||
/** | ||
* Derive xpub and generate BTC address. | ||
* @param {string} xpub extended publickey (base58 encoded), depth must be 3 | ||
* @param {number} change BIP44 change field | ||
* @param {number} addressIndex BIP44 address_index field | ||
* @param {AddressOption} [option] for address generation | ||
* @returns {string} address | ||
*/ | ||
static deriveAddress(xpub, change, addressIndex, option) { | ||
var _a, _b; | ||
(0, ow_1.default)(change, ow_1.default.number.uint8); | ||
(0, ow_1.default)(addressIndex, ow_1.default.number.uint8); | ||
(0, ow_1.default)(option, ow_1.default.any(ow_1.default.undefined, interface_2.ow_AddressOption)); | ||
const _xpub = (0, xpub_1.decodeXPUB)(xpub); | ||
if (_xpub.depth !== 3) | ||
throw Error(`ArgumentError: expect depth from xpub is 3, but got ${_xpub.depth}`); | ||
if (option === null || option === void 0 ? void 0 : option.script) { | ||
if (option.script in [interface_2.ScriptType.P2PKH, interface_2.ScriptType.P2SH_P2PKH, interface_2.ScriptType.P2SH_P2WPKH, interface_2.ScriptType.P2WPKH]) { | ||
const purpose = (0, utils_1.getPurpose)(option === null || option === void 0 ? void 0 : option.script); | ||
if (_xpub.purpose !== purpose) { | ||
throw Error(`ArgumentError: expect purpose from xpub is ${purpose}, but got ${_xpub.purpose}`); | ||
} | ||
} | ||
else { | ||
if (_xpub.purpose !== 44) | ||
throw Error(`ArgumentError: expect purpose from xpub is 44, but got ${_xpub.purpose}`); | ||
_xpub.purpose === (0, utils_1.getPurpose)(option === null || option === void 0 ? void 0 : option.script); | ||
} | ||
} | ||
const { publickey } = (0, xpub_1.deriveKey)(_xpub.publickey, _xpub.chaincode, [change, addressIndex]); | ||
const coin = (_a = option === null || option === void 0 ? void 0 : option.coin) !== null && _a !== void 0 ? _a : interface_2.CoinType.BITCOIN; | ||
const script = (_b = option === null || option === void 0 ? void 0 : option.script) !== null && _b !== void 0 ? _b : (0, utils_1.getDefaultScript)(`m/${_xpub.purpose}'`); | ||
return SecuxBTC_1.addressConvert(publickey, { coin, script }); | ||
} | ||
/** | ||
* Estimate virtual size of transaction. | ||
* @param {Array<ScriptType>} inputs | ||
* @param {Array<ScriptType>} outputs | ||
* @returns {number} virtual size | ||
*/ | ||
static getVirtualSize(inputs, outputs) { | ||
const baseSize = 8 + | ||
varuint.encodingLength(inputs.length) + | ||
varuint.encodingLength(outputs.length) + | ||
inputs.reduce((sum, input) => sum + 40 + (0, utils_1.sliceSize)((0, utils_1.getInScriptSize)(input)), 0) + | ||
outputs.reduce((sum, output) => sum + 8 + (0, utils_1.sliceSize)((0, utils_1.getOutScriptSize)(output)), 0); | ||
const inputsWitness = inputs.map(x => (0, utils_1.getWitnessSize)(x)); | ||
const hasWitness = inputsWitness.some(x => x.length !== 0); | ||
const witnessSize = (!hasWitness) ? 0 : | ||
2 + inputsWitness.reduce((sum, w) => sum + (0, utils_1.vectorSize)(w), 0); | ||
return (baseSize * 4 + witnessSize) / 4; | ||
} | ||
}; | ||
SecuxBTC = SecuxBTC_1 = __decorate([ | ||
(0, transport_1.staticImplements)() | ||
], SecuxBTC); | ||
exports.SecuxBTC = SecuxBTC; | ||
(0, utility_1.loadPlugin)(SecuxBTC, "SecuxBTC"); | ||
/** | ||
* Data type for transmission. | ||
* @typedef {string|Buffer} communicationData | ||
*/ | ||
/** | ||
* Script type for input/output. | ||
* @typedef {enum} ScriptType | ||
* @property {number} P2PKH 0 | ||
* @property {number} P2WPKH 1 | ||
* @property {number} P2SH_P2PKH 2 | ||
* @property {number} P2SH_P2WPKH 3 | ||
* @property {number} P2TR 4 | ||
*/ | ||
/** | ||
* Coins that are nearly identical to Bitcoin. | ||
* @typedef {enum} CoinType | ||
* @property {number} BITCOIN 0 | ||
* @property {number} TESTNET 1 | ||
* @property {number} REGTEST 2 | ||
* @property {number} LITECOIN 3 | ||
* @property {number} BITCOINCASH 4 | ||
* @property {number} GROESTL 5 | ||
* @property {number} DIGIBYTE 6 | ||
* @property {number} DASH 7 | ||
* @property {number} DOGECOIN 8 | ||
*/ | ||
/** | ||
* Parameters for address generation. | ||
* @typedef {object} PathObject | ||
* @property {CoinType} coin enum | ||
* @property {ScriptType} script enum | ||
*/ | ||
/** | ||
* Options for path validation. | ||
* @typedef {object} AddressOption | ||
* @property {CoinType} [coin] enum | ||
* @property {ScriptType} [script] enum | ||
*/ | ||
/** | ||
* UTXO. | ||
* @typedef {object} txInput | ||
* @property {string} path BIP32 path refer to utxo | ||
* @property {string | Buffer} publickey scep256k1 publickey from `path` | ||
* @property {string} hash referenced transaction hash | ||
* @property {number} vout referenced transaction output index | ||
* @property {number | string} satoshis referenced transaction output amount | ||
* @property {ScriptType} [script] script type related to `path` | ||
* @property {string} [txHex] referenced raw transaction for validation | ||
*/ | ||
/** | ||
* Outputs consist of one payment and one or no return. | ||
* @typedef {object} txOutput | ||
* @property {txOutputAddress | txOutputScriptExtened} to receiving address information | ||
* @property {txOutputScriptExtened} [utxo] changes | ||
*/ | ||
/** | ||
* Receiving address and payment. | ||
* @typedef {object} txOutputAddress | ||
* @property {string} address receiving address | ||
* @property {number | string} satoshis receiving amount | ||
*/ | ||
/** | ||
* Payment for another held account. | ||
* @typedef {object} txOutputScriptExtened | ||
* @property {string} path BIP32 path | ||
* @property {string | Buffer} publickey scep256k1 publickey from `path` | ||
* @property {number | string} satoshis amount | ||
* @property {ScriptType} [script] script type related to `path` | ||
*/ | ||
/** | ||
* Options used during the signing. | ||
* @typedef {object} SignOption | ||
* @property {CoinType} [coin] check cointype for each input | ||
* @property {number} [feeRate] calculate optimal transaction fee and replace it | ||
* @property {boolean} [isRBF] make Replace-by-Fee transaction | ||
*/ | ||
/** | ||
* Object for the signing and validation. | ||
* @typedef {object} prepared | ||
* @property {communicationData} commandData data for sending to device | ||
* @property {string} rawTx unsigned raw transaction | ||
*/ | ||
/** | ||
* Paramters for finalizing transaction. | ||
* @typedef {object} TransactionObject | ||
* @property {string} rawTx unsigned raw transaction | ||
* @property {Array<string | Buffer>} publickeys publickey correspond to each input | ||
* @property {CoinType} [coin] | ||
*/ | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.SecuxBTC=exports.ScriptType=exports.CoinType=void 0;const e=require("secp256k1/elliptic"),t=require("varuint-bitcoin"),r=require("@secux/utility"),i=require("@secux/utility/lib/xpub"),o=require("ow"),u=require("@secux/protocol-transaction"),c=require("@secux/utility/lib/communication"),n=require("@secux/protocol-transaction/lib/interface"),s=require("./interface");Object.defineProperty(exports,"CoinType",{enumerable:!0,get:function(){return s.CoinType}}),Object.defineProperty(exports,"ScriptType",{enumerable:!0,get:function(){return s.ScriptType}});const p=require("./psbt"),a=require("./utils");class l{static addressConvert(t,r){const i=(0,a.getPublickey)(t);(0,o.default)(r,o.default.any(s.ow_path,s.ow_PathObject));const u=Buffer.from(e.publicKeyConvert(i,!0)),c="string"==typeof r?(0,a.getCoinType)(r):r.coin,n="string"==typeof r?(0,a.getDefaultScript)(r):r.script,p=(0,a.getPayment)(c);switch(n){case s.ScriptType.P2SH_P2WPKH:const e=p.p2wpkh(c,{publickey:u});return p.p2sh(c,e.redeemHash).address;case s.ScriptType.P2SH_P2PKH:const t=p.p2pkh(c,{publickey:u});return p.p2sh(c,t.redeemHash).address;case s.ScriptType.P2PKH:return p.p2pkh(c,{publickey:u}).address;case s.ScriptType.P2WPKH:return p.p2wpkh(c,{publickey:u}).address;case s.ScriptType.P2TR:return p.p2tr(c,{publickey:u}).address;default:throw Error(`Invalid or unsupported ScriptType, got ${n} of ${c}`)}}static prepareAddress(e,t){return this.preparePublickey(e,t)}static resolveAddress(e,t){const r=l.resolvePublickey(e);return l.addressConvert(r,t)}static preparePublickey(e,t){var i;(0,o.default)(e,s.ow_path),t&&(0,o.default)(t,s.ow_AddressOption);const c=null!==(i=null==t?void 0:t.coin)&&void 0!==i?i:(0,a.getCoinType)(e),p=s.coinmap[c].coinType,l=void 0===(null==t?void 0:t.script)?void 0:(0,a.getPurpose)(null==t?void 0:t.script);return(0,o.default)(e,(0,r.ow_strictPath)(p,l)),u.SecuxTransactionTool.getPublickey(e,n.EllipticCurve.SECP256K1)}static resolvePublickey(e){const t=u.SecuxTransactionTool.resolvePublickey(e,n.EllipticCurve.SECP256K1,!0);return Buffer.from(t,"base64").toString("hex")}static prepareXPublickey(e){return(0,o.default)(e,s.ow_accountPath),u.SecuxTransactionTool.getXPublickey(e)}static resolveXPublickey(e,t){return(0,o.default)(t,s.ow_accountPath),u.SecuxTransactionTool.resolveXPublickey(e,t)}static prepareSign(e,t,i){var u;(0,o.default)(e,o.default.array.ofType(s.ow_txInput).minLength(1)),(0,o.default)(i,o.default.any(o.default.undefined,s.ow_SignOption));const n=null!==(u=null==i?void 0:i.coin)&&void 0!==u?u:(0,a.getCoinType)(e[0].path);(0,o.default)(t,s.ow_txOutput),e.map((e=>{const t=e.script?(0,a.getPurpose)(e.script):s.btcPurposes;(0,o.default)(e.path,(0,r.ow_strictPath)(s.coinmap[n].coinType,t))}));let l=(0,s.isOutuptScriptExtended)(t.to);if(l){const e=l.script?(0,a.getPurpose)(l.script):s.btcPurposes;(0,o.default)(l.path,(0,r.ow_strictPath)(s.coinmap[n].coinType,e))}if(t.utxo){const e=t.utxo.script?(0,a.getPurpose)(t.utxo.script):s.btcPurposes;(0,o.default)(t.utxo.path,(0,r.ow_strictPath)(s.coinmap[n].coinType,e))}const d=new p.SecuxPsbt(n,null==i?void 0:i.isRBF);return d.AddInputs(e),d.AddOutputs(t.utxo?[t.to,t.utxo]:[t.to]),(0,c.wrapResult)(d.PrepareSign(null==i?void 0:i.feeRate))}static resolveSignatureList(e){return u.SecuxTransactionTool.resolveSignatureList(e).map((e=>Buffer.from(e,"base64"))).map((e=>r.Signature.fromSignature(e))).map((e=>Buffer.concat([e.r,e.s]).toString("hex")))}static resolveTransaction(e,t){var r;(0,o.default)(e,o.default.any(c.ow_communicationData,o.default.array.ofType(c.ow_communicationData))),(0,o.default)(t,s.ow_TransactionObject),e=Array.isArray(e)?e:[e];const i=[];for(const t of e){const e=l.resolveSignatureList(t).map((e=>Buffer.from(e,"hex")));i.push(...e)}const u=t.publickeys.map((e=>(0,a.getPublickey)(e)));return p.SecuxPsbt.FromBuffer(Buffer.from(t.rawTx,"hex"),null!==(r=t.coin)&&void 0!==r?r:s.CoinType.BITCOIN).appendSignature(i,u).finalizeAllInputs().extractTransaction().toHex()}static async getAddress(e,t){var r,i;const o=l.prepareAddress(e,t),u=await this.Exchange((0,c.getBuffer)(o));return l.resolveAddress(u,{coin:null!==(r=null==t?void 0:t.coin)&&void 0!==r?r:(0,a.getCoinType)(e),script:null!==(i=null==t?void 0:t.script)&&void 0!==i?i:(0,a.getDefaultScript)(e)})}static async getPublickey(e,t){const r=l.preparePublickey(e,t),i=await this.Exchange((0,c.getBuffer)(r));return l.resolvePublickey(i)}static async getXPublickey(e){const t=l.prepareXPublickey(e),r=await this.Exchange((0,c.getBuffer)(t));return l.resolveXPublickey(r,e)}static async sign(e,t,r){var i,o;const u={},c=async e=>{if(void 0!==u[e])return u[e];const t=await l.getPublickey.call(this,e,{coin:n}),r=Buffer.from(t,"hex");return u[e]=r,r},n=null!==(i=null==r?void 0:r.coin)&&void 0!==i?i:(0,a.getCoinType)(e[0].path);for(const t of e)void 0===t.publickey&&(t.publickey=await c(t.path));t.to.path&&void 0===t.to.publickey&&(t.to.publickey=await c(t.to.path)),(null===(o=t.utxo)||void 0===o?void 0:o.path)&&void 0===t.utxo.publickey&&(t.utxo.publickey=await c(t.utxo.path));const{commands:s,rawTx:p}=l.prepareSign(e,t,Object.assign(Object.assign({},r),{coin:n}));return{multi_command:s,rawTx:p,publickeys:e.map((e=>e.publickey)),coin:n}}static deriveAddress(e,t,r,u){var c,n;(0,o.default)(t,o.default.number.uint8),(0,o.default)(r,o.default.number.uint8),(0,o.default)(u,o.default.any(o.default.undefined,s.ow_AddressOption));const p=(0,i.decodeXPUB)(e);if(3!==p.depth)throw Error(`ArgumentError: expect depth from xpub is 3, but got ${p.depth}`);if(null==u?void 0:u.script)if(u.script in[s.ScriptType.P2PKH,s.ScriptType.P2SH_P2PKH,s.ScriptType.P2SH_P2WPKH,s.ScriptType.P2WPKH]){const e=(0,a.getPurpose)(null==u?void 0:u.script);if(p.purpose!==e)throw Error(`ArgumentError: expect purpose from xpub is ${e}, but got ${p.purpose}`)}else{if(44!==p.purpose)throw Error(`ArgumentError: expect purpose from xpub is 44, but got ${p.purpose}`);p.purpose,(0,a.getPurpose)(null==u?void 0:u.script)}const{publickey:d}=(0,i.deriveKey)(p.publickey,p.chaincode,[t,r]),f=null!==(c=null==u?void 0:u.coin)&&void 0!==c?c:s.CoinType.BITCOIN,y=null!==(n=null==u?void 0:u.script)&&void 0!==n?n:(0,a.getDefaultScript)(`m/${p.purpose}'`);return l.addressConvert(d,{coin:f,script:y})}static getVirtualSize(e,r){const i=8+t.encodingLength(e.length)+t.encodingLength(r.length)+e.reduce(((e,t)=>e+40+(0,a.sliceSize)((0,a.getInScriptSize)(t))),0)+r.reduce(((e,t)=>e+8+(0,a.sliceSize)((0,a.getOutScriptSize)(t))),0),o=e.map((e=>(0,a.getWitnessSize)(e)));return(4*i+(o.some((e=>0!==e.length))?2+o.reduce(((e,t)=>e+(0,a.vectorSize)(t)),0):0))/4}}exports.SecuxBTC=l,(0,r.loadPlugin)(l,"SecuxBTC"); |
@@ -1,64 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.taprootVerify = exports.taprootConvert = void 0; | ||
const utils_1 = require("./utils"); | ||
const BigInteger = require("bigi"); | ||
const ecurve = require('ecurve'); | ||
const curve = ecurve.getCurveByName('secp256k1'); | ||
const G = curve.G; | ||
const p = curve.p; | ||
const n = curve.n; | ||
const zero = BigInteger.ZERO; | ||
const one = BigInteger.ONE; | ||
const two = BigInteger.valueOf(2); | ||
const three = BigInteger.valueOf(3); | ||
const four = BigInteger.valueOf(4); | ||
const seven = BigInteger.valueOf(7); | ||
function taprootConvert(XOnlyPubkey, commitHash) { | ||
const P = liftX(XOnlyPubkey); | ||
const tweak = BigInteger.fromBuffer(commitHash); | ||
const Q = P.add(G.multiply(tweak)); | ||
return Q.affineX.toBuffer(32); | ||
} | ||
exports.taprootConvert = taprootConvert; | ||
function taprootVerify(signature, message, XOnlyPubkey) { | ||
const P = liftX(XOnlyPubkey); | ||
const Px = P.affineX.toBuffer(32); | ||
const r = BigInteger.fromBuffer(signature.slice(0, 32)); | ||
const s = BigInteger.fromBuffer(signature.slice(32, 64)); | ||
if (r.compareTo(p) >= 0) | ||
return false; | ||
if (s.compareTo(n) >= 0) | ||
return false; | ||
const e = getE(r.toBuffer(32), Px, message); | ||
const R = getR(s, e, P); | ||
if (R.curve.isInfinity(R) || !isEven(R) || !R.affineX.equals(r)) | ||
return false; | ||
return true; | ||
} | ||
exports.taprootVerify = taprootVerify; | ||
function liftX(XOnlyPubkey) { | ||
const x = BigInteger.fromBuffer(XOnlyPubkey); | ||
const c = x.pow(three).add(seven).mod(p); | ||
const y = c.modPow(p.add(one).divide(four), p); | ||
if (c.compareTo(y.modPow(two, p)) !== 0) { | ||
throw new Error('c is not equal to y^2'); | ||
} | ||
let P = ecurve.Point.fromAffine(curve, x, y); | ||
if (!isEven(P)) { | ||
P = ecurve.Point.fromAffine(curve, x, p.subtract(y)); | ||
} | ||
return P; | ||
} | ||
function isEven(point) { | ||
return point.affineY.mod(two).equals(zero); | ||
} | ||
function getE(Rx, Px, m) { | ||
const hash = (0, utils_1.taggedHash)('BIP0340/challenge', Buffer.concat([Rx, Px, m])); | ||
return BigInteger.fromBuffer(hash).mod(n); | ||
} | ||
function getR(s, e, P) { | ||
const sG = G.multiply(s); | ||
const eP = P.multiply(e); | ||
return sG.add(eP.negate()); | ||
} | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.taprootVerify=exports.taprootConvert=void 0;const e=require("./utils"),r=require("bigi"),o=require("ecurve"),t=o.getCurveByName("secp256k1"),f=t.G,n=t.p,u=t.n,i=r.ZERO,a=r.ONE,c=r.valueOf(2),s=r.valueOf(3),l=r.valueOf(4),d=r.valueOf(7);function m(e){const f=r.fromBuffer(e),u=f.pow(s).add(d).mod(n),i=u.modPow(n.add(a).divide(l),n);if(0!==u.compareTo(i.modPow(c,n)))throw new Error("c is not equal to y^2");let m=o.Point.fromAffine(t,f,i);return p(m)||(m=o.Point.fromAffine(t,f,n.subtract(i))),m}function p(e){return e.affineY.mod(c).equals(i)}exports.taprootConvert=function(e,o){const t=m(e),n=r.fromBuffer(o);return t.add(f.multiply(n)).affineX.toBuffer(32)},exports.taprootVerify=function(o,t,i){const a=m(i),c=a.affineX.toBuffer(32),s=r.fromBuffer(o.slice(0,32)),l=r.fromBuffer(o.slice(32,64));if(s.compareTo(n)>=0)return!1;if(l.compareTo(u)>=0)return!1;const d=function(o,t,f){const n=(0,e.taggedHash)("BIP0340/challenge",Buffer.concat([o,t,f]));return r.fromBuffer(n).mod(u)}(s.toBuffer(32),c,t),v=function(e,r,o){const t=f.multiply(e),n=o.multiply(r);return t.add(n.negate())}(l,d,a);return!(v.curve.isInfinity(v)||!p(v)||!v.affineX.equals(s))}; |
@@ -1,134 +0,1 @@ | ||
"use strict"; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var _BufferReader_buffer; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.BufferWriter = exports.BufferReader = void 0; | ||
const varuint = require("varuint-bitcoin"); | ||
const bignumber_js_1 = require("bignumber.js"); | ||
/** | ||
* Helper class for serialization of bitcoin data types into a pre-allocated buffer. | ||
*/ | ||
class BufferWriter { | ||
constructor(buffer, offset = 0) { | ||
this.buffer = buffer; | ||
this.offset = offset; | ||
} | ||
writeUInt8(i) { | ||
this.offset = this.buffer.writeUInt8(i, this.offset); | ||
} | ||
writeInt32(i) { | ||
this.offset = this.buffer.writeInt32LE(i, this.offset); | ||
} | ||
writeUInt32(i) { | ||
this.offset = this.buffer.writeUInt32LE(i, this.offset); | ||
} | ||
writeUInt64(i) { | ||
this.offset = writeUInt64LE(this.buffer, i, this.offset); | ||
} | ||
writeVarInt(i) { | ||
varuint.encode(i, this.buffer, this.offset); | ||
this.offset += varuint.encode.bytes; | ||
} | ||
writeSlice(slice) { | ||
if (this.buffer.length < this.offset + slice.length) { | ||
throw new Error('Cannot write slice out of bounds'); | ||
} | ||
this.offset += slice.copy(this.buffer, this.offset); | ||
} | ||
writeVarSlice(slice) { | ||
this.writeVarInt(slice.length); | ||
this.writeSlice(slice); | ||
} | ||
writeVector(vector) { | ||
this.writeVarInt(vector.length); | ||
vector.forEach(buf => this.writeVarSlice(buf)); | ||
} | ||
} | ||
exports.BufferWriter = BufferWriter; | ||
/** | ||
* Helper class for reading of bitcoin data types from a buffer. | ||
*/ | ||
class BufferReader { | ||
constructor(buffer, offset = 0) { | ||
_BufferReader_buffer.set(this, void 0); | ||
__classPrivateFieldSet(this, _BufferReader_buffer, Buffer.from([...buffer]), "f"); | ||
this.offset = offset; | ||
} | ||
readUInt8() { | ||
const result = __classPrivateFieldGet(this, _BufferReader_buffer, "f").readUInt8(this.offset); | ||
this.offset += 1; | ||
return result; | ||
} | ||
readInt32() { | ||
const result = __classPrivateFieldGet(this, _BufferReader_buffer, "f").readInt32LE(this.offset); | ||
this.offset += 4; | ||
return result; | ||
} | ||
readUInt32() { | ||
const result = __classPrivateFieldGet(this, _BufferReader_buffer, "f").readUInt32LE(this.offset); | ||
this.offset += 4; | ||
return result; | ||
} | ||
readUInt64() { | ||
const result = readUInt64LE(__classPrivateFieldGet(this, _BufferReader_buffer, "f"), this.offset); | ||
this.offset += 8; | ||
return result; | ||
} | ||
readVarInt() { | ||
const vi = varuint.decode(__classPrivateFieldGet(this, _BufferReader_buffer, "f"), this.offset); | ||
this.offset += varuint.decode.bytes; | ||
return vi; | ||
} | ||
readSlice(n) { | ||
if (__classPrivateFieldGet(this, _BufferReader_buffer, "f").length < this.offset + n) { | ||
throw new Error('Cannot read slice out of bounds'); | ||
} | ||
const result = __classPrivateFieldGet(this, _BufferReader_buffer, "f").slice(this.offset, this.offset + n); | ||
this.offset += n; | ||
return result; | ||
} | ||
readVarSlice() { | ||
return this.readSlice(this.readVarInt()); | ||
} | ||
readVector() { | ||
const count = this.readVarInt(); | ||
const vector = []; | ||
for (let i = 0; i < count; i++) | ||
vector.push(this.readVarSlice()); | ||
return vector; | ||
} | ||
} | ||
exports.BufferReader = BufferReader; | ||
_BufferReader_buffer = new WeakMap(); | ||
// https://github.com/feross/buffer/blob/master/index.js#L1127 | ||
function verifuint(value) { | ||
if (typeof value !== 'number') | ||
throw new Error('cannot write a non-number as a number'); | ||
if (value < 0) | ||
throw new Error('specified a negative value for writing an unsigned value'); | ||
if (Math.floor(value) !== value) | ||
throw new Error('value has a fractional component'); | ||
} | ||
function writeUInt64LE(buffer, value, offset) { | ||
const num = new bignumber_js_1.BigNumber(value); | ||
verifuint(num.toNumber()); | ||
const buf = Buffer.from(num.toString(16).padStart(16, '0'), "hex"); | ||
buf.reverse().copy(buffer, offset); | ||
return offset + 8; | ||
} | ||
function readUInt64LE(buffer, offset) { | ||
const str = buffer.slice(offset, offset + 8).reverse().toString("hex"); | ||
const value = new bignumber_js_1.BigNumber(str, 16); | ||
verifuint(value.toNumber()); | ||
return value; | ||
} | ||
"use strict";var t,e=this&&this.__classPrivateFieldSet||function(t,e,r,s,i){if("m"===s)throw new TypeError("Private method is not writable");if("a"===s&&!i)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof e?t!==e||!i:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===s?i.call(t,r):i?i.value=r:e.set(t,r),r},r=this&&this.__classPrivateFieldGet||function(t,e,r,s){if("a"===r&&!s)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!s:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?s:"a"===r?s.call(t):s?s.value:e.get(t)};Object.defineProperty(exports,"__esModule",{value:!0}),exports.BufferWriter=exports.BufferReader=void 0;const s=require("varuint-bitcoin"),i=require("bignumber.js");exports.BufferWriter=class{constructor(t,e=0){this.buffer=t,this.offset=e}writeUInt8(t){this.offset=this.buffer.writeUInt8(t,this.offset)}writeInt32(t){this.offset=this.buffer.writeInt32LE(t,this.offset)}writeUInt32(t){this.offset=this.buffer.writeUInt32LE(t,this.offset)}writeUInt64(t){this.offset=function(t,e,r){const s=new i.BigNumber(e);o(s.toNumber());return Buffer.from(s.toString(16).padStart(16,"0"),"hex").reverse().copy(t,r),r+8}(this.buffer,t,this.offset)}writeVarInt(t){s.encode(t,this.buffer,this.offset),this.offset+=s.encode.bytes}writeSlice(t){if(this.buffer.length<this.offset+t.length)throw new Error("Cannot write slice out of bounds");this.offset+=t.copy(this.buffer,this.offset)}writeVarSlice(t){this.writeVarInt(t.length),this.writeSlice(t)}writeVector(t){this.writeVarInt(t.length),t.forEach((t=>this.writeVarSlice(t)))}};function o(t){if("number"!=typeof t)throw new Error("cannot write a non-number as a number");if(t<0)throw new Error("specified a negative value for writing an unsigned value");if(Math.floor(t)!==t)throw new Error("value has a fractional component")}exports.BufferReader=class{constructor(r,s=0){t.set(this,void 0),e(this,t,Buffer.from([...r]),"f"),this.offset=s}readUInt8(){const e=r(this,t,"f").readUInt8(this.offset);return this.offset+=1,e}readInt32(){const e=r(this,t,"f").readInt32LE(this.offset);return this.offset+=4,e}readUInt32(){const e=r(this,t,"f").readUInt32LE(this.offset);return this.offset+=4,e}readUInt64(){const e=function(t,e){const r=t.slice(e,e+8).reverse().toString("hex"),s=new i.BigNumber(r,16);return o(s.toNumber()),s}(r(this,t,"f"),this.offset);return this.offset+=8,e}readVarInt(){const e=s.decode(r(this,t,"f"),this.offset);return this.offset+=s.decode.bytes,e}readSlice(e){if(r(this,t,"f").length<this.offset+e)throw new Error("Cannot read slice out of bounds");const s=r(this,t,"f").slice(this.offset,this.offset+e);return this.offset+=e,s}readVarSlice(){return this.readSlice(this.readVarInt())}readVector(){const t=this.readVarInt(),e=[];for(let r=0;r<t;r++)e.push(this.readVarSlice());return e}},t=new WeakMap; |
@@ -1,125 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.OPCODES = exports.dogecoin = exports.dash = exports.digibyte = exports.groestl = exports.bitcoincash = exports.litecoin = exports.regtest = exports.testnet = exports.bitcoin = void 0; | ||
exports.bitcoin = Object.freeze({ | ||
messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
bech32: 'bc', | ||
bip32: { | ||
public: 0x0488b21e, | ||
private: 0x0488ade4, | ||
}, | ||
pubKeyHash: 0x00, | ||
scriptHash: 0x05, | ||
wif: 0x80, | ||
coinType: 0, | ||
}); | ||
exports.testnet = Object.freeze({ | ||
messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
bech32: 'tb', | ||
bip32: { | ||
public: 0x043587cf, | ||
private: 0x04358394, | ||
}, | ||
pubKeyHash: 0x6f, | ||
scriptHash: 0xc4, | ||
wif: 0xef, | ||
coinType: 1, | ||
}); | ||
exports.regtest = Object.freeze({ | ||
messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
bech32: 'bcrt', | ||
bip32: { | ||
public: 0x043587cf, | ||
private: 0x04358394, | ||
}, | ||
pubKeyHash: 0x6f, | ||
scriptHash: 0xc4, | ||
wif: 0xef, | ||
coinType: 1, | ||
}); | ||
exports.litecoin = Object.freeze({ | ||
messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
bech32: 'ltc', | ||
bip32: { | ||
public: 0x019da462, | ||
private: 0x019d9cfe | ||
}, | ||
pubKeyHash: 0x30, | ||
scriptHash: 0x32, | ||
wif: 0xb0, | ||
coinType: 2, | ||
}); | ||
exports.bitcoincash = Object.freeze({ | ||
messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
bip32: { | ||
public: 0x0488b21e, | ||
private: 0x0488ade4 | ||
}, | ||
pubKeyHash: 0x00, | ||
scriptHash: 0x05, | ||
wif: 0x80, | ||
coinType: 145, | ||
}); | ||
exports.groestl = Object.freeze({ | ||
messagePrefix: '\x1CGroestlCoin Signed Message:\n', | ||
bech32: 'grs', | ||
bip32: { | ||
public: 0x0488b21e, | ||
private: 0x0488ade4 | ||
}, | ||
pubKeyHash: 0x24, | ||
scriptHash: 0x05, | ||
wif: 0x80, | ||
coinType: 17, | ||
}); | ||
exports.digibyte = Object.freeze({ | ||
messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
bech32: 'dgb', | ||
bip32: { | ||
public: 0x0488b21e, | ||
private: 0x0488ade4 | ||
}, | ||
pubKeyHash: 0x1e, | ||
scriptHash: 0x3f, | ||
wif: 0x80, | ||
coinType: 20, | ||
}); | ||
exports.dash = Object.freeze({ | ||
messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
bech32: 'dash', | ||
bip32: { | ||
public: 0x0488b21e, | ||
private: 0x0488ade4 | ||
}, | ||
pubKeyHash: 0x4c, | ||
scriptHash: 0x10, | ||
wif: 0xcc, | ||
coinType: 5, | ||
}); | ||
exports.dogecoin = Object.freeze({ | ||
messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
bech32: 'doge', | ||
bip32: { | ||
public: 0x02facafd, | ||
private: 0x02fac398 | ||
}, | ||
pubKeyHash: 0x1e, | ||
scriptHash: 0x16, | ||
wif: 0x9e, | ||
coinType: 3, | ||
}); | ||
exports.OPCODES = Object.freeze({ | ||
OP_0: 0x00, | ||
OP_PUSHDATA1: 0x4c, | ||
OP_PUSHDATA2: 0x4d, | ||
OP_PUSHDATA4: 0x4e, | ||
OP_1NEGATE: 0x4f, | ||
OP_INT_BASE: 0x50, | ||
OP_DUP: 0x76, | ||
OP_HASH160: 0xa9, | ||
OP_EQUAL: 0x87, | ||
OP_EQUALVERIFY: 0x88, | ||
OP_CODESEPARATOR: 0xab, | ||
OP_CHECKSIG: 0xac, | ||
OP_CHECKMULTISIG: 0xae | ||
}); | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.OPCODES=exports.dogecoin=exports.dash=exports.digibyte=exports.groestl=exports.bitcoincash=exports.litecoin=exports.regtest=exports.testnet=exports.bitcoin=void 0,exports.bitcoin=Object.freeze({messagePrefix:"Bitcoin Signed Message:\n",bech32:"bc",bip32:{public:76067358,private:76066276},pubKeyHash:0,scriptHash:5,wif:128,coinType:0}),exports.testnet=Object.freeze({messagePrefix:"Bitcoin Signed Message:\n",bech32:"tb",bip32:{public:70617039,private:70615956},pubKeyHash:111,scriptHash:196,wif:239,coinType:1}),exports.regtest=Object.freeze({messagePrefix:"Bitcoin Signed Message:\n",bech32:"bcrt",bip32:{public:70617039,private:70615956},pubKeyHash:111,scriptHash:196,wif:239,coinType:1}),exports.litecoin=Object.freeze({messagePrefix:"Bitcoin Signed Message:\n",bech32:"ltc",bip32:{public:27108450,private:27106558},pubKeyHash:48,scriptHash:50,wif:176,coinType:2}),exports.bitcoincash=Object.freeze({messagePrefix:"Bitcoin Signed Message:\n",bip32:{public:76067358,private:76066276},pubKeyHash:0,scriptHash:5,wif:128,coinType:145}),exports.groestl=Object.freeze({messagePrefix:"GroestlCoin Signed Message:\n",bech32:"grs",bip32:{public:76067358,private:76066276},pubKeyHash:36,scriptHash:5,wif:128,coinType:17}),exports.digibyte=Object.freeze({messagePrefix:"Bitcoin Signed Message:\n",bech32:"dgb",bip32:{public:76067358,private:76066276},pubKeyHash:30,scriptHash:63,wif:128,coinType:20}),exports.dash=Object.freeze({messagePrefix:"Bitcoin Signed Message:\n",bech32:"dash",bip32:{public:76067358,private:76066276},pubKeyHash:76,scriptHash:16,wif:204,coinType:5}),exports.dogecoin=Object.freeze({messagePrefix:"Bitcoin Signed Message:\n",bech32:"doge",bip32:{public:49990397,private:49988504},pubKeyHash:30,scriptHash:22,wif:158,coinType:3}),exports.OPCODES=Object.freeze({OP_0:0,OP_PUSHDATA1:76,OP_PUSHDATA2:77,OP_PUSHDATA4:78,OP_1NEGATE:79,OP_INT_BASE:80,OP_DUP:118,OP_HASH160:169,OP_EQUAL:135,OP_EQUALVERIFY:136,OP_CODESEPARATOR:171,OP_CHECKSIG:172,OP_CHECKMULTISIG:174}); |
@@ -1,113 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ow_SignOption = exports.ow_AddressOption = exports.ow_TransactionObject = exports.isOutuptScriptExtended = exports.isOutuptScript = exports.isOutputAddress = exports.ow_txOutput = exports.ow_txOutputScriptExtened = exports.ow_txOutputScript = exports.ow_txOutputAddress = exports.ow_txInput = exports.ow_PathObject = exports.ow_hashString = exports.ow_hexString = exports.ow_accountPath = exports.ow_path = exports.ow_balance = exports.btcPurposes = exports.btcCoinTypes = exports.coinmap = exports.CoinType = exports.ScriptType = exports.OPCODES = void 0; | ||
const ow_1 = require("ow"); | ||
const constants = require("./coindef"); | ||
const utils = require("@secux/utility"); | ||
var coindef_1 = require("./coindef"); | ||
Object.defineProperty(exports, "OPCODES", { enumerable: true, get: function () { return coindef_1.OPCODES; } }); | ||
var ScriptType; | ||
(function (ScriptType) { | ||
ScriptType[ScriptType["P2PKH"] = 0] = "P2PKH"; | ||
ScriptType[ScriptType["P2WPKH"] = 1] = "P2WPKH"; | ||
ScriptType[ScriptType["P2SH_P2PKH"] = 2] = "P2SH_P2PKH"; | ||
ScriptType[ScriptType["P2SH_P2WPKH"] = 3] = "P2SH_P2WPKH"; | ||
ScriptType[ScriptType["P2TR"] = 4] = "P2TR"; | ||
ScriptType[ScriptType["__LENGTH"] = 5] = "__LENGTH"; | ||
})(ScriptType = exports.ScriptType || (exports.ScriptType = {})); | ||
var CoinType; | ||
(function (CoinType) { | ||
CoinType[CoinType["BITCOIN"] = 0] = "BITCOIN"; | ||
CoinType[CoinType["TESTNET"] = 1] = "TESTNET"; | ||
CoinType[CoinType["REGTEST"] = 2] = "REGTEST"; | ||
CoinType[CoinType["LITECOIN"] = 3] = "LITECOIN"; | ||
CoinType[CoinType["BITCOINCASH"] = 4] = "BITCOINCASH"; | ||
CoinType[CoinType["GROESTL"] = 5] = "GROESTL"; | ||
CoinType[CoinType["DIGIBYTE"] = 6] = "DIGIBYTE"; | ||
CoinType[CoinType["DASH"] = 7] = "DASH"; | ||
CoinType[CoinType["DOGECOIN"] = 8] = "DOGECOIN"; | ||
CoinType[CoinType["__LENGTH"] = 9] = "__LENGTH"; | ||
})(CoinType = exports.CoinType || (exports.CoinType = {})); | ||
// must match above CoinType define | ||
exports.coinmap = Object.freeze(Object.values(CoinType).slice(0, CoinType.__LENGTH) | ||
//@ts-ignore | ||
.map(x => constants[x.toLowerCase()])); | ||
exports.btcCoinTypes = Object.freeze(exports.coinmap.map(x => Object.freeze(x.coinType))); | ||
exports.btcPurposes = Object.freeze([ | ||
Object.freeze(44), | ||
Object.freeze(49), | ||
Object.freeze(84), | ||
Object.freeze(86) | ||
]); | ||
exports.ow_balance = ow_1.default.any(ow_1.default.number.integer.positive, utils.owTool.numberString); | ||
//@ts-ignore | ||
exports.ow_path = utils.ow_strictPath(exports.btcCoinTypes, exports.btcPurposes); | ||
//@ts-ignore | ||
exports.ow_accountPath = utils.ow_accountPath(exports.btcCoinTypes, exports.btcPurposes); | ||
exports.ow_hexString = utils.owTool.hexString; | ||
exports.ow_hashString = utils.owTool.hashString; | ||
exports.ow_PathObject = ow_1.default.object.exactShape({ | ||
coin: ow_1.default.number.inRange(0, CoinType.__LENGTH - 1), | ||
script: ow_1.default.number.inRange(0, ScriptType.__LENGTH - 1), | ||
}); | ||
exports.ow_txInput = ow_1.default.object.exactShape({ | ||
hash: exports.ow_hashString, | ||
vout: ow_1.default.number.greaterThanOrEqual(0), | ||
txHex: ow_1.default.any(ow_1.default.undefined, exports.ow_hexString), | ||
script: ow_1.default.optional.number.inRange(0, ScriptType.__LENGTH - 1), | ||
satoshis: exports.ow_balance, | ||
path: exports.ow_path, | ||
publickey: ow_1.default.any(ow_1.default.undefined, exports.ow_hexString, ow_1.default.buffer) | ||
}); | ||
exports.ow_txOutputAddress = ow_1.default.object.exactShape({ | ||
address: exports.ow_hashString, | ||
satoshis: exports.ow_balance | ||
}); | ||
exports.ow_txOutputScript = ow_1.default.object.exactShape({ | ||
scriptHex: exports.ow_hexString, | ||
satoshis: exports.ow_balance | ||
}); | ||
exports.ow_txOutputScriptExtened = ow_1.default.object.exactShape({ | ||
publickey: ow_1.default.any(ow_1.default.undefined, exports.ow_hexString, ow_1.default.buffer), | ||
path: exports.ow_path, | ||
satoshis: exports.ow_balance, | ||
script: ow_1.default.optional.number.inRange(0, ScriptType.__LENGTH - 1) | ||
}); | ||
exports.ow_txOutput = ow_1.default.object.exactShape({ | ||
to: ow_1.default.any(exports.ow_txOutputAddress, exports.ow_txOutputScriptExtened), | ||
utxo: ow_1.default.any(ow_1.default.undefined, exports.ow_txOutputScriptExtened) | ||
}); | ||
function isOutputAddress(output) { | ||
const out = output; | ||
if (out.address) | ||
return out; | ||
} | ||
exports.isOutputAddress = isOutputAddress; | ||
function isOutuptScript(output) { | ||
const out = output; | ||
if (out.scriptHex) | ||
return out; | ||
} | ||
exports.isOutuptScript = isOutuptScript; | ||
function isOutuptScriptExtended(output) { | ||
try { | ||
(0, ow_1.default)(output, exports.ow_txOutputScriptExtened); | ||
return output; | ||
} | ||
catch (error) { } | ||
} | ||
exports.isOutuptScriptExtended = isOutuptScriptExtended; | ||
exports.ow_TransactionObject = ow_1.default.object.partialShape({ | ||
rawTx: exports.ow_hexString, | ||
publickeys: ow_1.default.array.ofType(ow_1.default.any(exports.ow_hexString, ow_1.default.buffer)), | ||
coin: ow_1.default.optional.number.inRange(0, CoinType.__LENGTH - 1) | ||
}); | ||
exports.ow_AddressOption = ow_1.default.object.exactShape({ | ||
coin: ow_1.default.optional.number.inRange(0, CoinType.__LENGTH - 1), | ||
script: ow_1.default.optional.number.inRange(0, ScriptType.__LENGTH - 1), | ||
}); | ||
exports.ow_SignOption = ow_1.default.object.exactShape({ | ||
coin: ow_1.default.optional.number.inRange(0, CoinType.__LENGTH - 1), | ||
feeRate: ow_1.default.optional.number.greaterThanOrEqual(1), | ||
isRBF: ow_1.default.optional.boolean | ||
}); | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ow_SignOption=exports.ow_AddressOption=exports.ow_TransactionObject=exports.isOutuptScriptExtended=exports.isOutuptScript=exports.isOutputAddress=exports.ow_txOutput=exports.ow_txOutputScriptExtened=exports.ow_txOutputScript=exports.ow_txOutputAddress=exports.ow_txInput=exports.ow_PathObject=exports.ow_hashString=exports.ow_hexString=exports.ow_accountPath=exports.ow_path=exports.ow_balance=exports.btcPurposes=exports.btcCoinTypes=exports.coinmap=exports.CoinType=exports.ScriptType=exports.OPCODES=void 0;const t=require("ow"),e=require("./coindef"),o=require("@secux/utility");var r,p,s=require("./coindef");Object.defineProperty(exports,"OPCODES",{enumerable:!0,get:function(){return s.OPCODES}}),function(t){t[t.P2PKH=0]="P2PKH",t[t.P2WPKH=1]="P2WPKH",t[t.P2SH_P2PKH=2]="P2SH_P2PKH",t[t.P2SH_P2WPKH=3]="P2SH_P2WPKH",t[t.P2TR=4]="P2TR",t[t.__LENGTH=5]="__LENGTH"}(r=exports.ScriptType||(exports.ScriptType={})),function(t){t[t.BITCOIN=0]="BITCOIN",t[t.TESTNET=1]="TESTNET",t[t.REGTEST=2]="REGTEST",t[t.LITECOIN=3]="LITECOIN",t[t.BITCOINCASH=4]="BITCOINCASH",t[t.GROESTL=5]="GROESTL",t[t.DIGIBYTE=6]="DIGIBYTE",t[t.DASH=7]="DASH",t[t.DOGECOIN=8]="DOGECOIN",t[t.__LENGTH=9]="__LENGTH"}(p=exports.CoinType||(exports.CoinType={})),exports.coinmap=Object.freeze(Object.values(p).slice(0,p.__LENGTH).map((t=>e[t.toLowerCase()]))),exports.btcCoinTypes=Object.freeze(exports.coinmap.map((t=>Object.freeze(t.coinType)))),exports.btcPurposes=Object.freeze([Object.freeze(44),Object.freeze(49),Object.freeze(84),Object.freeze(86)]),exports.ow_balance=t.default.any(t.default.number.integer.positive,o.owTool.numberString),exports.ow_path=o.ow_strictPath(exports.btcCoinTypes,exports.btcPurposes),exports.ow_accountPath=o.ow_accountPath(exports.btcCoinTypes,exports.btcPurposes),exports.ow_hexString=o.owTool.hexString,exports.ow_hashString=o.owTool.hashString,exports.ow_PathObject=t.default.object.exactShape({coin:t.default.number.inRange(0,p.__LENGTH-1),script:t.default.number.inRange(0,r.__LENGTH-1)}),exports.ow_txInput=t.default.object.exactShape({hash:exports.ow_hashString,vout:t.default.number.greaterThanOrEqual(0),txHex:t.default.any(t.default.undefined,exports.ow_hexString),script:t.default.optional.number.inRange(0,r.__LENGTH-1),satoshis:exports.ow_balance,path:exports.ow_path,publickey:t.default.any(t.default.undefined,exports.ow_hexString,t.default.buffer)}),exports.ow_txOutputAddress=t.default.object.exactShape({address:exports.ow_hashString,satoshis:exports.ow_balance}),exports.ow_txOutputScript=t.default.object.exactShape({scriptHex:exports.ow_hexString,satoshis:exports.ow_balance}),exports.ow_txOutputScriptExtened=t.default.object.exactShape({publickey:t.default.any(t.default.undefined,exports.ow_hexString,t.default.buffer),path:exports.ow_path,satoshis:exports.ow_balance,script:t.default.optional.number.inRange(0,r.__LENGTH-1)}),exports.ow_txOutput=t.default.object.exactShape({to:t.default.any(exports.ow_txOutputAddress,exports.ow_txOutputScriptExtened),utxo:t.default.any(t.default.undefined,exports.ow_txOutputScriptExtened)}),exports.isOutputAddress=function(t){const e=t;if(e.address)return e},exports.isOutuptScript=function(t){const e=t;if(e.scriptHex)return e},exports.isOutuptScriptExtended=function(e){try{return(0,t.default)(e,exports.ow_txOutputScriptExtened),e}catch(t){}},exports.ow_TransactionObject=t.default.object.partialShape({rawTx:exports.ow_hexString,publickeys:t.default.array.ofType(t.default.any(exports.ow_hexString,t.default.buffer)),coin:t.default.optional.number.inRange(0,p.__LENGTH-1)}),exports.ow_AddressOption=t.default.object.exactShape({coin:t.default.optional.number.inRange(0,p.__LENGTH-1),script:t.default.optional.number.inRange(0,r.__LENGTH-1)}),exports.ow_SignOption=t.default.object.exactShape({coin:t.default.optional.number.inRange(0,p.__LENGTH-1),feeRate:t.default.optional.number.greaterThanOrEqual(1),isRBF:t.default.optional.boolean}); |
@@ -1,435 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Psbtv2 = void 0; | ||
const bip174_1 = require("bip174"); | ||
const convert = require("bip174/src/lib/converter"); | ||
const bufferutils_1 = require("./bufferutils"); | ||
class Psbtv2 extends bip174_1.Psbt { | ||
static fromBuffer(buffer, txFromBuffer) { | ||
const results = psbtFromBuffer(buffer, txFromBuffer); | ||
const psbt = new this(results.globalMap.unsignedTx); | ||
Object.assign(psbt, results); | ||
return psbt; | ||
} | ||
} | ||
exports.Psbtv2 = Psbtv2; | ||
function psbtFromBuffer(buffer, txGetter) { | ||
// implements PSBTv2 (https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki) | ||
// refer to https://github.com/achow101/hardware-wallet-interface/blob/psbt2/hwilib/psbt.py | ||
if (buffer.readUInt32BE() !== 0x70736274) { | ||
throw Error("Format Error: Invalid Magic Number"); | ||
} | ||
if (buffer.readUInt8(4) !== 0xff) { | ||
throw Error('Format Error: Magic Number must be followed by 0xff separator'); | ||
} | ||
const reader = new bufferutils_1.BufferReader(buffer); | ||
reader.offset += 5; | ||
const getKeyValue = () => { | ||
const key = reader.readVarSlice(); | ||
const value = reader.readVarSlice(); | ||
return { key, value }; | ||
}; | ||
const checkEndOfKeyValPairs = () => { | ||
if (reader.offset >= buffer.length) | ||
throw Error('Format Error: Unexpected End of PSBT'); | ||
const isEnd = buffer.readUInt8(reader.offset) === 0; | ||
if (isEnd) | ||
reader.offset += 1; | ||
return isEnd; | ||
}; | ||
const globalMapKeyVals = []; | ||
const globalKeyIndex = {}; | ||
while (!checkEndOfKeyValPairs()) { | ||
const keyVal = getKeyValue(); | ||
const hexKey = keyVal.key.toString('hex'); | ||
if (globalKeyIndex[hexKey]) | ||
throw Error('Format Error: Keys must be unique for global keymap: key ' + hexKey); | ||
globalKeyIndex[hexKey] = 1; | ||
globalMapKeyVals.push(keyVal); | ||
} | ||
const unsignedTxMaps = globalMapKeyVals.filter(keyVal => keyVal.key[0] === GlobalTypes.UNSIGNED_TX); | ||
if (unsignedTxMaps.length !== 1) | ||
throw Error('Format Error: Only one UNSIGNED_TX allowed'); | ||
const unsignedTx = txGetter(unsignedTxMaps[0].value); | ||
// Get input and output counts to loop the respective fields | ||
const { inputCount, outputCount } = unsignedTx.getInputOutputCounts(); | ||
const inputKeyVals = []; | ||
const outputKeyVals = []; | ||
// Get input fields | ||
for (let index = 0; index < inputCount; index++) { | ||
const inputKeyIndex = {}; | ||
const input = []; | ||
while (!checkEndOfKeyValPairs()) { | ||
const keyVal = getKeyValue(); | ||
const hexKey = keyVal.key.toString('hex'); | ||
if (inputKeyIndex[hexKey]) { | ||
throw Error(`Format Error: Keys must be unique, got "${hexKey}" from input#${index}`); | ||
} | ||
inputKeyIndex[hexKey] = 1; | ||
input.push(keyVal); | ||
} | ||
inputKeyVals.push(input); | ||
} | ||
for (let index = 0; index < outputCount; index++) { | ||
const outputKeyIndex = {}; | ||
const output = []; | ||
while (!checkEndOfKeyValPairs()) { | ||
const keyVal = getKeyValue(); | ||
const hexKey = keyVal.key.toString('hex'); | ||
if (outputKeyIndex[hexKey]) { | ||
throw Error(`Format Error: Keys must be unique, got "${hexKey}" from output#${index}`); | ||
} | ||
outputKeyIndex[hexKey] = 1; | ||
output.push(keyVal); | ||
} | ||
outputKeyVals.push(output); | ||
} | ||
return psbtFromKeyVals(unsignedTx, { | ||
globalMapKeyVals, | ||
inputKeyVals, | ||
outputKeyVals, | ||
}); | ||
} | ||
function psbtFromKeyVals(unsignedTx, { globalMapKeyVals, inputKeyVals, outputKeyVals }) { | ||
// That was easy :-) | ||
const globalMap = { | ||
unsignedTx, | ||
}; | ||
let txCount = 0; | ||
let inputCount; | ||
let outputCount; | ||
for (const keyVal of globalMapKeyVals) { | ||
// If a globalMap item needs pubkey, uncomment | ||
// const pubkey = convert.globals.checkPubkey(keyVal); | ||
let reader; | ||
switch (keyVal.key[0]) { | ||
case GlobalTypes.UNSIGNED_TX: | ||
checkKeyBuffer('global', keyVal.key, GlobalTypes.UNSIGNED_TX); | ||
if (txCount > 0) { | ||
throw new Error('Format Error: GlobalMap has multiple UNSIGNED_TX'); | ||
} | ||
txCount++; | ||
break; | ||
case GlobalTypes.GLOBAL_XPUB: | ||
if (globalMap.globalXpub === undefined) { | ||
globalMap.globalXpub = []; | ||
} | ||
globalMap.globalXpub.push(convert.globals.globalXpub.decode(keyVal)); | ||
break; | ||
case GlobalTypes.GLOBAL_TX_VERSION: | ||
checkKeyBuffer('global', keyVal.key, GlobalTypes.GLOBAL_TX_VERSION); | ||
if (keyVal.value.length !== 4) | ||
throw Error("Value Error: Global transaction version is not 4 bytes"); | ||
globalMap.txVersion = keyVal.value.readUInt32LE(); | ||
break; | ||
case GlobalTypes.GLOBAL_FALLBACK_LOCKTIME: | ||
checkKeyBuffer('global', keyVal.key, GlobalTypes.GLOBAL_FALLBACK_LOCKTIME); | ||
if (keyVal.value.length !== 4) | ||
throw Error("Value Error: Global fallback locktime is not 4 bytes"); | ||
globalMap.fallbackLocktime = keyVal.value.readUInt32LE(); | ||
break; | ||
case GlobalTypes.GLOBAL_INPUT_COUNT: | ||
checkKeyBuffer('global', keyVal.key, GlobalTypes.GLOBAL_INPUT_COUNT); | ||
reader = new bufferutils_1.BufferReader(keyVal.value); | ||
reader.readVarInt(); // Value length, we can ignore this | ||
inputCount = reader.readVarInt(); | ||
break; | ||
case GlobalTypes.GLOBAL_OUTPUT_COUNT: | ||
checkKeyBuffer('global', keyVal.key, GlobalTypes.GLOBAL_OUTPUT_COUNT); | ||
reader = new bufferutils_1.BufferReader(keyVal.value); | ||
reader.readVarInt(); // Value length, we can ignore this | ||
outputCount = reader.readVarInt(); | ||
break; | ||
case GlobalTypes.GLOBAL_TXMODIFIABLE: | ||
checkKeyBuffer('global', keyVal.key, GlobalTypes.GLOBAL_TXMODIFIABLE); | ||
if (keyVal.value.length !== 1) | ||
throw Error("Value Error: Global tx modifiable flags is not 1 bytes"); | ||
globalMap.txModifiable = (keyVal.value[0] & 1) === 1; | ||
break; | ||
case GlobalTypes.GLOBAL_VERSION: | ||
checkKeyBuffer('global', keyVal.key, GlobalTypes.GLOBAL_VERSION); | ||
if (keyVal.value.length !== 4) | ||
throw Error("Value Error: Global PSBT version is not 4 bytes"); | ||
globalMap.version = keyVal.value.readUInt32LE(); | ||
break; | ||
default: | ||
// This will allow inclusion during serialization. | ||
if (!globalMap.unknownKeyVals) | ||
globalMap.unknownKeyVals = []; | ||
globalMap.unknownKeyVals.push(keyVal); | ||
} | ||
} | ||
// Get input and output counts to loop the respective fields | ||
inputCount = inputCount !== null && inputCount !== void 0 ? inputCount : inputKeyVals.length; | ||
outputCount = outputCount !== null && outputCount !== void 0 ? outputCount : outputKeyVals.length; | ||
const inputs = []; | ||
const outputs = []; | ||
// Get input fields | ||
for (let index = 0; index < inputCount; index++) { | ||
const input = { | ||
tapScriptSigs: {}, | ||
tapScripts: {}, | ||
tapBip32Paths: {} | ||
}; | ||
for (const keyVal of inputKeyVals[index]) { | ||
convert.inputs.checkPubkey(keyVal); | ||
switch (keyVal.key[0]) { | ||
case InputTypes.NON_WITNESS_UTXO: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.NON_WITNESS_UTXO); | ||
if (input.nonWitnessUtxo !== undefined) { | ||
throw Error('Format Error: Input has multiple NON_WITNESS_UTXO'); | ||
} | ||
input.nonWitnessUtxo = convert.inputs.nonWitnessUtxo.decode(keyVal); | ||
break; | ||
case InputTypes.WITNESS_UTXO: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.WITNESS_UTXO); | ||
if (input.witnessUtxo !== undefined) { | ||
throw Error('Format Error: Input has multiple WITNESS_UTXO'); | ||
} | ||
input.witnessUtxo = convert.inputs.witnessUtxo.decode(keyVal); | ||
break; | ||
case InputTypes.PARTIAL_SIG: | ||
if (input.partialSig === undefined) | ||
input.partialSig = []; | ||
input.partialSig.push(convert.inputs.partialSig.decode(keyVal)); | ||
break; | ||
case InputTypes.SIGHASH_TYPE: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.SIGHASH_TYPE); | ||
if (input.sighashType !== undefined) { | ||
throw Error('Format Error: Input has multiple SIGHASH_TYPE'); | ||
} | ||
input.sighashType = convert.inputs.sighashType.decode(keyVal); | ||
break; | ||
case InputTypes.REDEEM_SCRIPT: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.REDEEM_SCRIPT); | ||
if (input.redeemScript !== undefined) { | ||
throw Error('Format Error: Input has multiple REDEEM_SCRIPT'); | ||
} | ||
input.redeemScript = convert.inputs.redeemScript.decode(keyVal); | ||
break; | ||
case InputTypes.WITNESS_SCRIPT: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.WITNESS_SCRIPT); | ||
if (input.witnessScript !== undefined) { | ||
throw Error('Format Error: Input has multiple WITNESS_SCRIPT'); | ||
} | ||
input.witnessScript = convert.inputs.witnessScript.decode(keyVal); | ||
break; | ||
case InputTypes.BIP32_DERIVATION: | ||
if (input.bip32Derivation === undefined) { | ||
input.bip32Derivation = []; | ||
} | ||
input.bip32Derivation.push(convert.inputs.bip32Derivation.decode(keyVal)); | ||
break; | ||
case InputTypes.FINAL_SCRIPTSIG: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.FINAL_SCRIPTSIG); | ||
input.finalScriptSig = convert.inputs.finalScriptSig.decode(keyVal); | ||
break; | ||
case InputTypes.FINAL_SCRIPTWITNESS: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.FINAL_SCRIPTWITNESS); | ||
input.finalScriptWitness = convert.inputs.finalScriptWitness.decode(keyVal); | ||
break; | ||
case InputTypes.POR_COMMITMENT: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.POR_COMMITMENT); | ||
input.porCommitment = convert.inputs.porCommitment.decode(keyVal); | ||
break; | ||
case InputTypes.PREVIOUS_TXID: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.PREVIOUS_TXID); | ||
if (keyVal.value.length !== 32) | ||
throw Error("Value Error: Previous txid is not 32 bytes"); | ||
input.prevTXID = keyVal.value.toString("hex"); | ||
break; | ||
case InputTypes.OUTPUT_INDEX: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.OUTPUT_INDEX); | ||
if (keyVal.value.length !== 4) | ||
throw Error("Value Error: Previous output index is not 4 bytes"); | ||
input.prevOutputIndex = keyVal.value[0]; | ||
break; | ||
case InputTypes.TAP_KEY_SIG: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.TAP_KEY_SIG); | ||
if (keyVal.value.length < 64) | ||
throw Error("Value Error: Input Taproot key path signature is shorter than 64 bytes"); | ||
if (keyVal.value.length > 65) | ||
throw Error("Value Error: Input Taproot key path signature is longer than 65 bytes"); | ||
input.tapKeySig = keyVal.value; | ||
break; | ||
case InputTypes.TAP_SCRIPT_SIG: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.TAP_SCRIPT_SIG); | ||
if (keyVal.key.length !== 65) | ||
throw Error("Format Error: Input Taproot script signature key is not 65 bytes"); | ||
if (keyVal.value.length < 64) | ||
throw Error("Value Error: Input Taproot script path signature is shorter than 64 bytes"); | ||
if (keyVal.value.length > 65) | ||
throw Error("Value Error: Input Taproot script path signature is longer than 65 bytes"); | ||
const scriptkey = keyVal.key.slice(1).toString("hex"); | ||
input.tapScriptSigs[scriptkey] = keyVal.value; | ||
break; | ||
case InputTypes.TAP_LEAF_SCRIPT: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.TAP_LEAF_SCRIPT); | ||
if (keyVal.key.length < 34) | ||
throw Error("Format Error: Input Taproot leaf script key is not at least 34 bytes"); | ||
if (keyVal.key.length % 32 !== 2) | ||
throw Error("Format Error: Input Taproot leaf script key's control block is not valid"); | ||
if (keyVal.value.length === 0) | ||
throw Error("Value Error: Intput Taproot leaf script cannot be empty"); | ||
const script = keyVal.value.slice(-1).toString("hex"); | ||
if (!input.tapScripts[script]) | ||
input.tapScripts[script] = new Set(); | ||
input.tapScripts[script].add(keyVal.key.slice(1).toString("hex")); | ||
break; | ||
case InputTypes.TAP_BIP32_DERIVATION: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.TAP_BIP32_DERIVATION); | ||
if (keyVal.key.length !== 33) | ||
throw Error("Format Error: Input Taproot BIP 32 keypath key is not 33 bytes"); | ||
const xonly = keyVal.key.slice(1).toString("hex"); | ||
const reader = new bufferutils_1.BufferReader(keyVal.value); | ||
const num_hashs = reader.readVarInt(); | ||
const leaf_hashes = new Set(); | ||
for (let i = 0; i < num_hashs; i++) | ||
leaf_hashes.add(reader.readSlice(32).toString("hex")); | ||
input.tapBip32Paths[xonly] = { | ||
leafHashs: leaf_hashes, | ||
Bip32Derivation: keyVal.value.slice(reader.offset) | ||
}; | ||
break; | ||
case InputTypes.TAP_INTERNAL_KEY: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.TAP_INTERNAL_KEY); | ||
if (keyVal.value.length !== 32) | ||
throw Error("Value Error: Input Taproot internal key is not 32 bytes"); | ||
input.tapInternalKey = keyVal.value; | ||
break; | ||
case InputTypes.TAP_MERKLE_ROOT: | ||
checkKeyBuffer('input', keyVal.key, InputTypes.TAP_MERKLE_ROOT); | ||
if (keyVal.value.length !== 32) | ||
throw Error("Value Error: Input Taproot merkle root is not 32 bytes"); | ||
input.tapMarkleRoot = keyVal.value.toString("hex"); | ||
break; | ||
default: | ||
// This will allow inclusion during serialization. | ||
if (!input.unknownKeyVals) | ||
input.unknownKeyVals = []; | ||
input.unknownKeyVals.push(keyVal); | ||
} | ||
} | ||
inputs.push(input); | ||
} | ||
for (let index = 0; index < outputCount; index++) { | ||
const output = { | ||
tapBip32Paths: {} | ||
}; | ||
for (const keyVal of outputKeyVals[index]) { | ||
convert.outputs.checkPubkey(keyVal); | ||
let reader; | ||
switch (keyVal.key[0]) { | ||
case OutputTypes.REDEEM_SCRIPT: | ||
checkKeyBuffer('output', keyVal.key, OutputTypes.REDEEM_SCRIPT); | ||
if (output.redeemScript !== undefined) { | ||
throw Error('Format Error: Output has multiple REDEEM_SCRIPT'); | ||
} | ||
output.redeemScript = convert.outputs.redeemScript.decode(keyVal); | ||
break; | ||
case OutputTypes.WITNESS_SCRIPT: | ||
checkKeyBuffer('output', keyVal.key, OutputTypes.WITNESS_SCRIPT); | ||
if (output.witnessScript !== undefined) { | ||
throw Error('Format Error: Output has multiple WITNESS_SCRIPT'); | ||
} | ||
output.witnessScript = convert.outputs.witnessScript.decode(keyVal); | ||
break; | ||
case OutputTypes.BIP32_DERIVATION: | ||
if (output.bip32Derivation === undefined) | ||
output.bip32Derivation = []; | ||
output.bip32Derivation.push(convert.outputs.bip32Derivation.decode(keyVal)); | ||
break; | ||
case OutputTypes.AMOUNT: | ||
checkKeyBuffer('output', keyVal.key, OutputTypes.AMOUNT); | ||
if (keyVal.value.length !== 8) | ||
throw Error("Value Error: Output amount is not 8 bytes"); | ||
reader = new bufferutils_1.BufferReader(keyVal.value); | ||
output.amount = reader.readUInt64(); | ||
break; | ||
case OutputTypes.SCRIPT: | ||
checkKeyBuffer('output', keyVal.key, OutputTypes.SCRIPT); | ||
output.script = keyVal.value; | ||
break; | ||
case OutputTypes.TAP_INTERNAL_KEY: | ||
checkKeyBuffer('output', keyVal.key, OutputTypes.TAP_INTERNAL_KEY); | ||
if (keyVal.value.length !== 32) | ||
throw Error("Value Error: Output Taproot internal key is not 32 bytes"); | ||
output.tapInternalKey = keyVal.value; | ||
break; | ||
case OutputTypes.TAP_TREE: | ||
checkKeyBuffer('output', keyVal.key, OutputTypes.TAP_TREE); | ||
output.tapTree = keyVal.value; | ||
break; | ||
case OutputTypes.TAP_BIP32_DERIVATION: | ||
checkKeyBuffer('output', keyVal.key, OutputTypes.TAP_BIP32_DERIVATION); | ||
if (keyVal.key.length !== 33) | ||
throw Error("Output Taproot BIP 32 keypath key is not 33 bytes"); | ||
const xonly = keyVal.key.slice(1).toString("hex"); | ||
const leafHashs = new Set(); | ||
reader = new bufferutils_1.BufferReader(keyVal.value); | ||
const num_hashs = reader.readVarInt(); | ||
for (let i = 0; i < num_hashs; i++) | ||
leafHashs.add(reader.readSlice(32).toString("hex")); | ||
output.tapBip32Paths[xonly] = { leafHashs, Bip32Derivation: keyVal.value.slice(reader.offset) }; | ||
break; | ||
default: | ||
if (!output.unknownKeyVals) | ||
output.unknownKeyVals = []; | ||
output.unknownKeyVals.push(keyVal); | ||
} | ||
} | ||
outputs.push(output); | ||
} | ||
return { globalMap, inputs, outputs }; | ||
} | ||
function checkKeyBuffer(type, keyBuf, keyNum) { | ||
if (!keyBuf.equals(Buffer.from([keyNum]))) { | ||
throw Error(`Format Error: Invalid ${type} key: ${keyBuf.toString('hex')}`); | ||
} | ||
} | ||
var GlobalTypes; | ||
(function (GlobalTypes) { | ||
GlobalTypes[GlobalTypes["UNSIGNED_TX"] = 0] = "UNSIGNED_TX"; | ||
GlobalTypes[GlobalTypes["GLOBAL_XPUB"] = 1] = "GLOBAL_XPUB"; | ||
GlobalTypes[GlobalTypes["GLOBAL_TX_VERSION"] = 2] = "GLOBAL_TX_VERSION"; | ||
GlobalTypes[GlobalTypes["GLOBAL_FALLBACK_LOCKTIME"] = 3] = "GLOBAL_FALLBACK_LOCKTIME"; | ||
GlobalTypes[GlobalTypes["GLOBAL_INPUT_COUNT"] = 4] = "GLOBAL_INPUT_COUNT"; | ||
GlobalTypes[GlobalTypes["GLOBAL_OUTPUT_COUNT"] = 5] = "GLOBAL_OUTPUT_COUNT"; | ||
GlobalTypes[GlobalTypes["GLOBAL_TXMODIFIABLE"] = 6] = "GLOBAL_TXMODIFIABLE"; | ||
GlobalTypes[GlobalTypes["GLOBAL_VERSION"] = 251] = "GLOBAL_VERSION"; | ||
})(GlobalTypes || (GlobalTypes = {})); | ||
var InputTypes; | ||
(function (InputTypes) { | ||
InputTypes[InputTypes["NON_WITNESS_UTXO"] = 0] = "NON_WITNESS_UTXO"; | ||
InputTypes[InputTypes["WITNESS_UTXO"] = 1] = "WITNESS_UTXO"; | ||
InputTypes[InputTypes["PARTIAL_SIG"] = 2] = "PARTIAL_SIG"; | ||
InputTypes[InputTypes["SIGHASH_TYPE"] = 3] = "SIGHASH_TYPE"; | ||
InputTypes[InputTypes["REDEEM_SCRIPT"] = 4] = "REDEEM_SCRIPT"; | ||
InputTypes[InputTypes["WITNESS_SCRIPT"] = 5] = "WITNESS_SCRIPT"; | ||
InputTypes[InputTypes["BIP32_DERIVATION"] = 6] = "BIP32_DERIVATION"; | ||
InputTypes[InputTypes["FINAL_SCRIPTSIG"] = 7] = "FINAL_SCRIPTSIG"; | ||
InputTypes[InputTypes["FINAL_SCRIPTWITNESS"] = 8] = "FINAL_SCRIPTWITNESS"; | ||
InputTypes[InputTypes["POR_COMMITMENT"] = 9] = "POR_COMMITMENT"; | ||
InputTypes[InputTypes["PREVIOUS_TXID"] = 14] = "PREVIOUS_TXID"; | ||
InputTypes[InputTypes["OUTPUT_INDEX"] = 15] = "OUTPUT_INDEX"; | ||
InputTypes[InputTypes["SEQUENCE"] = 16] = "SEQUENCE"; | ||
InputTypes[InputTypes["REQUIRED_TIME_LOCKTIME"] = 17] = "REQUIRED_TIME_LOCKTIME"; | ||
InputTypes[InputTypes["REQUIRED_HEIGHT_LOCKTIME"] = 18] = "REQUIRED_HEIGHT_LOCKTIME"; | ||
InputTypes[InputTypes["TAP_KEY_SIG"] = 19] = "TAP_KEY_SIG"; | ||
InputTypes[InputTypes["TAP_SCRIPT_SIG"] = 20] = "TAP_SCRIPT_SIG"; | ||
InputTypes[InputTypes["TAP_LEAF_SCRIPT"] = 21] = "TAP_LEAF_SCRIPT"; | ||
InputTypes[InputTypes["TAP_BIP32_DERIVATION"] = 22] = "TAP_BIP32_DERIVATION"; | ||
InputTypes[InputTypes["TAP_INTERNAL_KEY"] = 23] = "TAP_INTERNAL_KEY"; | ||
InputTypes[InputTypes["TAP_MERKLE_ROOT"] = 24] = "TAP_MERKLE_ROOT"; | ||
})(InputTypes || (InputTypes = {})); | ||
var OutputTypes; | ||
(function (OutputTypes) { | ||
OutputTypes[OutputTypes["REDEEM_SCRIPT"] = 0] = "REDEEM_SCRIPT"; | ||
OutputTypes[OutputTypes["WITNESS_SCRIPT"] = 1] = "WITNESS_SCRIPT"; | ||
OutputTypes[OutputTypes["BIP32_DERIVATION"] = 2] = "BIP32_DERIVATION"; | ||
OutputTypes[OutputTypes["AMOUNT"] = 3] = "AMOUNT"; | ||
OutputTypes[OutputTypes["SCRIPT"] = 4] = "SCRIPT"; | ||
OutputTypes[OutputTypes["TAP_INTERNAL_KEY"] = 5] = "TAP_INTERNAL_KEY"; | ||
OutputTypes[OutputTypes["TAP_TREE"] = 6] = "TAP_TREE"; | ||
OutputTypes[OutputTypes["TAP_BIP32_DERIVATION"] = 7] = "TAP_BIP32_DERIVATION"; | ||
})(OutputTypes || (OutputTypes = {})); | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Psbtv2=void 0;const e=require("bip174"),r=require("bip174/src/lib/converter"),t=require("./bufferutils");class o extends e.Psbt{static fromBuffer(e,o){const E=function(e,o){if(1886610036!==e.readUInt32BE())throw Error("Format Error: Invalid Magic Number");if(255!==e.readUInt8(4))throw Error("Format Error: Magic Number must be followed by 0xff separator");const E=new t.BufferReader(e);E.offset+=5;const u=()=>({key:E.readVarSlice(),value:E.readVarSlice()}),I=()=>{if(E.offset>=e.length)throw Error("Format Error: Unexpected End of PSBT");const r=0===e.readUInt8(E.offset);return r&&(E.offset+=1),r},T=[],l={};for(;!I();){const e=u(),r=e.key.toString("hex");if(l[r])throw Error("Format Error: Keys must be unique for global keymap: key "+r);l[r]=1,T.push(e)}const p=T.filter((e=>e.key[0]===i.UNSIGNED_TX));if(1!==p.length)throw Error("Format Error: Only one UNSIGNED_TX allowed");const _=o(p[0].value),{inputCount:S,outputCount:c}=_.getInputOutputCounts(),P=[],O=[];for(let e=0;e<S;e++){const r={},t=[];for(;!I();){const o=u(),a=o.key.toString("hex");if(r[a])throw Error(`Format Error: Keys must be unique, got "${a}" from input#${e}`);r[a]=1,t.push(o)}P.push(t)}for(let e=0;e<c;e++){const r={},t=[];for(;!I();){const o=u(),a=o.key.toString("hex");if(r[a])throw Error(`Format Error: Keys must be unique, got "${a}" from output#${e}`);r[a]=1,t.push(o)}O.push(t)}return function(e,{globalMapKeyVals:o,inputKeyVals:E,outputKeyVals:u}){const I={unsignedTx:e};let T,l,p=0;for(const e of o){let o;switch(e.key[0]){case i.UNSIGNED_TX:if(a("global",e.key,i.UNSIGNED_TX),p>0)throw new Error("Format Error: GlobalMap has multiple UNSIGNED_TX");p++;break;case i.GLOBAL_XPUB:void 0===I.globalXpub&&(I.globalXpub=[]),I.globalXpub.push(r.globals.globalXpub.decode(e));break;case i.GLOBAL_TX_VERSION:if(a("global",e.key,i.GLOBAL_TX_VERSION),4!==e.value.length)throw Error("Value Error: Global transaction version is not 4 bytes");I.txVersion=e.value.readUInt32LE();break;case i.GLOBAL_FALLBACK_LOCKTIME:if(a("global",e.key,i.GLOBAL_FALLBACK_LOCKTIME),4!==e.value.length)throw Error("Value Error: Global fallback locktime is not 4 bytes");I.fallbackLocktime=e.value.readUInt32LE();break;case i.GLOBAL_INPUT_COUNT:a("global",e.key,i.GLOBAL_INPUT_COUNT),o=new t.BufferReader(e.value),o.readVarInt(),T=o.readVarInt();break;case i.GLOBAL_OUTPUT_COUNT:a("global",e.key,i.GLOBAL_OUTPUT_COUNT),o=new t.BufferReader(e.value),o.readVarInt(),l=o.readVarInt();break;case i.GLOBAL_TXMODIFIABLE:if(a("global",e.key,i.GLOBAL_TXMODIFIABLE),1!==e.value.length)throw Error("Value Error: Global tx modifiable flags is not 1 bytes");I.txModifiable=1==(1&e.value[0]);break;case i.GLOBAL_VERSION:if(a("global",e.key,i.GLOBAL_VERSION),4!==e.value.length)throw Error("Value Error: Global PSBT version is not 4 bytes");I.version=e.value.readUInt32LE();break;default:I.unknownKeyVals||(I.unknownKeyVals=[]),I.unknownKeyVals.push(e)}}T=null!=T?T:E.length,l=null!=l?l:u.length;const _=[],S=[];for(let e=0;e<T;e++){const o={tapScriptSigs:{},tapScripts:{},tapBip32Paths:{}};for(const i of E[e])switch(r.inputs.checkPubkey(i),i.key[0]){case n.NON_WITNESS_UTXO:if(a("input",i.key,n.NON_WITNESS_UTXO),void 0!==o.nonWitnessUtxo)throw Error("Format Error: Input has multiple NON_WITNESS_UTXO");o.nonWitnessUtxo=r.inputs.nonWitnessUtxo.decode(i);break;case n.WITNESS_UTXO:if(a("input",i.key,n.WITNESS_UTXO),void 0!==o.witnessUtxo)throw Error("Format Error: Input has multiple WITNESS_UTXO");o.witnessUtxo=r.inputs.witnessUtxo.decode(i);break;case n.PARTIAL_SIG:void 0===o.partialSig&&(o.partialSig=[]),o.partialSig.push(r.inputs.partialSig.decode(i));break;case n.SIGHASH_TYPE:if(a("input",i.key,n.SIGHASH_TYPE),void 0!==o.sighashType)throw Error("Format Error: Input has multiple SIGHASH_TYPE");o.sighashType=r.inputs.sighashType.decode(i);break;case n.REDEEM_SCRIPT:if(a("input",i.key,n.REDEEM_SCRIPT),void 0!==o.redeemScript)throw Error("Format Error: Input has multiple REDEEM_SCRIPT");o.redeemScript=r.inputs.redeemScript.decode(i);break;case n.WITNESS_SCRIPT:if(a("input",i.key,n.WITNESS_SCRIPT),void 0!==o.witnessScript)throw Error("Format Error: Input has multiple WITNESS_SCRIPT");o.witnessScript=r.inputs.witnessScript.decode(i);break;case n.BIP32_DERIVATION:void 0===o.bip32Derivation&&(o.bip32Derivation=[]),o.bip32Derivation.push(r.inputs.bip32Derivation.decode(i));break;case n.FINAL_SCRIPTSIG:a("input",i.key,n.FINAL_SCRIPTSIG),o.finalScriptSig=r.inputs.finalScriptSig.decode(i);break;case n.FINAL_SCRIPTWITNESS:a("input",i.key,n.FINAL_SCRIPTWITNESS),o.finalScriptWitness=r.inputs.finalScriptWitness.decode(i);break;case n.POR_COMMITMENT:a("input",i.key,n.POR_COMMITMENT),o.porCommitment=r.inputs.porCommitment.decode(i);break;case n.PREVIOUS_TXID:if(a("input",i.key,n.PREVIOUS_TXID),32!==i.value.length)throw Error("Value Error: Previous txid is not 32 bytes");o.prevTXID=i.value.toString("hex");break;case n.OUTPUT_INDEX:if(a("input",i.key,n.OUTPUT_INDEX),4!==i.value.length)throw Error("Value Error: Previous output index is not 4 bytes");o.prevOutputIndex=i.value[0];break;case n.TAP_KEY_SIG:if(a("input",i.key,n.TAP_KEY_SIG),i.value.length<64)throw Error("Value Error: Input Taproot key path signature is shorter than 64 bytes");if(i.value.length>65)throw Error("Value Error: Input Taproot key path signature is longer than 65 bytes");o.tapKeySig=i.value;break;case n.TAP_SCRIPT_SIG:if(a("input",i.key,n.TAP_SCRIPT_SIG),65!==i.key.length)throw Error("Format Error: Input Taproot script signature key is not 65 bytes");if(i.value.length<64)throw Error("Value Error: Input Taproot script path signature is shorter than 64 bytes");if(i.value.length>65)throw Error("Value Error: Input Taproot script path signature is longer than 65 bytes");const e=i.key.slice(1).toString("hex");o.tapScriptSigs[e]=i.value;break;case n.TAP_LEAF_SCRIPT:if(a("input",i.key,n.TAP_LEAF_SCRIPT),i.key.length<34)throw Error("Format Error: Input Taproot leaf script key is not at least 34 bytes");if(i.key.length%32!=2)throw Error("Format Error: Input Taproot leaf script key's control block is not valid");if(0===i.value.length)throw Error("Value Error: Intput Taproot leaf script cannot be empty");const s=i.value.slice(-1).toString("hex");o.tapScripts[s]||(o.tapScripts[s]=new Set),o.tapScripts[s].add(i.key.slice(1).toString("hex"));break;case n.TAP_BIP32_DERIVATION:if(a("input",i.key,n.TAP_BIP32_DERIVATION),33!==i.key.length)throw Error("Format Error: Input Taproot BIP 32 keypath key is not 33 bytes");const E=i.key.slice(1).toString("hex"),u=new t.BufferReader(i.value),I=u.readVarInt(),T=new Set;for(let e=0;e<I;e++)T.add(u.readSlice(32).toString("hex"));o.tapBip32Paths[E]={leafHashs:T,Bip32Derivation:i.value.slice(u.offset)};break;case n.TAP_INTERNAL_KEY:if(a("input",i.key,n.TAP_INTERNAL_KEY),32!==i.value.length)throw Error("Value Error: Input Taproot internal key is not 32 bytes");o.tapInternalKey=i.value;break;case n.TAP_MERKLE_ROOT:if(a("input",i.key,n.TAP_MERKLE_ROOT),32!==i.value.length)throw Error("Value Error: Input Taproot merkle root is not 32 bytes");o.tapMarkleRoot=i.value.toString("hex");break;default:o.unknownKeyVals||(o.unknownKeyVals=[]),o.unknownKeyVals.push(i)}_.push(o)}for(let e=0;e<l;e++){const o={tapBip32Paths:{}};for(const i of u[e]){let e;switch(r.outputs.checkPubkey(i),i.key[0]){case s.REDEEM_SCRIPT:if(a("output",i.key,s.REDEEM_SCRIPT),void 0!==o.redeemScript)throw Error("Format Error: Output has multiple REDEEM_SCRIPT");o.redeemScript=r.outputs.redeemScript.decode(i);break;case s.WITNESS_SCRIPT:if(a("output",i.key,s.WITNESS_SCRIPT),void 0!==o.witnessScript)throw Error("Format Error: Output has multiple WITNESS_SCRIPT");o.witnessScript=r.outputs.witnessScript.decode(i);break;case s.BIP32_DERIVATION:void 0===o.bip32Derivation&&(o.bip32Derivation=[]),o.bip32Derivation.push(r.outputs.bip32Derivation.decode(i));break;case s.AMOUNT:if(a("output",i.key,s.AMOUNT),8!==i.value.length)throw Error("Value Error: Output amount is not 8 bytes");e=new t.BufferReader(i.value),o.amount=e.readUInt64();break;case s.SCRIPT:a("output",i.key,s.SCRIPT),o.script=i.value;break;case s.TAP_INTERNAL_KEY:if(a("output",i.key,s.TAP_INTERNAL_KEY),32!==i.value.length)throw Error("Value Error: Output Taproot internal key is not 32 bytes");o.tapInternalKey=i.value;break;case s.TAP_TREE:a("output",i.key,s.TAP_TREE),o.tapTree=i.value;break;case s.TAP_BIP32_DERIVATION:if(a("output",i.key,s.TAP_BIP32_DERIVATION),33!==i.key.length)throw Error("Output Taproot BIP 32 keypath key is not 33 bytes");const n=i.key.slice(1).toString("hex"),E=new Set;e=new t.BufferReader(i.value);const u=e.readVarInt();for(let r=0;r<u;r++)E.add(e.readSlice(32).toString("hex"));o.tapBip32Paths[n]={leafHashs:E,Bip32Derivation:i.value.slice(e.offset)};break;default:o.unknownKeyVals||(o.unknownKeyVals=[]),o.unknownKeyVals.push(i)}}S.push(o)}return{globalMap:I,inputs:_,outputs:S}}(_,{globalMapKeyVals:T,inputKeyVals:P,outputKeyVals:O})}(e,o),u=new this(E.globalMap.unsignedTx);return Object.assign(u,E),u}}function a(e,r,t){if(!r.equals(Buffer.from([t])))throw Error(`Format Error: Invalid ${e} key: ${r.toString("hex")}`)}var i,n,s;exports.Psbtv2=o,function(e){e[e.UNSIGNED_TX=0]="UNSIGNED_TX",e[e.GLOBAL_XPUB=1]="GLOBAL_XPUB",e[e.GLOBAL_TX_VERSION=2]="GLOBAL_TX_VERSION",e[e.GLOBAL_FALLBACK_LOCKTIME=3]="GLOBAL_FALLBACK_LOCKTIME",e[e.GLOBAL_INPUT_COUNT=4]="GLOBAL_INPUT_COUNT",e[e.GLOBAL_OUTPUT_COUNT=5]="GLOBAL_OUTPUT_COUNT",e[e.GLOBAL_TXMODIFIABLE=6]="GLOBAL_TXMODIFIABLE",e[e.GLOBAL_VERSION=251]="GLOBAL_VERSION"}(i||(i={})),function(e){e[e.NON_WITNESS_UTXO=0]="NON_WITNESS_UTXO",e[e.WITNESS_UTXO=1]="WITNESS_UTXO",e[e.PARTIAL_SIG=2]="PARTIAL_SIG",e[e.SIGHASH_TYPE=3]="SIGHASH_TYPE",e[e.REDEEM_SCRIPT=4]="REDEEM_SCRIPT",e[e.WITNESS_SCRIPT=5]="WITNESS_SCRIPT",e[e.BIP32_DERIVATION=6]="BIP32_DERIVATION",e[e.FINAL_SCRIPTSIG=7]="FINAL_SCRIPTSIG",e[e.FINAL_SCRIPTWITNESS=8]="FINAL_SCRIPTWITNESS",e[e.POR_COMMITMENT=9]="POR_COMMITMENT",e[e.PREVIOUS_TXID=14]="PREVIOUS_TXID",e[e.OUTPUT_INDEX=15]="OUTPUT_INDEX",e[e.SEQUENCE=16]="SEQUENCE",e[e.REQUIRED_TIME_LOCKTIME=17]="REQUIRED_TIME_LOCKTIME",e[e.REQUIRED_HEIGHT_LOCKTIME=18]="REQUIRED_HEIGHT_LOCKTIME",e[e.TAP_KEY_SIG=19]="TAP_KEY_SIG",e[e.TAP_SCRIPT_SIG=20]="TAP_SCRIPT_SIG",e[e.TAP_LEAF_SCRIPT=21]="TAP_LEAF_SCRIPT",e[e.TAP_BIP32_DERIVATION=22]="TAP_BIP32_DERIVATION",e[e.TAP_INTERNAL_KEY=23]="TAP_INTERNAL_KEY",e[e.TAP_MERKLE_ROOT=24]="TAP_MERKLE_ROOT"}(n||(n={})),function(e){e[e.REDEEM_SCRIPT=0]="REDEEM_SCRIPT",e[e.WITNESS_SCRIPT=1]="WITNESS_SCRIPT",e[e.BIP32_DERIVATION=2]="BIP32_DERIVATION",e[e.AMOUNT=3]="AMOUNT",e[e.SCRIPT=4]="SCRIPT",e[e.TAP_INTERNAL_KEY=5]="TAP_INTERNAL_KEY",e[e.TAP_TREE=6]="TAP_TREE",e[e.TAP_BIP32_DERIVATION=7]="TAP_BIP32_DERIVATION"}(s||(s={})); |
@@ -1,74 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.CoinType = exports.PaymentBCH = void 0; | ||
const cashaddr = require('cashaddrjs'); | ||
const payment_1 = require("./payment"); | ||
Object.defineProperty(exports, "CoinType", { enumerable: true, get: function () { return payment_1.CoinType; } }); | ||
const interface_1 = require("./interface"); | ||
class PaymentBCH extends payment_1.PaymentBTC { | ||
static CoinSupported(coin) { | ||
if (coin !== payment_1.CoinType.BITCOINCASH) | ||
throw Error('Not supported cointype'); | ||
} | ||
/** | ||
* Pay to Public Key Hash for BITCOINCASH | ||
* @param {CoinType} coin | ||
* @param {Buffer} param1 [publickey | hashed publickey] | ||
* @returns | ||
*/ | ||
static p2pkh(coin, opt) { | ||
this.CoinSupported(coin); | ||
if (!opt.publickey && !opt.hash) | ||
throw Error('Invalid Parameters'); | ||
if (opt.publickey && opt.hash) | ||
throw Error('Invalid Parameters'); | ||
//@ts-ignore | ||
const pkHash = (opt.hash) ? opt.hash : (0, payment_1.Hash160)(opt.publickey); | ||
payment_1.logger === null || payment_1.logger === void 0 ? void 0 : payment_1.logger.info(`publickey hash: ${pkHash.toString('hex')}`); | ||
// FIXME: no fixed params | ||
let address = cashaddr.encode('bitcoincash', 'P2PKH', pkHash); | ||
address = address.split(':')[1]; | ||
const op = Buffer.from([interface_1.OPCODES.OP_DUP, interface_1.OPCODES.OP_HASH160, 0x14]); | ||
const check = Buffer.from([interface_1.OPCODES.OP_EQUALVERIFY, interface_1.OPCODES.OP_CHECKSIG]); | ||
const scriptPublickey = Buffer.concat([op, pkHash, check]); | ||
const redeemHash = (0, payment_1.Hash160)(scriptPublickey); | ||
payment_1.logger === null || payment_1.logger === void 0 ? void 0 : payment_1.logger.info(`redeem hash: ${redeemHash.toString('hex')}`); | ||
return { address, scriptPublickey, redeemHash }; | ||
} | ||
/** | ||
* Pay to Script Hash for BITCOINCASH | ||
* @param {CoinType} coin | ||
* @param {Buffer} redeemHash | ||
* @returns | ||
*/ | ||
static p2sh(coin, redeemHash) { | ||
this.CoinSupported(coin); | ||
let address = cashaddr.encode('bitcoincash', 'P2SH', redeemHash); | ||
address = address.split(':')[1]; | ||
const op = Buffer.from([interface_1.OPCODES.OP_HASH160, 0x14]); | ||
const check = Buffer.from([interface_1.OPCODES.OP_EQUAL]); | ||
const scriptPublickey = Buffer.concat([op, redeemHash, check]); | ||
return { address, scriptPublickey }; | ||
} | ||
/** | ||
* decode address to script | ||
* @param {string} address | ||
*/ | ||
static decode(coin, address) { | ||
if (address.startsWith('1')) { | ||
const hash160 = this.bs58check.decode(address); | ||
const hash = Buffer.from(hash160.slice(1)); | ||
return PaymentBCH.p2pkh(coin, { hash }).scriptPublickey; | ||
} | ||
else { | ||
address = (CheckPrefix(address)) ? address : `bitcoincash:${address}`; | ||
const { hash } = cashaddr.decode(address); | ||
return PaymentBCH.p2pkh(coin, { hash: Buffer.from(hash) }).scriptPublickey; | ||
} | ||
} | ||
} | ||
exports.PaymentBCH = PaymentBCH; | ||
function CheckPrefix(address) { | ||
const regexp = /^(?:bitcoincash|bchtest):q.+/; | ||
return regexp.test(address); | ||
} | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.CoinType=exports.PaymentBCH=void 0;const e=require("cashaddrjs"),r=require("./payment");Object.defineProperty(exports,"CoinType",{enumerable:!0,get:function(){return r.CoinType}});const t=require("./interface");class o extends r.PaymentBTC{static CoinSupported(e){if(e!==r.CoinType.BITCOINCASH)throw Error("Not supported cointype")}static p2pkh(o,s){if(this.CoinSupported(o),!s.publickey&&!s.hash)throw Error("Invalid Parameters");if(s.publickey&&s.hash)throw Error("Invalid Parameters");const i=s.hash?s.hash:(0,r.Hash160)(s.publickey);null===r.logger||void 0===r.logger||r.logger.info(`publickey hash: ${i.toString("hex")}`);let c=e.encode("bitcoincash","P2PKH",i);c=c.split(":")[1];const n=Buffer.from([t.OPCODES.OP_DUP,t.OPCODES.OP_HASH160,20]),h=Buffer.from([t.OPCODES.OP_EQUALVERIFY,t.OPCODES.OP_CHECKSIG]),a=Buffer.concat([n,i,h]),p=(0,r.Hash160)(a);return null===r.logger||void 0===r.logger||r.logger.info(`redeem hash: ${p.toString("hex")}`),{address:c,scriptPublickey:a,redeemHash:p}}static p2sh(r,o){this.CoinSupported(r);let s=e.encode("bitcoincash","P2SH",o);s=s.split(":")[1];const i=Buffer.from([t.OPCODES.OP_HASH160,20]),c=Buffer.from([t.OPCODES.OP_EQUAL]);return{address:s,scriptPublickey:Buffer.concat([i,o,c])}}static decode(r,t){if(t.startsWith("1")){const e=this.bs58check.decode(t),s=Buffer.from(e.slice(1));return o.p2pkh(r,{hash:s}).scriptPublickey}{t=function(e){return/^(?:bitcoincash|bchtest):q.+/.test(e)}(t)?t:`bitcoincash:${t}`;const{hash:s,type:i}=e.decode(t);return"P2SH"===i?o.p2sh(r,Buffer.from(s)).scriptPublickey:o.p2pkh(r,{hash:Buffer.from(s)}).scriptPublickey}}}exports.PaymentBCH=o; |
@@ -1,18 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.CoinType = exports.PaymentGRS = void 0; | ||
const payment_1 = require("./payment"); | ||
Object.defineProperty(exports, "CoinType", { enumerable: true, get: function () { return payment_1.CoinType; } }); | ||
const bs58_1 = require("@secux/utility/lib/bs58"); | ||
const groestl = require("groestl-hash-js"); | ||
class PaymentGRS extends payment_1.PaymentBTC { | ||
static CoinSupported(coin) { | ||
if (coin !== payment_1.CoinType.GROESTL) | ||
throw Error('Not supported cointype'); | ||
} | ||
} | ||
exports.PaymentGRS = PaymentGRS; | ||
PaymentGRS.bs58check = new bs58_1.bs58Check(hash); | ||
function hash(data) { | ||
return Buffer.from(groestl.groestl_2(data, 1, 1)); | ||
} | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.CoinType=exports.PaymentGRS=void 0;const e=require("./payment");Object.defineProperty(exports,"CoinType",{enumerable:!0,get:function(){return e.CoinType}});const t=require("@secux/utility/lib/bs58"),r=require("groestl-hash-js");class o extends e.PaymentBTC{static CoinSupported(t){if(t!==e.CoinType.GROESTL)throw Error("Not supported cointype")}}exports.PaymentGRS=o,o.bs58check=new t.bs58Check((function(e){return Buffer.from(r.groestl_2(e,1,1))})); |
@@ -1,232 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.logger = exports.Hash160 = exports.CoinType = exports.PaymentBTC = void 0; | ||
const bech32_1 = require("bech32"); | ||
const hash_js_1 = require("hash.js"); | ||
const interface_1 = require("./interface"); | ||
Object.defineProperty(exports, "CoinType", { enumerable: true, get: function () { return interface_1.CoinType; } }); | ||
const bs58_1 = require("@secux/utility/lib/bs58"); | ||
const utility_1 = require("@secux/utility"); | ||
const utils_1 = require("./utils"); | ||
exports.logger = utility_1.Logger === null || utility_1.Logger === void 0 ? void 0 : utility_1.Logger.child({ id: "payment" }); | ||
const SEGWIT_VERSION_DIFF = 0x50; | ||
class PaymentBTC { | ||
static CoinSupported(coin) { | ||
if (coin === interface_1.CoinType.BITCOINCASH) | ||
throw Error('Please use class PaymentBCH instead'); | ||
if (coin === interface_1.CoinType.GROESTL) | ||
throw Error('Please use class PaymentGRS instead'); | ||
} | ||
/** | ||
* Pay to Public Key Hash for BTC compatible coin | ||
* @param {CoinType} coin | ||
* @param {Buffer} param1 [publickey | hashed publickey] | ||
* @returns | ||
*/ | ||
static p2pkh(coin, opt) { | ||
this.CoinSupported(coin); | ||
if (!opt.publickey && !opt.hash) | ||
throw Error('Invalid Parameters'); | ||
if (opt.publickey && opt.hash) | ||
throw Error('Invalid Parameters'); | ||
//@ts-ignore | ||
const pkHash = (opt.hash) ? opt.hash : Hash160(opt.publickey); | ||
exports.logger === null || exports.logger === void 0 ? void 0 : exports.logger.info(`publickey hash: ${pkHash.toString('hex')}`); | ||
const network = interface_1.coinmap[coin]; | ||
const address = this.bs58check.encode(pkHash, Buffer.from([network.pubKeyHash])); | ||
const op = Buffer.from([interface_1.OPCODES.OP_DUP, interface_1.OPCODES.OP_HASH160, 0x14]); | ||
const check = Buffer.from([interface_1.OPCODES.OP_EQUALVERIFY, interface_1.OPCODES.OP_CHECKSIG]); | ||
const scriptPublickey = Buffer.concat([op, pkHash, check]); | ||
const redeemHash = Hash160(scriptPublickey); | ||
exports.logger === null || exports.logger === void 0 ? void 0 : exports.logger.info(`redeem hash: ${redeemHash.toString('hex')}`); | ||
return { address, scriptPublickey, redeemHash }; | ||
} | ||
/** | ||
* Pay to Script Hash for BTC compatible coin | ||
* @param {CoinType} coin | ||
* @param {Buffer} redeemHash | ||
* @returns | ||
*/ | ||
static p2sh(coin, redeemHash) { | ||
this.CoinSupported(coin); | ||
const network = interface_1.coinmap[coin]; | ||
const address = this.bs58check.encode(redeemHash, Buffer.from([network.scriptHash])); | ||
const op = Buffer.from([interface_1.OPCODES.OP_HASH160, 0x14]); | ||
const check = Buffer.from([interface_1.OPCODES.OP_EQUAL]); | ||
const scriptPublickey = Buffer.concat([op, redeemHash, check]); | ||
return { address, scriptPublickey }; | ||
} | ||
/** | ||
* Pay to Witness Public Key Hash | ||
* @param {CoinType} coin | ||
* @param {Buffer} param1 [publickey | hashed publickey] | ||
* @returns | ||
*/ | ||
static p2wpkh(coin, opt) { | ||
this.CoinSupported(coin); | ||
if (!opt.publickey && !opt.hash) | ||
throw Error('Invalid Parameters'); | ||
if (opt.publickey && opt.hash) | ||
throw Error('Invalid Parameters'); | ||
const pkHash = (opt.hash) ? opt.hash : Hash160(opt.publickey); | ||
exports.logger === null || exports.logger === void 0 ? void 0 : exports.logger.info(`publickey hash: ${pkHash.toString('hex')}`); | ||
let network = interface_1.coinmap[coin]; | ||
const words = bech32_1.bech32.toWords(pkHash); | ||
words.unshift(0x00); | ||
const address = bech32_1.bech32.encode(network.bech32, words); | ||
const op = Buffer.from([interface_1.OPCODES.OP_0, 0x14]); | ||
const scriptPublickey = Buffer.concat([op, pkHash]); | ||
const redeemHash = Hash160(scriptPublickey); | ||
exports.logger === null || exports.logger === void 0 ? void 0 : exports.logger.info(`redeem hash: ${redeemHash.toString('hex')}`); | ||
return { address, scriptPublickey, redeemHash }; | ||
} | ||
/** | ||
* Pay to MultiSig | ||
* @param {number} m | ||
* @param {Array<Buffer>} publickeys | ||
* @returns | ||
*/ | ||
static p2ms(m, publickeys) { | ||
if (m <= 0) | ||
throw Error('Invalid paramter \"m\"'); | ||
m = m + interface_1.OPCODES.OP_INT_BASE; | ||
const n = publickeys.length + interface_1.OPCODES.OP_INT_BASE; | ||
const multi_pk = Buffer.concat(publickeys); | ||
const redeem = Buffer.concat([ | ||
Buffer.from([m]), | ||
multi_pk, | ||
Buffer.from([n]), | ||
Buffer.from([interface_1.OPCODES.OP_CHECKMULTISIG]) | ||
]); | ||
const redeemHash = Hash160(redeem); | ||
exports.logger === null || exports.logger === void 0 ? void 0 : exports.logger.info(`redeem hash: ${redeemHash.toString('hex')}`); | ||
const op = Buffer.from([interface_1.OPCODES.OP_HASH160, 0x14]); | ||
const check = Buffer.from([interface_1.OPCODES.OP_EQUAL]); | ||
const scriptPubicKey = Buffer.concat([ | ||
op, | ||
redeemHash, | ||
check | ||
]); | ||
return { redeem, scriptPubicKey }; | ||
} | ||
static p2tr(coin, opt) { | ||
this.CoinSupported(coin); | ||
if (!opt.publickey && !opt.hash) | ||
throw Error('Invalid Parameters'); | ||
if (opt.publickey && opt.hash) | ||
throw Error('Invalid Parameters'); | ||
let tweaked = opt.hash; | ||
if (tweaked === undefined) { | ||
tweaked = (0, utils_1.toTweakedPublickey)(opt.publickey); | ||
} | ||
const version = 1; | ||
const network = interface_1.coinmap[coin]; | ||
const words = bech32_1.bech32.toWords(tweaked); | ||
words.unshift(version); | ||
const address = bech32_1.bech32m.encode(network.bech32, words); | ||
// witness v1 | PUSH_DATA 32 bytes | ||
const header = Buffer.from([SEGWIT_VERSION_DIFF + version, 0x20]); | ||
const scriptPublickey = Buffer.concat([header, tweaked]); | ||
return { address, scriptPublickey }; | ||
} | ||
/** | ||
* decode address to script | ||
* @param {CoinType} coin | ||
* @param {string} address | ||
*/ | ||
static decode(coin, address) { | ||
const network = interface_1.coinmap[coin]; | ||
// segwit address | ||
if (network.bech32 && address.startsWith(network.bech32)) { | ||
const trimmed = address.slice(network.bech32.length + 1); | ||
let result; | ||
switch (trimmed[0]) { | ||
case 'p': | ||
result = bech32_1.bech32m.decode(address); | ||
break; | ||
default: | ||
result = bech32_1.bech32.decode(address); | ||
break; | ||
} | ||
const version = result.words.shift(); | ||
switch (version) { | ||
case 0: | ||
const hash160 = Buffer.from(bech32_1.bech32.fromWords(result.words)); | ||
exports.logger === null || exports.logger === void 0 ? void 0 : exports.logger.debug(`bech32 address: ${address}\nbech32 decoded: ${hash160.toString("hex")}`); | ||
return this.p2wpkh(coin, { hash: hash160 }).scriptPublickey; | ||
case 1: | ||
const tweaked = Buffer.from(bech32_1.bech32m.fromWords(result.words)); | ||
exports.logger === null || exports.logger === void 0 ? void 0 : exports.logger.debug(`bech32m address: ${address}\nbech32m decoded: ${tweaked.toString("hex")}`); | ||
return this.p2tr(coin, { hash: tweaked }).scriptPublickey; | ||
default: | ||
throw Error(`ArgumentError: unsupported witness version, got "${version}" from address "${address}"`); | ||
} | ||
} | ||
try { | ||
const hash160 = this.bs58check.decode(address); | ||
const prefix = hash160[0]; | ||
const hash = hash160.slice(1); | ||
if (prefix === network.scriptHash) | ||
return this.p2sh(coin, hash).scriptPublickey; | ||
if (prefix === network.pubKeyHash) | ||
return this.p2pkh(coin, { hash }).scriptPublickey; | ||
} | ||
catch (error) { | ||
exports.logger === null || exports.logger === void 0 ? void 0 : exports.logger.debug(`${error.toString()}, cointype: ${interface_1.CoinType[coin]}, address: ${address}`); | ||
} | ||
throw Error(`ArgumentError: invalid address for ${interface_1.CoinType[coin]}, got ${address}`); | ||
} | ||
static classify(script) { | ||
if (this.isP2WPKH(script)) | ||
return interface_1.ScriptType.P2WPKH; | ||
if (this.isP2PKH(script)) | ||
return interface_1.ScriptType.P2PKH; | ||
if (this.isP2TR(script)) | ||
return interface_1.ScriptType.P2TR; | ||
throw Error(`non-standard script: ${script.toString("hex")}`); | ||
} | ||
static isP2PKH(script) { | ||
if (script.length !== 25 || | ||
script[0] !== interface_1.OPCODES.OP_DUP || | ||
script[1] !== interface_1.OPCODES.OP_HASH160 || | ||
script[2] !== 0x14 || | ||
script[23] !== interface_1.OPCODES.OP_EQUALVERIFY || | ||
script[24] !== interface_1.OPCODES.OP_CHECKSIG) | ||
return false; | ||
return true; | ||
} | ||
static isP2SH(script) { | ||
if (script.length !== 23 || | ||
script[0] !== interface_1.OPCODES.OP_HASH160 || | ||
script[1] !== 0x14 || | ||
script[22] !== interface_1.OPCODES.OP_EQUAL) | ||
return false; | ||
return true; | ||
} | ||
static isP2WPKH(script) { | ||
if (script.length !== 22 || | ||
script[0] !== interface_1.OPCODES.OP_0 || | ||
script[1] !== 0x14) | ||
return false; | ||
return true; | ||
} | ||
static isP2TR(script) { | ||
if (script.length !== 34 || | ||
script[0] !== SEGWIT_VERSION_DIFF + 1 || | ||
script[1] !== 0x20) | ||
return false; | ||
return true; | ||
} | ||
} | ||
exports.PaymentBTC = PaymentBTC; | ||
PaymentBTC.bs58check = new bs58_1.bs58Check(Hash256); | ||
function Hash160(publickey) { | ||
const sha = Buffer.from((0, hash_js_1.sha256)().update(publickey).digest()); | ||
return Buffer.from((0, hash_js_1.ripemd160)().update(sha).digest()); | ||
} | ||
exports.Hash160 = Hash160; | ||
function Hash256(data) { | ||
const sha1 = (0, hash_js_1.sha256)().update(data).digest(); | ||
const sha2 = (0, hash_js_1.sha256)().update(sha1).digest(); | ||
return Buffer.from(sha2); | ||
} | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.logger=exports.Hash160=exports.CoinType=exports.PaymentBTC=void 0;const e=require("bech32"),r=require("hash.js"),t=require("./interface");Object.defineProperty(exports,"CoinType",{enumerable:!0,get:function(){return t.CoinType}});const o=require("@secux/utility/lib/bs58"),s=require("@secux/utility"),i=require("./utils");exports.logger=null===s.Logger||void 0===s.Logger?void 0:s.Logger.child({id:"payment"});class c{static CoinSupported(e){if(e===t.CoinType.BITCOINCASH)throw Error("Please use class PaymentBCH instead");if(e===t.CoinType.GROESTL)throw Error("Please use class PaymentGRS instead")}static p2pkh(e,r){if(this.CoinSupported(e),!r.publickey&&!r.hash)throw Error("Invalid Parameters");if(r.publickey&&r.hash)throw Error("Invalid Parameters");const o=r.hash?r.hash:n(r.publickey);null===exports.logger||void 0===exports.logger||exports.logger.info(`publickey hash: ${o.toString("hex")}`);const s=t.coinmap[e],i=this.bs58check.encode(o,Buffer.from([s.pubKeyHash])),c=Buffer.from([t.OPCODES.OP_DUP,t.OPCODES.OP_HASH160,20]),h=Buffer.from([t.OPCODES.OP_EQUALVERIFY,t.OPCODES.OP_CHECKSIG]),u=Buffer.concat([c,o,h]),a=n(u);return null===exports.logger||void 0===exports.logger||exports.logger.info(`redeem hash: ${a.toString("hex")}`),{address:i,scriptPublickey:u,redeemHash:a}}static p2sh(e,r){this.CoinSupported(e);const o=t.coinmap[e],s=this.bs58check.encode(r,Buffer.from([o.scriptHash])),i=Buffer.from([t.OPCODES.OP_HASH160,20]),c=Buffer.from([t.OPCODES.OP_EQUAL]);return{address:s,scriptPublickey:Buffer.concat([i,r,c])}}static p2wpkh(r,o){if(this.CoinSupported(r),!o.publickey&&!o.hash)throw Error("Invalid Parameters");if(o.publickey&&o.hash)throw Error("Invalid Parameters");const s=o.hash?o.hash:n(o.publickey);null===exports.logger||void 0===exports.logger||exports.logger.info(`publickey hash: ${s.toString("hex")}`);let i=t.coinmap[r];const c=e.bech32.toWords(s);c.unshift(0);const h=e.bech32.encode(i.bech32,c),u=Buffer.from([t.OPCODES.OP_0,20]),a=Buffer.concat([u,s]),p=n(a);return null===exports.logger||void 0===exports.logger||exports.logger.info(`redeem hash: ${p.toString("hex")}`),{address:h,scriptPublickey:a,redeemHash:p}}static p2ms(e,r){if(e<=0)throw Error('Invalid paramter "m"');e+=t.OPCODES.OP_INT_BASE;const o=r.length+t.OPCODES.OP_INT_BASE,s=Buffer.concat(r),i=Buffer.concat([Buffer.from([e]),s,Buffer.from([o]),Buffer.from([t.OPCODES.OP_CHECKMULTISIG])]),c=n(i);null===exports.logger||void 0===exports.logger||exports.logger.info(`redeem hash: ${c.toString("hex")}`);const h=Buffer.from([t.OPCODES.OP_HASH160,20]),u=Buffer.from([t.OPCODES.OP_EQUAL]);return{redeem:i,scriptPubicKey:Buffer.concat([h,c,u])}}static p2tr(r,o){if(this.CoinSupported(r),!o.publickey&&!o.hash)throw Error("Invalid Parameters");if(o.publickey&&o.hash)throw Error("Invalid Parameters");let s=o.hash;void 0===s&&(s=(0,i.toTweakedPublickey)(o.publickey));const c=t.coinmap[r],n=e.bech32.toWords(s);n.unshift(1);const h=e.bech32m.encode(c.bech32,n),u=Buffer.from([81,32]);return{address:h,scriptPublickey:Buffer.concat([u,s])}}static decode(r,o){const s=t.coinmap[r];if(s.bech32&&o.startsWith(s.bech32)){let t;if("p"===o.slice(s.bech32.length+1)[0])t=e.bech32m.decode(o);else t=e.bech32.decode(o);const i=t.words.shift();switch(i){case 0:const s=Buffer.from(e.bech32.fromWords(t.words));return null===exports.logger||void 0===exports.logger||exports.logger.debug(`bech32 address: ${o}\nbech32 decoded: ${s.toString("hex")}`),this.p2wpkh(r,{hash:s}).scriptPublickey;case 1:const c=Buffer.from(e.bech32m.fromWords(t.words));return null===exports.logger||void 0===exports.logger||exports.logger.debug(`bech32m address: ${o}\nbech32m decoded: ${c.toString("hex")}`),this.p2tr(r,{hash:c}).scriptPublickey;default:throw Error(`ArgumentError: unsupported witness version, got "${i}" from address "${o}"`)}}try{const e=this.bs58check.decode(o),t=e[0],i=e.slice(1);if(t===s.scriptHash)return this.p2sh(r,i).scriptPublickey;if(t===s.pubKeyHash)return this.p2pkh(r,{hash:i}).scriptPublickey}catch(e){null===exports.logger||void 0===exports.logger||exports.logger.debug(`${e.toString()}, cointype: ${t.CoinType[r]}, address: ${o}`)}throw Error(`ArgumentError: invalid address for ${t.CoinType[r]}, got ${o}`)}static classify(e){if(this.isP2WPKH(e))return t.ScriptType.P2WPKH;if(this.isP2PKH(e))return t.ScriptType.P2PKH;if(this.isP2TR(e))return t.ScriptType.P2TR;throw Error(`non-standard script: ${e.toString("hex")}`)}static isP2PKH(e){return 25===e.length&&e[0]===t.OPCODES.OP_DUP&&e[1]===t.OPCODES.OP_HASH160&&20===e[2]&&e[23]===t.OPCODES.OP_EQUALVERIFY&&e[24]===t.OPCODES.OP_CHECKSIG}static isP2SH(e){return 23===e.length&&e[0]===t.OPCODES.OP_HASH160&&20===e[1]&&e[22]===t.OPCODES.OP_EQUAL}static isP2WPKH(e){return 22===e.length&&e[0]===t.OPCODES.OP_0&&20===e[1]}static isP2TR(e){return 34===e.length&&81===e[0]&&32===e[1]}}function n(e){const t=Buffer.from((0,r.sha256)().update(e).digest());return Buffer.from((0,r.ripemd160)().update(t).digest())}exports.PaymentBTC=c,c.bs58check=new o.bs58Check((function(e){const t=(0,r.sha256)().update(e).digest(),o=(0,r.sha256)().update(t).digest();return Buffer.from(o)})),exports.Hash160=n; |
567
lib/psbt.js
@@ -1,566 +0,1 @@ | ||
"use strict"; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var _SecuxPsbt_instances, _SecuxPsbt_data, _SecuxPsbt_coin, _SecuxPsbt_payment, _SecuxPsbt_tx, _SecuxPsbt_isRBF, _SecuxPsbt_paths, _SecuxPsbt_inScripts, _SecuxPsbt_fetchInputScript, _SecuxPsbt_getDataForSig, _SecuxPsbt_extractInput, _SecuxPsbt_estimateVSize, _PsbtTransaction_tx; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SecuxPsbt = void 0; | ||
const utils_1 = require("bip174/src/lib/utils"); | ||
const secp256k1 = require('secp256k1/elliptic'); | ||
const hash_js_1 = require("hash.js"); | ||
const bignumber_js_1 = require("bignumber.js"); | ||
const parser_1 = require("./parser"); | ||
const Script = require("./script"); | ||
const utility_1 = require("@secux/utility"); | ||
const interface_1 = require("./interface"); | ||
const utils_2 = require("./utils"); | ||
const payment_1 = require("./payment"); | ||
const transaction_1 = require("./transaction"); | ||
const coindef_1 = require("./coindef"); | ||
const communication_1 = require("@secux/utility/lib/communication"); | ||
const protocol_transaction_1 = require("@secux/protocol-transaction/lib/protocol-transaction"); | ||
const bip340_1 = require("./bip340"); | ||
const logger = utility_1.Logger === null || utility_1.Logger === void 0 ? void 0 : utility_1.Logger.child({ id: "psbt" }); | ||
const SIGHASH_FORKID = 0x40; | ||
class SecuxPsbt { | ||
constructor(coin, isRBF = false, data = new parser_1.Psbtv2(new PsbtTransaction())) { | ||
_SecuxPsbt_instances.add(this); | ||
_SecuxPsbt_data.set(this, void 0); | ||
_SecuxPsbt_coin.set(this, void 0); | ||
_SecuxPsbt_payment.set(this, void 0); | ||
_SecuxPsbt_tx.set(this, void 0); | ||
_SecuxPsbt_isRBF.set(this, void 0); | ||
_SecuxPsbt_paths.set(this, []); | ||
_SecuxPsbt_inScripts.set(this, {}); | ||
__classPrivateFieldSet(this, _SecuxPsbt_data, data, "f"); | ||
__classPrivateFieldSet(this, _SecuxPsbt_coin, coin, "f"); | ||
__classPrivateFieldSet(this, _SecuxPsbt_payment, (0, utils_2.getPayment)(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f")), "f"); | ||
__classPrivateFieldSet(this, _SecuxPsbt_isRBF, isRBF, "f"); | ||
//@ts-ignore | ||
__classPrivateFieldSet(this, _SecuxPsbt_tx, __classPrivateFieldGet(this, _SecuxPsbt_data, "f").globalMap.unsignedTx.tx, "f"); | ||
if (coin === interface_1.CoinType.BITCOINCASH) | ||
__classPrivateFieldGet(this, _SecuxPsbt_tx, "f").version = 1; | ||
} | ||
static FromBuffer(data, coin) { | ||
const psbtBase = parser_1.Psbtv2.fromBuffer(data, x => new PsbtTransaction(x)); | ||
const psbt = new SecuxPsbt(coin, false, psbtBase); | ||
return psbt; | ||
} | ||
AddInput(input) { | ||
var _a; | ||
if (!(0, utility_1.isSupportedCoin)(input.path)) | ||
throw Error(`ArgumentError: unsupport bip32 path, got "${input.path}"`); | ||
const mix1 = {}; | ||
const mix2 = {}; | ||
const publickey = (0, utils_2.getPublickey)(input.publickey); | ||
const script = (_a = input.script) !== null && _a !== void 0 ? _a : (0, utils_2.getDefaultScript)(input.path); | ||
switch (script) { | ||
case interface_1.ScriptType.P2PKH: | ||
mix1.witnessUtxo = { | ||
script: __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2pkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey }).scriptPublickey, | ||
value: input.satoshis | ||
}; | ||
break; | ||
case interface_1.ScriptType.P2SH_P2PKH: | ||
const p2pkh = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2pkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey }); | ||
mix2.redeemScript = p2pkh.scriptPublickey; | ||
mix1.witnessUtxo = { | ||
script: __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2sh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), p2pkh.redeemHash).scriptPublickey, | ||
value: input.satoshis | ||
}; | ||
break; | ||
case interface_1.ScriptType.P2SH_P2WPKH: | ||
const p2wpkh = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2wpkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey }); | ||
mix2.redeemScript = p2wpkh.scriptPublickey; | ||
mix1.witnessUtxo = { | ||
script: __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2sh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), p2wpkh.redeemHash).scriptPublickey, | ||
value: input.satoshis | ||
}; | ||
break; | ||
case interface_1.ScriptType.P2WPKH: | ||
mix1.witnessUtxo = { | ||
script: __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2wpkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey }).scriptPublickey, | ||
value: input.satoshis | ||
}; | ||
break; | ||
case interface_1.ScriptType.P2TR: | ||
mix1.witnessUtxo = { | ||
script: __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2tr(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey }).scriptPublickey, | ||
value: input.satoshis | ||
}; | ||
break; | ||
default: | ||
throw Error(`ArgumentError: Invalid ScriptType of input#${__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.length}, got "${interface_1.ScriptType[script]}"`); | ||
} | ||
// check input | ||
if (input.txHex) { | ||
const tx = transaction_1.Transaction.fromBuffer(Buffer.from(input.txHex, "hex")); | ||
if ((0, utils_2.getSerializer)(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f")).getId(tx) !== input.hash) { | ||
throw Error(`UTXO hash for input #${__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.length} doesn't match the hash specified in the prevout`); | ||
} | ||
const out = tx.outs[input.vout]; | ||
if (!new bignumber_js_1.BigNumber(out.value).eq(input.satoshis)) { | ||
throw Error(`UTXO value for input #${__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.length} doesn't match the value specified in the prevout`); | ||
} | ||
if (!out.script.equals(mix1.witnessUtxo.script)) { | ||
logger === null || logger === void 0 ? void 0 : logger.warn(`Input script generation error: ${out.script.toString("hex")}, got "${mix1.witnessUtxo.script}"`); | ||
} | ||
} | ||
const data = Object.assign(Object.assign({ hash: input.hash, index: input.vout, sequence: __classPrivateFieldGet(this, _SecuxPsbt_isRBF, "f") ? 0xfffffffd : undefined }, mix1), mix2); | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").addInput(data); | ||
__classPrivateFieldGet(this, _SecuxPsbt_paths, "f").push(input.path); | ||
return this; | ||
} | ||
AddInputs(inputs) { | ||
for (const input of inputs) { | ||
this.AddInput(input); | ||
} | ||
return this; | ||
} | ||
AddOutput(output) { | ||
var _a; | ||
let out, script, path; | ||
let value = output.satoshis; | ||
if ((out = (0, interface_1.isOutuptScriptExtended)(output))) { | ||
const pk = (0, utils_2.getPublickey)(out.publickey); | ||
path = out.path; | ||
const scriptType = (_a = out.script) !== null && _a !== void 0 ? _a : (0, utils_2.getDefaultScript)(path); | ||
let redeemHash, p2sh; | ||
switch (scriptType) { | ||
case interface_1.ScriptType.P2SH_P2WPKH: | ||
if (!out.path.startsWith("m/49'/")) | ||
throw Error("P2SH(...) should use m/49' path"); | ||
redeemHash = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2wpkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey: pk }).redeemHash; | ||
p2sh = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2sh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), redeemHash); | ||
script = p2sh.scriptPublickey; | ||
break; | ||
case interface_1.ScriptType.P2SH_P2PKH: | ||
if (!out.path.startsWith("m/49'/")) | ||
throw Error("P2SH(...) should use m/49' path"); | ||
redeemHash = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2pkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey: pk }).redeemHash; | ||
p2sh = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2sh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), redeemHash); | ||
script = p2sh.scriptPublickey; | ||
break; | ||
case interface_1.ScriptType.P2PKH: | ||
if (!out.path.startsWith("m/44'/")) | ||
throw Error("P2PKH should use m/44' path"); | ||
const p2pkh = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2pkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey: pk }); | ||
script = p2pkh.scriptPublickey; | ||
break; | ||
case interface_1.ScriptType.P2WPKH: | ||
if (!out.path.startsWith("m/84'/")) | ||
throw Error("P2WPKH should use m/84' path"); | ||
const p2wpkh = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2wpkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey: pk }); | ||
script = p2wpkh.scriptPublickey; | ||
break; | ||
case interface_1.ScriptType.P2TR: | ||
if (!out.path.startsWith("m/86'/")) | ||
throw Error("P2TR should use m/86' path"); | ||
const p2tr = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").p2tr(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { publickey: pk }); | ||
script = p2tr.scriptPublickey; | ||
break; | ||
default: | ||
throw Error(`ArgumentError: Invalid ScriptType of output#${__classPrivateFieldGet(this, _SecuxPsbt_data, "f").outputs.length}, got "${interface_1.ScriptType[scriptType]}"`); | ||
} | ||
} | ||
else if ((out = (0, interface_1.isOutputAddress)(output))) { | ||
script = __classPrivateFieldGet(this, _SecuxPsbt_payment, "f").decode(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), out.address); | ||
} | ||
else if ((out = (0, interface_1.isOutuptScript)(output))) { | ||
script = Buffer.from(out.scriptHex, "hex"); | ||
} | ||
else | ||
throw Error("Invalid parameter of output"); | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").addOutput({ | ||
script, | ||
value, | ||
path | ||
}); | ||
return this; | ||
} | ||
AddOutputs(outputs) { | ||
for (const output of outputs) { | ||
this.AddOutput(output); | ||
} | ||
return this; | ||
} | ||
PrepareSign(feeRate) { | ||
if (feeRate) { | ||
const vSize = __classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_estimateVSize).call(this); | ||
const estimateFee = Math.round(vSize * feeRate); | ||
logger === null || logger === void 0 ? void 0 : logger.info(`Estimated fee is ${estimateFee}, with ${feeRate} fee rates.`); | ||
const total = __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.reduce((a, txIn) => a + txIn.witnessUtxo.value, 0); | ||
const spend = __classPrivateFieldGet(this, _SecuxPsbt_tx, "f").outs[0].value; | ||
const change = (__classPrivateFieldGet(this, _SecuxPsbt_data, "f").outputs.length === 1) ? 0 : __classPrivateFieldGet(this, _SecuxPsbt_tx, "f").outs[1].value; | ||
const actualFee = total - spend - change; | ||
if (actualFee < estimateFee) | ||
logger === null || logger === void 0 ? void 0 : logger.warn(`Estimated fee is ${estimateFee}, but got ${actualFee}.`); | ||
if (actualFee > estimateFee || actualFee < vSize) { | ||
if (change !== 0) { | ||
const value = total - spend - estimateFee; | ||
if (value < 0) | ||
throw Error(`Insufficient amount, expect ${spend + estimateFee}, but got ${total}.`); | ||
__classPrivateFieldGet(this, _SecuxPsbt_tx, "f").outs[1].value = value; | ||
logger === null || logger === void 0 ? void 0 : logger.info(`Modify change amount from ${change} to ${value}.`); | ||
} | ||
else { | ||
const value = total - estimateFee; | ||
if (value < 0) | ||
throw Error(`Insufficient amount, expect at least ${estimateFee}, but got ${total}.`); | ||
__classPrivateFieldGet(this, _SecuxPsbt_tx, "f").outs[0].value = value; | ||
logger === null || logger === void 0 ? void 0 : logger.info(`Modify spend amount from ${spend} to ${value}.`); | ||
} | ||
} | ||
} | ||
const outConfirm = Buffer.from([ | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").outputs.length, | ||
...(0, utility_1.BigIntToBuffer)(__classPrivateFieldGet(this, _SecuxPsbt_tx, "f").outs[0].value, 8), | ||
__classPrivateFieldGet(this, _SecuxPsbt_tx, "f").outs[0].script.length, | ||
...__classPrivateFieldGet(this, _SecuxPsbt_tx, "f").outs[0].script, | ||
...__classPrivateFieldGet(this, _SecuxPsbt_tx, "f").outs.slice(1).reduce((data, out) => [ | ||
...data, | ||
...(0, utility_1.BigIntToBuffer)(out.value, 8), | ||
...(0, utility_1.buildPathBuffer)(out.path).pathBuffer | ||
], []) | ||
]); | ||
const txs = __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.map((_, i) => { | ||
const data = __classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_getDataForSig).call(this, i); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`tx data [${i}]: ${data.toString("hex")}`); | ||
if (data.length + communication_1.MAX_HEAD_SIZE > communication_1.ONESIGN_THRESHOLD) { | ||
throw Error("ArgumentError: utxo exceed maximum payload size"); | ||
} | ||
return data; | ||
}); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`confirm data: ${outConfirm.toString("hex")}`); | ||
const commands = []; | ||
let _txs = [], _paths = []; | ||
let confirmBuf = (__classPrivateFieldGet(this, _SecuxPsbt_coin, "f") !== interface_1.CoinType.BITCOINCASH && | ||
__classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_fetchInputScript).call(this, 0).type === interface_1.ScriptType.P2PKH) ? Buffer.alloc(0) : outConfirm; | ||
for (let i = 0, size = 0; i < txs.length; i++) { | ||
size += txs[i].length + communication_1.MAX_HEAD_SIZE; | ||
_txs.push(txs[i]); | ||
_paths.push(__classPrivateFieldGet(this, _SecuxPsbt_paths, "f")[i]); | ||
if (size + confirmBuf.length < communication_1.ONESIGN_THRESHOLD) | ||
continue; | ||
_txs.pop(); | ||
_paths.pop(); | ||
commands.push(protocol_transaction_1.SecuxTransactionTool.signRawTransactionList(_paths, _txs, confirmBuf)); | ||
size = txs[i].length + 25; | ||
_txs = [txs[i]]; | ||
_paths = [__classPrivateFieldGet(this, _SecuxPsbt_paths, "f")[i]]; | ||
const { type } = __classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_fetchInputScript).call(this, i); | ||
if (__classPrivateFieldGet(this, _SecuxPsbt_coin, "f") !== interface_1.CoinType.BITCOINCASH && type === interface_1.ScriptType.P2PKH) { | ||
confirmBuf = Buffer.alloc(0); | ||
} | ||
else { | ||
confirmBuf = outConfirm; | ||
} | ||
} | ||
if (_txs.length > 0) { | ||
commands.push(protocol_transaction_1.SecuxTransactionTool.signRawTransactionList(_paths, _txs, confirmBuf)); | ||
} | ||
return { | ||
commands, | ||
rawTx: __classPrivateFieldGet(this, _SecuxPsbt_data, "f").toHex() | ||
}; | ||
} | ||
appendSignature(signatures, publickeys) { | ||
var _a, _b; | ||
if (signatures.length !== publickeys.length) | ||
throw Error(`ArgumentError: each signature is correspond to one publickey, \ | ||
got ${signatures.length} signatures and ${publickeys.length} publickeys`); | ||
for (let i = 0; i < __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.length; i++) { | ||
const data = __classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_getDataForSig).call(this, i); | ||
if (__classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_fetchInputScript).call(this, i).type !== interface_1.ScriptType.P2TR) { | ||
const hash = (__classPrivateFieldGet(this, _SecuxPsbt_coin, "f") === interface_1.CoinType.GROESTL) ? Buffer.from((0, hash_js_1.sha256)().update(data).digest()) | ||
: Buffer.from((0, hash_js_1.sha256)().update((0, hash_js_1.sha256)().update(data).digest()).digest()); | ||
const publickey = publickeys[i]; | ||
if (!secp256k1.ecdsaVerify(signatures[i], hash, publickey)) | ||
throw Error(`Signature Error #${i}`); | ||
let sighashType = (_a = __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs[i].sighashType) !== null && _a !== void 0 ? _a : transaction_1.Transaction.SIGHASH_ALL; | ||
if (__classPrivateFieldGet(this, _SecuxPsbt_coin, "f") === interface_1.CoinType.BITCOINCASH) | ||
sighashType = sighashType | SIGHASH_FORKID; | ||
const partialSig = [ | ||
{ | ||
pubkey: publickey, | ||
signature: Script.encode(signatures[i], sighashType), | ||
}, | ||
]; | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").updateInput(i, { partialSig }); | ||
} | ||
else { | ||
const hash = (0, utils_2.taggedHash)("TapSighash", data); | ||
const tweaked = (0, utils_2.toTweakedPublickey)(publickeys[i]); | ||
const signature = signatures[i].slice(0, 64); | ||
if (!(0, bip340_1.taprootVerify)(signature, hash, tweaked)) | ||
throw Error(`Signature Error #${i}`); | ||
const sighashType = (_b = __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs[i].sighashType) !== null && _b !== void 0 ? _b : transaction_1.Transaction.SIGHASH_DEFAULT; | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs[i].partialSig = [ | ||
{ | ||
pubkey: tweaked, | ||
signature: (sighashType === transaction_1.Transaction.SIGHASH_DEFAULT) ? signature | ||
: Buffer.from([sighashType, ...signature]) | ||
}, | ||
]; | ||
} | ||
} | ||
return this; | ||
} | ||
finalizeAllInputs() { | ||
if (__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.length < 1) | ||
throw Error("utxo input cannot be empty"); | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.forEach((input, idx) => { | ||
(0, utils_1.checkForInput)(__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs, idx); | ||
const { script, scriptType } = getScriptFromInput(input, __classPrivateFieldGet(this, _SecuxPsbt_coin, "f")); | ||
if (!script) | ||
throw new Error(`No script found for input #${idx}`); | ||
// check sighash type | ||
if (input.sighashType && input.partialSig) { | ||
const { partialSig, sighashType } = input; | ||
for (const sig of partialSig) { | ||
const { hashType } = Script.decode(sig.signature); | ||
if (hashType !== sighashType) | ||
throw new Error('Signature sighash does not match input sighash type'); | ||
} | ||
} | ||
const { finalScriptSig, finalScriptWitness } = prepareFinalScripts(scriptType, input.partialSig); | ||
if (finalScriptSig) | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").updateInput(idx, { finalScriptSig }); | ||
if (finalScriptWitness) | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").updateInput(idx, { finalScriptWitness }); | ||
if (!finalScriptSig && !finalScriptWitness) | ||
throw new Error(`Unknown error finalizing input #${idx}`); | ||
}); | ||
return this; | ||
} | ||
extractTransaction() { | ||
const tx = __classPrivateFieldGet(this, _SecuxPsbt_tx, "f").clone(); | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.forEach((input, idx) => __classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_extractInput).call(this, tx, idx, input)); | ||
const input = __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.reduce((sum, txIn) => sum.plus(txIn.witnessUtxo.value), new bignumber_js_1.BigNumber(0)); | ||
const output = tx.outs.reduce((sum, txOut) => sum.plus(txOut.value), new bignumber_js_1.BigNumber(0)); | ||
const fee = input.minus(output); | ||
const minFee = tx.virtualSize(); | ||
if (fee.lt(minFee)) | ||
throw Error(`Transaction fee must >= ${minFee}, but got ${fee}.`); | ||
return tx; | ||
} | ||
} | ||
exports.SecuxPsbt = SecuxPsbt; | ||
_SecuxPsbt_data = new WeakMap(), _SecuxPsbt_coin = new WeakMap(), _SecuxPsbt_payment = new WeakMap(), _SecuxPsbt_tx = new WeakMap(), _SecuxPsbt_isRBF = new WeakMap(), _SecuxPsbt_paths = new WeakMap(), _SecuxPsbt_inScripts = new WeakMap(), _SecuxPsbt_instances = new WeakSet(), _SecuxPsbt_fetchInputScript = function _SecuxPsbt_fetchInputScript(index) { | ||
if (__classPrivateFieldGet(this, _SecuxPsbt_inScripts, "f")[index]) | ||
return __classPrivateFieldGet(this, _SecuxPsbt_inScripts, "f")[index]; | ||
const txIn = __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs[index]; | ||
const prevout = txIn.witnessUtxo; | ||
const type = getScriptFromInput(txIn, __classPrivateFieldGet(this, _SecuxPsbt_coin, "f")).scriptType; | ||
const scriptPubkey = getMeaningfulScript(prevout.script, type, txIn.redeemScript, txIn.witnessScript); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`input #${index} script type: ${interface_1.ScriptType[type]}`); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`script: ${scriptPubkey.toString("hex")}`); | ||
const obj = { type, scriptPubkey }; | ||
__classPrivateFieldGet(this, _SecuxPsbt_inScripts, "f")[index] = obj; | ||
return obj; | ||
}, _SecuxPsbt_getDataForSig = function _SecuxPsbt_getDataForSig(inputIndex) { | ||
var _a, _b; | ||
const txIn = __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs[inputIndex]; | ||
const unsignedTx = __classPrivateFieldGet(this, _SecuxPsbt_tx, "f"); | ||
let sighashType = (_a = txIn.sighashType) !== null && _a !== void 0 ? _a : transaction_1.Transaction.SIGHASH_ALL; | ||
const serializer = (0, utils_2.getSerializer)(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f")); | ||
if (txIn.witnessUtxo === undefined) | ||
Error('Need a Utxo input item for signing'); | ||
const prevout = txIn.witnessUtxo; | ||
const { type, scriptPubkey } = __classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_fetchInputScript).call(this, inputIndex); | ||
let data; | ||
switch (type) { | ||
case interface_1.ScriptType.P2WPKH: | ||
case interface_1.ScriptType.P2SH_P2WPKH: | ||
case interface_1.ScriptType.P2SH_P2PKH: | ||
logger === null || logger === void 0 ? void 0 : logger.debug(interface_1.ScriptType[type]); | ||
// P2WPKH uses the P2PKH template for prevoutScript when signing | ||
const signingScript = (0, utils_2.getPayment)(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f")).p2pkh(__classPrivateFieldGet(this, _SecuxPsbt_coin, "f"), { hash: scriptPubkey.slice(2) }).scriptPublickey; | ||
data = serializer.dataForWitnessV0(unsignedTx, inputIndex, signingScript, prevout.value, sighashType); | ||
break; | ||
case interface_1.ScriptType.P2TR: | ||
logger === null || logger === void 0 ? void 0 : logger.debug("p2tr"); | ||
sighashType = (_b = txIn.sighashType) !== null && _b !== void 0 ? _b : transaction_1.Transaction.SIGHASH_DEFAULT; | ||
data = serializer.dataForWitnessV1(unsignedTx, inputIndex, __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.map((_, i) => __classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_fetchInputScript).call(this, i).scriptPubkey), __classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.map(x => x.witnessUtxo.value), sighashType); | ||
break; | ||
default: | ||
if (__classPrivateFieldGet(this, _SecuxPsbt_coin, "f") === interface_1.CoinType.BITCOINCASH) { | ||
logger === null || logger === void 0 ? void 0 : logger.debug("bch using bip143"); | ||
data = serializer.dataForWitnessV0(unsignedTx, inputIndex, scriptPubkey, prevout.value, sighashType | SIGHASH_FORKID); | ||
} | ||
else { | ||
logger === null || logger === void 0 ? void 0 : logger.debug("non-segwit"); | ||
data = serializer.dataForSignature(unsignedTx, inputIndex, scriptPubkey, sighashType); | ||
} | ||
break; | ||
} | ||
return data; | ||
}, _SecuxPsbt_extractInput = function _SecuxPsbt_extractInput(tx, index, _) { | ||
if (!_.finalScriptSig && !_.finalScriptWitness) | ||
throw Error(`input#${index} not finalized.`); | ||
if (_.finalScriptSig) | ||
tx.ins[index].script = _.finalScriptSig; | ||
if (_.finalScriptWitness) { | ||
if (__classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_fetchInputScript).call(this, index).type !== interface_1.ScriptType.P2TR) { | ||
tx.ins[index].witness = (0, utils_2.scriptWitnessToWitnessStack)(_.finalScriptWitness); | ||
} | ||
else { | ||
tx.ins[index].witness = [_.finalScriptWitness]; | ||
} | ||
} | ||
}, _SecuxPsbt_estimateVSize = function _SecuxPsbt_estimateVSize() { | ||
const txForFee = __classPrivateFieldGet(this, _SecuxPsbt_tx, "f").clone(); | ||
let scriptSize = 0, witnessSize = 2; | ||
__classPrivateFieldGet(this, _SecuxPsbt_data, "f").inputs.forEach((txIn, i) => { | ||
const { type } = __classPrivateFieldGet(this, _SecuxPsbt_instances, "m", _SecuxPsbt_fetchInputScript).call(this, i); | ||
scriptSize += (0, utils_2.getInScriptSize)(type); | ||
const witness = (0, utils_2.getWitnessSize)(type, txIn.sighashType); | ||
witnessSize += (0, utils_2.vectorSize)(witness); | ||
}); | ||
return txForFee.virtualSize() + scriptSize + witnessSize / 4; | ||
}; | ||
function getMeaningfulScript(script, scriptType, redeemScript, witnessScript) { | ||
let meaningfulScript; | ||
switch (scriptType) { | ||
case interface_1.ScriptType.P2SH_P2PKH: | ||
case interface_1.ScriptType.P2SH_P2WPKH: | ||
if (!redeemScript) | ||
throw Error("scriptPubkey is P2SH but redeemScript missing"); | ||
meaningfulScript = redeemScript; | ||
break; | ||
// case ScriptType.P2SH_P2WSH, ScriptType.P2WSH: | ||
// if (!witnessScript) throw Error("scriptPubkey or redeemScript is P2WSH but witnessScript missing"); | ||
// meaningfulScript = witnessScript; | ||
// break; | ||
default: | ||
meaningfulScript = script; | ||
} | ||
if (!meaningfulScript) | ||
throw Error("cannot extract script"); | ||
return meaningfulScript; | ||
} | ||
function getScriptFromInput(input, coin) { | ||
let script; | ||
let scriptType; | ||
const payment = (0, utils_2.getPayment)(coin); | ||
if (input.witnessScript) { | ||
script = input.witnessScript; | ||
// scriptType = payment.classify(script); | ||
// switch (scriptType) { | ||
// case ScriptType.P2PKH: | ||
// scriptType = ScriptType.P2WSH_P2PKH; | ||
// break; | ||
// case ScriptType.P2WPKH: | ||
// scriptType = ScriptType.P2WSH_P2WPKH; | ||
// break; | ||
// } | ||
} | ||
else if (input.redeemScript) { | ||
script = input.redeemScript; | ||
scriptType = payment.classify(script); | ||
switch (scriptType) { | ||
case interface_1.ScriptType.P2PKH: | ||
scriptType = interface_1.ScriptType.P2SH_P2PKH; | ||
break; | ||
case interface_1.ScriptType.P2WPKH: | ||
scriptType = interface_1.ScriptType.P2SH_P2WPKH; | ||
break; | ||
} | ||
} | ||
else { | ||
script = input.witnessUtxo.script; | ||
scriptType = payment.classify(script); | ||
} | ||
return { | ||
script, | ||
scriptType | ||
}; | ||
} | ||
function prepareFinalScripts(scriptType, partialSig) { | ||
let finalScriptSig; | ||
let finalScriptWitness; | ||
const { signature, pubkey } = partialSig[0]; | ||
switch (scriptType) { | ||
case interface_1.ScriptType.P2PKH: | ||
finalScriptSig = Script.compile([signature, pubkey]); | ||
break; | ||
case interface_1.ScriptType.P2SH_P2PKH: | ||
finalScriptSig = (() => { | ||
const input = Script.compile([signature, pubkey]); | ||
const chunks = Script.decompile(input); | ||
const redeem = { | ||
output: chunks[chunks.length - 1], | ||
input: Script.compile(chunks.slice(0, -1)) | ||
}; | ||
return Script.compile([].concat(Script.decompile(redeem.input), redeem.output)); | ||
})(); | ||
break; | ||
case interface_1.ScriptType.P2SH_P2WPKH: | ||
finalScriptWitness = (0, utils_2.witnessStackToScriptWitness)([signature, pubkey]); | ||
finalScriptSig = (() => { | ||
const input = Buffer.alloc(0); | ||
const hash = (0, payment_1.Hash160)(pubkey); | ||
const output = Script.compile([coindef_1.OPCODES.OP_0, hash]); | ||
return Script.compile([].concat(Script.decompile(input), output)); | ||
})(); | ||
break; | ||
case interface_1.ScriptType.P2WPKH: | ||
finalScriptWitness = (0, utils_2.witnessStackToScriptWitness)([signature, pubkey]); | ||
break; | ||
case interface_1.ScriptType.P2TR: | ||
finalScriptWitness = signature; | ||
break; | ||
} | ||
return { | ||
finalScriptSig, | ||
finalScriptWitness | ||
}; | ||
} | ||
class PsbtTransaction { | ||
constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { | ||
_PsbtTransaction_tx.set(this, void 0); | ||
__classPrivateFieldSet(this, _PsbtTransaction_tx, transaction_1.Transaction.fromBuffer(buffer), "f"); | ||
} | ||
getInputOutputCounts() { | ||
return { | ||
inputCount: __classPrivateFieldGet(this, _PsbtTransaction_tx, "f").ins.length, | ||
outputCount: __classPrivateFieldGet(this, _PsbtTransaction_tx, "f").outs.length, | ||
}; | ||
} | ||
addInput(input) { | ||
if (input.hash === undefined || | ||
input.index === undefined || | ||
(!Buffer.isBuffer(input.hash) && typeof input.hash !== 'string') || | ||
typeof input.index !== 'number') { | ||
throw new Error('Error adding input.'); | ||
} | ||
const hash = typeof input.hash === 'string' | ||
? Buffer.from(Buffer.from(input.hash, 'hex').reverse()) | ||
: input.hash; | ||
__classPrivateFieldGet(this, _PsbtTransaction_tx, "f").addInput(hash, input.index, input.sequence); | ||
} | ||
addOutput(output) { | ||
if (output.script === undefined || | ||
output.value === undefined || | ||
!Buffer.isBuffer(output.script) || | ||
typeof output.value !== 'number') { | ||
throw new Error('Error adding output.'); | ||
} | ||
__classPrivateFieldGet(this, _PsbtTransaction_tx, "f").addOutput(output.script, output.value, output.path); | ||
} | ||
toBuffer() { | ||
return __classPrivateFieldGet(this, _PsbtTransaction_tx, "f").toBuffer(); | ||
} | ||
get tx() { | ||
return __classPrivateFieldGet(this, _PsbtTransaction_tx, "f"); | ||
} | ||
} | ||
_PsbtTransaction_tx = new WeakMap(); | ||
"use strict";var t,e,i,s,r,n,o,p,a,u,c,h,f,l=this&&this.__classPrivateFieldSet||function(t,e,i,s,r){if("m"===s)throw new TypeError("Private method is not writable");if("a"===s&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof e?t!==e||!r:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===s?r.call(t,i):r?r.value=i:e.set(t,i),i},d=this&&this.__classPrivateFieldGet||function(t,e,i,s){if("a"===i&&!s)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!s:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===i?s:"a"===i?s.call(t):s?s.value:e.get(t)};Object.defineProperty(exports,"__esModule",{value:!0}),exports.SecuxPsbt=void 0;const S=require("bip174/src/lib/utils"),g=require("secp256k1/elliptic"),y=require("hash.js"),P=require("bignumber.js"),m=require("./parser"),w=require("./script"),b=require("@secux/utility"),T=require("./interface"),k=require("./utils"),v=require("./payment"),H=require("./transaction"),E=require("./coindef"),x=require("@secux/utility/lib/communication"),I=require("@secux/protocol-transaction/lib/protocol-transaction"),W=require("./bip340"),B=null===b.Logger||void 0===b.Logger?void 0:b.Logger.child({id:"psbt"});class ${constructor(a,u=!1,c=new m.Psbtv2(new _)){t.add(this),e.set(this,void 0),i.set(this,void 0),s.set(this,void 0),r.set(this,void 0),n.set(this,void 0),o.set(this,[]),p.set(this,{}),l(this,e,c,"f"),l(this,i,a,"f"),l(this,s,(0,k.getPayment)(d(this,i,"f")),"f"),l(this,n,u,"f"),l(this,r,d(this,e,"f").globalMap.unsignedTx.tx,"f"),a===T.CoinType.BITCOINCASH&&(d(this,r,"f").version=1)}static FromBuffer(t,e){const i=m.Psbtv2.fromBuffer(t,(t=>new _(t)));return new $(e,!1,i)}AddInput(t){var r;if(!(0,b.isSupportedCoin)(t.path))throw Error(`ArgumentError: unsupport bip32 path, got "${t.path}"`);const p={},a={},u=(0,k.getPublickey)(t.publickey),c=null!==(r=t.script)&&void 0!==r?r:(0,k.getDefaultScript)(t.path),h=new P.BigNumber(t.satoshis).toNumber();switch(c){case T.ScriptType.P2PKH:p.witnessUtxo={script:d(this,s,"f").p2pkh(d(this,i,"f"),{publickey:u}).scriptPublickey,value:h};break;case T.ScriptType.P2SH_P2PKH:const t=d(this,s,"f").p2pkh(d(this,i,"f"),{publickey:u});a.redeemScript=t.scriptPublickey,p.witnessUtxo={script:d(this,s,"f").p2sh(d(this,i,"f"),t.redeemHash).scriptPublickey,value:h};break;case T.ScriptType.P2SH_P2WPKH:const r=d(this,s,"f").p2wpkh(d(this,i,"f"),{publickey:u});a.redeemScript=r.scriptPublickey,p.witnessUtxo={script:d(this,s,"f").p2sh(d(this,i,"f"),r.redeemHash).scriptPublickey,value:h};break;case T.ScriptType.P2WPKH:p.witnessUtxo={script:d(this,s,"f").p2wpkh(d(this,i,"f"),{publickey:u}).scriptPublickey,value:h};break;case T.ScriptType.P2TR:p.witnessUtxo={script:d(this,s,"f").p2tr(d(this,i,"f"),{publickey:u}).scriptPublickey,value:h};break;default:throw Error(`ArgumentError: Invalid ScriptType of input#${d(this,e,"f").inputs.length}, got "${T.ScriptType[c]}"`)}if(t.txHex){const s=H.Transaction.fromBuffer(Buffer.from(t.txHex,"hex"));if((0,k.getSerializer)(d(this,i,"f")).getId(s)!==t.hash)throw Error(`UTXO hash for input #${d(this,e,"f").inputs.length} doesn't match the hash specified in the prevout`);const r=s.outs[t.vout];if(!new P.BigNumber(r.value).eq(t.satoshis))throw Error(`UTXO value for input #${d(this,e,"f").inputs.length} doesn't match the value specified in the prevout`);r.script.equals(p.witnessUtxo.script)||null==B||B.warn(`Input script generation error: ${r.script.toString("hex")}, got "${p.witnessUtxo.script}"`)}const f=Object.assign(Object.assign({hash:t.hash,index:t.vout,sequence:d(this,n,"f")?4294967293:void 0},p),a);return d(this,e,"f").addInput(f),d(this,o,"f").push(t.path),this}AddInputs(t){for(const e of t)this.AddInput(e);return this}AddOutput(t){var r;let n,o,p,a=new P.BigNumber(t.satoshis).toNumber();if(n=(0,T.isOutuptScriptExtended)(t)){const t=(0,k.getPublickey)(n.publickey);p=n.path;const a=null!==(r=n.script)&&void 0!==r?r:(0,k.getDefaultScript)(p);let u,c;switch(a){case T.ScriptType.P2SH_P2WPKH:if(!n.path.startsWith("m/49'/"))throw Error("P2SH(...) should use m/49' path");u=d(this,s,"f").p2wpkh(d(this,i,"f"),{publickey:t}).redeemHash,c=d(this,s,"f").p2sh(d(this,i,"f"),u),o=c.scriptPublickey;break;case T.ScriptType.P2SH_P2PKH:if(!n.path.startsWith("m/49'/"))throw Error("P2SH(...) should use m/49' path");u=d(this,s,"f").p2pkh(d(this,i,"f"),{publickey:t}).redeemHash,c=d(this,s,"f").p2sh(d(this,i,"f"),u),o=c.scriptPublickey;break;case T.ScriptType.P2PKH:if(!n.path.startsWith("m/44'/"))throw Error("P2PKH should use m/44' path");o=d(this,s,"f").p2pkh(d(this,i,"f"),{publickey:t}).scriptPublickey;break;case T.ScriptType.P2WPKH:if(!n.path.startsWith("m/84'/"))throw Error("P2WPKH should use m/84' path");o=d(this,s,"f").p2wpkh(d(this,i,"f"),{publickey:t}).scriptPublickey;break;case T.ScriptType.P2TR:if(!n.path.startsWith("m/86'/"))throw Error("P2TR should use m/86' path");o=d(this,s,"f").p2tr(d(this,i,"f"),{publickey:t}).scriptPublickey;break;default:throw Error(`ArgumentError: Invalid ScriptType of output#${d(this,e,"f").outputs.length}, got "${T.ScriptType[a]}"`)}}else if(n=(0,T.isOutputAddress)(t))o=d(this,s,"f").decode(d(this,i,"f"),n.address);else{if(!(n=(0,T.isOutuptScript)(t)))throw Error("Invalid parameter of output");o=Buffer.from(n.scriptHex,"hex")}return d(this,e,"f").addOutput({script:o,value:a,path:p}),this}AddOutputs(t){for(const e of t)this.AddOutput(e);return this}PrepareSign(s){if(s){const i=d(this,t,"m",h).call(this),n=Math.round(i*s);null==B||B.info(`Estimated fee is ${n}, with ${s} fee rates.`);const o=d(this,e,"f").inputs.reduce(((t,e)=>t+e.witnessUtxo.value),0),p=d(this,r,"f").outs[0].value,a=1===d(this,e,"f").outputs.length?0:d(this,r,"f").outs[1].value,u=o-p-a;if(u<n&&(null==B||B.warn(`Estimated fee is ${n}, but got ${u}.`)),u>n||u<i)if(0!==a){const t=o-p-n;if(t<0)throw Error(`Insufficient amount, expect ${p+n}, but got ${o}.`);d(this,r,"f").outs[1].value=t,null==B||B.info(`Modify change amount from ${a} to ${t}.`)}else{const t=o-n;if(t<0)throw Error(`Insufficient amount, expect at least ${n}, but got ${o}.`);d(this,r,"f").outs[0].value=t,null==B||B.info(`Modify spend amount from ${p} to ${t}.`)}}const n=Buffer.from([d(this,e,"f").outputs.length,...(0,b.BigIntToBuffer)(d(this,r,"f").outs[0].value,8),d(this,r,"f").outs[0].script.length,...d(this,r,"f").outs[0].script,...d(this,r,"f").outs.slice(1).reduce(((t,e)=>[...t,...(0,b.BigIntToBuffer)(e.value,8),...(0,b.buildPathBuffer)(e.path).pathBuffer]),[])]),p=d(this,e,"f").inputs.map(((e,i)=>{const s=d(this,t,"m",u).call(this,i);if(null==B||B.debug(`tx data [${i}]: ${s.toString("hex")}`),s.length+x.MAX_HEAD_SIZE>x.ONESIGN_THRESHOLD)throw Error("ArgumentError: utxo exceed maximum payload size");return s}));null==B||B.debug(`confirm data: ${n.toString("hex")}`);const c=[];let f=[],l=[],S=d(this,i,"f")!==T.CoinType.BITCOINCASH&&d(this,t,"m",a).call(this,0).type===T.ScriptType.P2PKH?Buffer.alloc(0):n;for(let e=0,s=0;e<p.length;e++){if(s+=p[e].length+x.MAX_HEAD_SIZE,f.push(p[e]),l.push(d(this,o,"f")[e]),s+S.length<x.ONESIGN_THRESHOLD)continue;f.pop(),l.pop(),c.push(I.SecuxTransactionTool.signRawTransactionList(l,f,S)),s=p[e].length+25,f=[p[e]],l=[d(this,o,"f")[e]];const{type:r}=d(this,t,"m",a).call(this,e);S=d(this,i,"f")!==T.CoinType.BITCOINCASH&&r===T.ScriptType.P2PKH?Buffer.alloc(0):n}return f.length>0&&c.push(I.SecuxTransactionTool.signRawTransactionList(l,f,S)),{commands:c,rawTx:d(this,e,"f").toHex()}}appendSignature(s,r){var n,o;if(s.length!==r.length)throw Error(`ArgumentError: each signature is correspond to one publickey, got ${s.length} signatures and ${r.length} publickeys`);for(let p=0;p<d(this,e,"f").inputs.length;p++){const c=d(this,t,"m",u).call(this,p);if(d(this,t,"m",a).call(this,p).type!==T.ScriptType.P2TR){const t=d(this,i,"f")===T.CoinType.GROESTL?Buffer.from((0,y.sha256)().update(c).digest()):Buffer.from((0,y.sha256)().update((0,y.sha256)().update(c).digest()).digest()),o=r[p];if(!g.ecdsaVerify(s[p],t,o))throw Error(`Signature Error #${p}`);let a=null!==(n=d(this,e,"f").inputs[p].sighashType)&&void 0!==n?n:H.Transaction.SIGHASH_ALL;d(this,i,"f")===T.CoinType.BITCOINCASH&&(a|=64);const u=[{pubkey:o,signature:w.encode(s[p],a)}];d(this,e,"f").updateInput(p,{partialSig:u})}else{const t=(0,k.taggedHash)("TapSighash",c),i=(0,k.toTweakedPublickey)(r[p]),n=s[p].slice(0,64);if(!(0,W.taprootVerify)(n,t,i))throw Error(`Signature Error #${p}`);const a=null!==(o=d(this,e,"f").inputs[p].sighashType)&&void 0!==o?o:H.Transaction.SIGHASH_DEFAULT;d(this,e,"f").inputs[p].partialSig=[{pubkey:i,signature:a===H.Transaction.SIGHASH_DEFAULT?n:Buffer.from([a,...n])}]}}return this}finalizeAllInputs(){if(d(this,e,"f").inputs.length<1)throw Error("utxo input cannot be empty");return d(this,e,"f").inputs.forEach(((t,s)=>{(0,S.checkForInput)(d(this,e,"f").inputs,s);const{script:r,scriptType:n}=A(t,d(this,i,"f"));if(!r)throw new Error(`No script found for input #${s}`);if(t.sighashType&&t.partialSig){const{partialSig:e,sighashType:i}=t;for(const t of e){const{hashType:e}=w.decode(t.signature);if(e!==i)throw new Error("Signature sighash does not match input sighash type")}}const{finalScriptSig:o,finalScriptWitness:p}=function(t,e){let i,s;const{signature:r,pubkey:n}=e[0];switch(t){case T.ScriptType.P2PKH:i=w.compile([r,n]);break;case T.ScriptType.P2SH_P2PKH:i=(()=>{const t=w.compile([r,n]),e=w.decompile(t),i={output:e[e.length-1],input:w.compile(e.slice(0,-1))};return w.compile([].concat(w.decompile(i.input),i.output))})();break;case T.ScriptType.P2SH_P2WPKH:s=(0,k.witnessStackToScriptWitness)([r,n]),i=(()=>{const t=Buffer.alloc(0),e=(0,v.Hash160)(n),i=w.compile([E.OPCODES.OP_0,e]);return w.compile([].concat(w.decompile(t),i))})();break;case T.ScriptType.P2WPKH:s=(0,k.witnessStackToScriptWitness)([r,n]);break;case T.ScriptType.P2TR:s=r}return{finalScriptSig:i,finalScriptWitness:s}}(n,t.partialSig);if(o&&d(this,e,"f").updateInput(s,{finalScriptSig:o}),p&&d(this,e,"f").updateInput(s,{finalScriptWitness:p}),!o&&!p)throw new Error(`Unknown error finalizing input #${s}`)})),this}extractTransaction(){const i=d(this,r,"f").clone();d(this,e,"f").inputs.forEach(((e,s)=>d(this,t,"m",c).call(this,i,s,e)));const s=d(this,e,"f").inputs.reduce(((t,e)=>t.plus(e.witnessUtxo.value)),new P.BigNumber(0)),n=i.outs.reduce(((t,e)=>t.plus(e.value)),new P.BigNumber(0)),o=s.minus(n),p=i.virtualSize();if(o.lt(p))throw Error(`Transaction fee must >= ${p}, but got ${o}.`);return i}}function A(t,e){let i,s;const r=(0,k.getPayment)(e);if(t.witnessScript)i=t.witnessScript;else if(t.redeemScript)switch(i=t.redeemScript,s=r.classify(i),s){case T.ScriptType.P2PKH:s=T.ScriptType.P2SH_P2PKH;break;case T.ScriptType.P2WPKH:s=T.ScriptType.P2SH_P2WPKH}else i=t.witnessUtxo.script,s=r.classify(i);return{script:i,scriptType:s}}exports.SecuxPsbt=$,e=new WeakMap,i=new WeakMap,s=new WeakMap,r=new WeakMap,n=new WeakMap,o=new WeakMap,p=new WeakMap,t=new WeakSet,a=function(t){if(d(this,p,"f")[t])return d(this,p,"f")[t];const s=d(this,e,"f").inputs[t],r=s.witnessUtxo,n=A(s,d(this,i,"f")).scriptType,o=function(t,e,i,s){let r;switch(e){case T.ScriptType.P2SH_P2PKH:case T.ScriptType.P2SH_P2WPKH:if(!i)throw Error("scriptPubkey is P2SH but redeemScript missing");r=i;break;default:r=t}if(!r)throw Error("cannot extract script");return r}(r.script,n,s.redeemScript,s.witnessScript);null==B||B.debug(`input #${t} script type: ${T.ScriptType[n]}`),null==B||B.debug(`script: ${o.toString("hex")}`);const a={type:n,scriptPubkey:o};return d(this,p,"f")[t]=a,a},u=function(s){var n,o;const p=d(this,e,"f").inputs[s],u=d(this,r,"f");let c=null!==(n=p.sighashType)&&void 0!==n?n:H.Transaction.SIGHASH_ALL;const h=(0,k.getSerializer)(d(this,i,"f"));void 0===p.witnessUtxo&&Error("Need a Utxo input item for signing");const f=p.witnessUtxo,{type:l,scriptPubkey:S}=d(this,t,"m",a).call(this,s);let g;switch(l){case T.ScriptType.P2WPKH:case T.ScriptType.P2SH_P2WPKH:case T.ScriptType.P2SH_P2PKH:null==B||B.debug(T.ScriptType[l]);const r=(0,k.getPayment)(d(this,i,"f")).p2pkh(d(this,i,"f"),{hash:S.slice(2)}).scriptPublickey;g=h.dataForWitnessV0(u,s,r,f.value,c);break;case T.ScriptType.P2TR:null==B||B.debug("p2tr"),c=null!==(o=p.sighashType)&&void 0!==o?o:H.Transaction.SIGHASH_DEFAULT,g=h.dataForWitnessV1(u,s,d(this,e,"f").inputs.map(((e,i)=>d(this,t,"m",a).call(this,i).scriptPubkey)),d(this,e,"f").inputs.map((t=>t.witnessUtxo.value)),c);break;default:d(this,i,"f")===T.CoinType.BITCOINCASH?(null==B||B.debug("bch using bip143"),g=h.dataForWitnessV0(u,s,S,f.value,64|c)):(null==B||B.debug("non-segwit"),g=h.dataForSignature(u,s,S,c))}return g},c=function(e,i,s){if(!s.finalScriptSig&&!s.finalScriptWitness)throw Error(`input#${i} not finalized.`);s.finalScriptSig&&(e.ins[i].script=s.finalScriptSig),s.finalScriptWitness&&(d(this,t,"m",a).call(this,i).type!==T.ScriptType.P2TR?e.ins[i].witness=(0,k.scriptWitnessToWitnessStack)(s.finalScriptWitness):e.ins[i].witness=[s.finalScriptWitness])},h=function(){const i=d(this,r,"f").clone();let s=0,n=2;return d(this,e,"f").inputs.forEach(((e,i)=>{const{type:r}=d(this,t,"m",a).call(this,i);s+=(0,k.getInScriptSize)(r);const o=(0,k.getWitnessSize)(r,e.sighashType);n+=(0,k.vectorSize)(o)})),i.virtualSize()+s+n/4};class _{constructor(t=Buffer.from([2,0,0,0,0,0,0,0,0,0])){f.set(this,void 0),l(this,f,H.Transaction.fromBuffer(t),"f")}getInputOutputCounts(){return{inputCount:d(this,f,"f").ins.length,outputCount:d(this,f,"f").outs.length}}addInput(t){if(void 0===t.hash||void 0===t.index||!Buffer.isBuffer(t.hash)&&"string"!=typeof t.hash||"number"!=typeof t.index)throw new Error("Error adding input.");const e="string"==typeof t.hash?Buffer.from(Buffer.from(t.hash,"hex").reverse()):t.hash;d(this,f,"f").addInput(e,t.index,t.sequence)}addOutput(t){if(void 0===t.script||void 0===t.value||!Buffer.isBuffer(t.script)||"number"!=typeof t.value)throw new Error("Error adding output.");d(this,f,"f").addOutput(t.script,t.value,t.path)}toBuffer(){return d(this,f,"f").toBuffer()}get tx(){return d(this,f,"f")}}f=new WeakMap; |
@@ -1,205 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.encode = exports.decode = exports.decompile = exports.compile = void 0; | ||
const bip66 = require("bip66"); | ||
const coindef_1 = require("./coindef"); | ||
const utility_1 = require("@secux/utility"); | ||
const ZERO = Buffer.alloc(1, 0); | ||
const logger = utility_1.Logger === null || utility_1.Logger === void 0 ? void 0 : utility_1.Logger.child({ id: "script" }); | ||
function compile(chunks) { | ||
const bufferSize = chunks.reduce((accum, chunk) => { | ||
// data chunk | ||
if (Buffer.isBuffer(chunk)) { | ||
// adhere to BIP62.3, minimal push policy | ||
if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { | ||
return accum + 1; | ||
} | ||
return accum + pushdata.encodingLength(chunk.length) + chunk.length; | ||
} | ||
// opcode | ||
return accum + 1; | ||
}, 0); | ||
const buffer = Buffer.allocUnsafe(bufferSize); | ||
let offset = 0; | ||
for (const chunk of chunks) { | ||
// data chunk | ||
if (Buffer.isBuffer(chunk)) { | ||
// adhere to BIP62.3, minimal push policy | ||
const opcode = asMinimalOP(chunk); | ||
if (opcode !== undefined) { | ||
buffer.writeUInt8(opcode, offset); | ||
offset += 1; | ||
return; | ||
} | ||
offset += pushdata.encode(buffer, chunk.length, offset); | ||
chunk.copy(buffer, offset); | ||
offset += chunk.length; | ||
} | ||
// opcode | ||
else { | ||
buffer.writeUInt8(chunk, offset); | ||
offset += 1; | ||
} | ||
} | ||
if (offset !== buffer.length) | ||
throw new Error('Could not decode chunks'); | ||
return buffer; | ||
} | ||
exports.compile = compile; | ||
function decompile(buffer) { | ||
const chunks = []; | ||
let i = 0; | ||
while (i < buffer.length) { | ||
const opcode = buffer[i]; | ||
// data chunk | ||
if (opcode > coindef_1.OPCODES.OP_0 && opcode <= coindef_1.OPCODES.OP_PUSHDATA4) { | ||
const d = pushdata.decode(buffer, i); | ||
// did reading a pushDataInt fail? | ||
if (d === null) { | ||
logger === null || logger === void 0 ? void 0 : logger.warn(`decompile error: reading a pushDataInt fail, got ${buffer.toString("binary")}, index:${i}`); | ||
return []; | ||
} | ||
i += d.size; | ||
// attempt to read too much data? | ||
if (i + d.number > buffer.length) { | ||
logger === null || logger === void 0 ? void 0 : logger.warn(`decompile error: attempt to read too much data, got ${buffer.slice(i).toString("binary")}, desired length:${d.number}`); | ||
return []; | ||
} | ||
const data = buffer.slice(i, i + d.number); | ||
i += d.number; | ||
// decompile minimally | ||
const op = asMinimalOP(data); | ||
if (op !== undefined) { | ||
chunks.push(op); | ||
} | ||
else { | ||
chunks.push(data); | ||
} | ||
} | ||
// opcode | ||
else { | ||
chunks.push(opcode); | ||
i += 1; | ||
} | ||
} | ||
return chunks; | ||
} | ||
exports.decompile = decompile; | ||
// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) | ||
function decode(buffer) { | ||
const hashType = buffer.readUInt8(buffer.length - 1); | ||
const hashTypeMod = hashType & ~0x80; | ||
if (hashTypeMod <= 0 || hashTypeMod >= 4) | ||
throw new Error('Invalid hashType ' + hashType); | ||
const decoded = bip66.decode(buffer.slice(0, -1)); | ||
const r = fromDER(decoded.r); | ||
const s = fromDER(decoded.s); | ||
const signature = Buffer.concat([r, s], 64); | ||
return { signature, hashType }; | ||
} | ||
exports.decode = decode; | ||
function encode(signature, hashType) { | ||
const hashTypeBuffer = Buffer.allocUnsafe(1); | ||
hashTypeBuffer.writeUInt8(hashType, 0); | ||
const r = toDER(signature.slice(0, 32)); | ||
const s = toDER(signature.slice(32, 64)); | ||
return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); | ||
} | ||
exports.encode = encode; | ||
function toDER(x) { | ||
let i = 0; | ||
while (x[i] === 0) | ||
++i; | ||
if (i === x.length) | ||
return ZERO; | ||
x = x.slice(i); | ||
if (x[0] & 0x80) | ||
return Buffer.concat([ZERO, x], 1 + x.length); | ||
return x; | ||
} | ||
function fromDER(x) { | ||
if (x[0] === 0x00) | ||
x = x.slice(1); | ||
const buffer = Buffer.alloc(32, 0); | ||
const bstart = Math.max(0, 32 - x.length); | ||
x.copy(buffer, bstart); | ||
return buffer; | ||
} | ||
function asMinimalOP(buffer) { | ||
if (buffer.length === 0) | ||
return coindef_1.OPCODES.OP_0; | ||
if (buffer.length !== 1) | ||
return; | ||
if (buffer[0] >= 1 && buffer[0] <= 16) | ||
return coindef_1.OPCODES.OP_INT_BASE + buffer[0]; | ||
if (buffer[0] === 0x81) | ||
return coindef_1.OPCODES.OP_1NEGATE; | ||
} | ||
class pushdata { | ||
static encodingLength(i) { | ||
return i < coindef_1.OPCODES.OP_PUSHDATA1 ? 1 | ||
: i <= 0xff ? 2 | ||
: i <= 0xffff ? 3 | ||
: 5; | ||
} | ||
static encode(buffer, number, offset) { | ||
var size = this.encodingLength(number); | ||
// ~6 bit | ||
if (size === 1) { | ||
buffer.writeUInt8(number, offset); | ||
} | ||
// 8 bit | ||
else if (size === 2) { | ||
buffer.writeUInt8(coindef_1.OPCODES.OP_PUSHDATA1, offset); | ||
buffer.writeUInt8(number, offset + 1); | ||
} | ||
// 16 bit | ||
else if (size === 3) { | ||
buffer.writeUInt8(coindef_1.OPCODES.OP_PUSHDATA2, offset); | ||
buffer.writeUInt16LE(number, offset + 1); | ||
} | ||
// 32 bit | ||
else { | ||
buffer.writeUInt8(coindef_1.OPCODES.OP_PUSHDATA4, offset); | ||
buffer.writeUInt32LE(number, offset + 1); | ||
} | ||
return size; | ||
} | ||
static decode(buffer, offset) { | ||
var opcode = buffer.readUInt8(offset); | ||
var number, size; | ||
// ~6 bit | ||
if (opcode < coindef_1.OPCODES.OP_PUSHDATA1) { | ||
number = opcode; | ||
size = 1; | ||
} | ||
// 8 bit | ||
else if (opcode === coindef_1.OPCODES.OP_PUSHDATA1) { | ||
if (offset + 2 > buffer.length) | ||
return null; | ||
number = buffer.readUInt8(offset + 1); | ||
size = 2; | ||
} | ||
// 16 bit | ||
else if (opcode === coindef_1.OPCODES.OP_PUSHDATA2) { | ||
if (offset + 3 > buffer.length) | ||
return null; | ||
number = buffer.readUInt16LE(offset + 1); | ||
size = 3; | ||
} | ||
// 32 bit | ||
else { | ||
if (offset + 5 > buffer.length) | ||
return null; | ||
if (opcode !== coindef_1.OPCODES.OP_PUSHDATA4) | ||
throw new Error('Unexpected opcode'); | ||
number = buffer.readUInt32LE(offset + 1); | ||
size = 5; | ||
} | ||
return { | ||
opcode: opcode, | ||
number: number, | ||
size: size | ||
}; | ||
} | ||
} | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.encode=exports.decode=exports.decompile=exports.compile=void 0;const e=require("bip66"),t=require("./coindef"),n=require("@secux/utility"),r=Buffer.alloc(1,0),o=null===n.Logger||void 0===n.Logger?void 0:n.Logger.child({id:"script"});function i(e){let t=0;for(;0===e[t];)++t;return t===e.length?r:128&(e=e.slice(t))[0]?Buffer.concat([r,e],1+e.length):e}function c(e){0===e[0]&&(e=e.slice(1));const t=Buffer.alloc(32,0),n=Math.max(0,32-e.length);return e.copy(t,n),t}function l(e){return 0===e.length?t.OPCODES.OP_0:1===e.length?e[0]>=1&&e[0]<=16?t.OPCODES.OP_INT_BASE+e[0]:129===e[0]?t.OPCODES.OP_1NEGATE:void 0:void 0}exports.compile=function(e){const t=e.reduce(((e,t)=>Buffer.isBuffer(t)?1===t.length&&void 0!==l(t)?e+1:e+u.encodingLength(t.length)+t.length:e+1),0),n=Buffer.allocUnsafe(t);let r=0;for(const t of e)if(Buffer.isBuffer(t)){const e=l(t);if(void 0!==e)return n.writeUInt8(e,r),void(r+=1);r+=u.encode(n,t.length,r),t.copy(n,r),r+=t.length}else n.writeUInt8(t,r),r+=1;if(r!==n.length)throw new Error("Could not decode chunks");return n},exports.decompile=function(e){const n=[];let r=0;for(;r<e.length;){const i=e[r];if(i>t.OPCODES.OP_0&&i<=t.OPCODES.OP_PUSHDATA4){const t=u.decode(e,r);if(null===t)return null==o||o.warn(`decompile error: reading a pushDataInt fail, got ${e.toString("binary")}, index:${r}`),[];if(r+=t.size,r+t.number>e.length)return null==o||o.warn(`decompile error: attempt to read too much data, got ${e.slice(r).toString("binary")}, desired length:${t.number}`),[];const i=e.slice(r,r+t.number);r+=t.number;const c=l(i);void 0!==c?n.push(c):n.push(i)}else n.push(i),r+=1}return n},exports.decode=function(t){const n=t.readUInt8(t.length-1),r=-129&n;if(r<=0||r>=4)throw new Error("Invalid hashType "+n);const o=e.decode(t.slice(0,-1)),i=c(o.r),l=c(o.s);return{signature:Buffer.concat([i,l],64),hashType:n}},exports.encode=function(t,n){const r=Buffer.allocUnsafe(1);r.writeUInt8(n,0);const o=i(t.slice(0,32)),c=i(t.slice(32,64));return Buffer.concat([e.encode(o,c),r])};class u{static encodingLength(e){return e<t.OPCODES.OP_PUSHDATA1?1:e<=255?2:e<=65535?3:5}static encode(e,n,r){var o=this.encodingLength(n);return 1===o?e.writeUInt8(n,r):2===o?(e.writeUInt8(t.OPCODES.OP_PUSHDATA1,r),e.writeUInt8(n,r+1)):3===o?(e.writeUInt8(t.OPCODES.OP_PUSHDATA2,r),e.writeUInt16LE(n,r+1)):(e.writeUInt8(t.OPCODES.OP_PUSHDATA4,r),e.writeUInt32LE(n,r+1)),o}static decode(e,n){var r,o,i=e.readUInt8(n);if(i<t.OPCODES.OP_PUSHDATA1)r=i,o=1;else if(i===t.OPCODES.OP_PUSHDATA1){if(n+2>e.length)return null;r=e.readUInt8(n+1),o=2}else if(i===t.OPCODES.OP_PUSHDATA2){if(n+3>e.length)return null;r=e.readUInt16LE(n+1),o=3}else{if(n+5>e.length)return null;if(i!==t.OPCODES.OP_PUSHDATA4)throw new Error("Unexpected opcode");r=e.readUInt32LE(n+1),o=5}return{opcode:i,number:r,size:o}}} |
@@ -1,80 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TransactionGRS = void 0; | ||
const hash_js_1 = require("hash.js"); | ||
const transaction_1 = require("./transaction"); | ||
const bufferutils_1 = require("./bufferutils"); | ||
const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); | ||
class TransactionGRS extends transaction_1.Transaction { | ||
static dataForWitnessV0(trans, inIndex, prevOutScript, value, hashType) { | ||
let tbuffer = Buffer.from([]); | ||
let bufferWriter; | ||
let hashOutputs = ZERO; | ||
let hashPrevouts = ZERO; | ||
let hashSequence = ZERO; | ||
if (!(hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY)) { | ||
tbuffer = Buffer.allocUnsafe(36 * trans.ins.length); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
trans.ins.forEach(txIn => { | ||
bufferWriter.writeSlice(txIn.hash); | ||
bufferWriter.writeUInt32(txIn.index); | ||
}); | ||
hashPrevouts = Buffer.from((0, hash_js_1.sha256)().update(tbuffer).digest()); | ||
} | ||
if (!(hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY) && | ||
(hashType & 0x1f) !== transaction_1.Transaction.SIGHASH_SINGLE && | ||
(hashType & 0x1f) !== transaction_1.Transaction.SIGHASH_NONE) { | ||
tbuffer = Buffer.allocUnsafe(4 * trans.ins.length); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
trans.ins.forEach(txIn => { | ||
bufferWriter.writeUInt32(txIn.sequence); | ||
}); | ||
hashSequence = Buffer.from((0, hash_js_1.sha256)().update(tbuffer).digest()); | ||
} | ||
if ((hashType & 0x1f) !== transaction_1.Transaction.SIGHASH_SINGLE && | ||
(hashType & 0x1f) !== transaction_1.Transaction.SIGHASH_NONE) { | ||
const txOutsSize = trans.outs.reduce((sum, output) => { | ||
return sum + 8 + (0, transaction_1.varSliceSize)(output.script); | ||
}, 0); | ||
tbuffer = Buffer.allocUnsafe(txOutsSize); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
trans.outs.forEach(out => { | ||
bufferWriter.writeUInt64(out.value); | ||
bufferWriter.writeVarSlice(out.script); | ||
}); | ||
hashOutputs = Buffer.from((0, hash_js_1.sha256)().update(tbuffer).digest()); | ||
} | ||
else if ((hashType & 0x1f) === transaction_1.Transaction.SIGHASH_SINGLE && | ||
inIndex < trans.outs.length) { | ||
const output = trans.outs[inIndex]; | ||
tbuffer = Buffer.allocUnsafe(8 + (0, transaction_1.varSliceSize)(output.script)); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
bufferWriter.writeUInt64(output.value); | ||
bufferWriter.writeVarSlice(output.script); | ||
hashOutputs = Buffer.from((0, hash_js_1.sha256)().update(tbuffer).digest()); | ||
} | ||
tbuffer = Buffer.allocUnsafe(156 + (0, transaction_1.varSliceSize)(prevOutScript)); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
const input = trans.ins[inIndex]; | ||
bufferWriter.writeUInt32(trans.version); | ||
bufferWriter.writeSlice(hashPrevouts); | ||
bufferWriter.writeSlice(hashSequence); | ||
bufferWriter.writeSlice(input.hash); | ||
bufferWriter.writeUInt32(input.index); | ||
bufferWriter.writeVarSlice(prevOutScript); | ||
bufferWriter.writeUInt64(value); | ||
bufferWriter.writeUInt32(input.sequence); | ||
bufferWriter.writeSlice(hashOutputs); | ||
bufferWriter.writeUInt32(trans.locktime); | ||
bufferWriter.writeUInt32(hashType); | ||
return tbuffer; | ||
} | ||
static getHash(trans, forWitness) { | ||
// wtxid for coinbase is always 32 bytes of 0x00 | ||
if (forWitness && trans.isCoinbase()) | ||
return Buffer.alloc(32, 0); | ||
const data = trans.toBuffer(undefined, undefined, forWitness); | ||
return Buffer.from((0, hash_js_1.sha256)().update(data).digest()); | ||
} | ||
} | ||
exports.TransactionGRS = TransactionGRS; | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.TransactionGRS=void 0;const e=require("hash.js"),r=require("./transaction"),t=require("./bufferutils"),i=Buffer.from("0000000000000000000000000000000000000000000000000000000000000000","hex");class s extends r.Transaction{static dataForWitnessV0(s,n,a,f,c){let o,u=Buffer.from([]),l=i,S=i,w=i;if(c&r.Transaction.SIGHASH_ANYONECANPAY||(u=Buffer.allocUnsafe(36*s.ins.length),o=new t.BufferWriter(u,0),s.ins.forEach((e=>{o.writeSlice(e.hash),o.writeUInt32(e.index)})),S=Buffer.from((0,e.sha256)().update(u).digest())),c&r.Transaction.SIGHASH_ANYONECANPAY||(31&c)===r.Transaction.SIGHASH_SINGLE||(31&c)===r.Transaction.SIGHASH_NONE||(u=Buffer.allocUnsafe(4*s.ins.length),o=new t.BufferWriter(u,0),s.ins.forEach((e=>{o.writeUInt32(e.sequence)})),w=Buffer.from((0,e.sha256)().update(u).digest())),(31&c)!==r.Transaction.SIGHASH_SINGLE&&(31&c)!==r.Transaction.SIGHASH_NONE){const i=s.outs.reduce(((e,t)=>e+8+(0,r.varSliceSize)(t.script)),0);u=Buffer.allocUnsafe(i),o=new t.BufferWriter(u,0),s.outs.forEach((e=>{o.writeUInt64(e.value),o.writeVarSlice(e.script)})),l=Buffer.from((0,e.sha256)().update(u).digest())}else if((31&c)===r.Transaction.SIGHASH_SINGLE&&n<s.outs.length){const i=s.outs[n];u=Buffer.allocUnsafe(8+(0,r.varSliceSize)(i.script)),o=new t.BufferWriter(u,0),o.writeUInt64(i.value),o.writeVarSlice(i.script),l=Buffer.from((0,e.sha256)().update(u).digest())}u=Buffer.allocUnsafe(156+(0,r.varSliceSize)(a)),o=new t.BufferWriter(u,0);const d=s.ins[n];return o.writeUInt32(s.version),o.writeSlice(S),o.writeSlice(w),o.writeSlice(d.hash),o.writeUInt32(d.index),o.writeVarSlice(a),o.writeUInt64(f),o.writeUInt32(d.sequence),o.writeSlice(l),o.writeUInt32(s.locktime),o.writeUInt32(c),u}static getHash(r,t){if(t&&r.isCoinbase())return Buffer.alloc(32,0);const i=r.toBuffer(void 0,void 0,t);return Buffer.from((0,e.sha256)().update(i).digest())}}exports.TransactionGRS=s; |
@@ -1,475 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.varSliceSize = exports.Transaction = void 0; | ||
const hash_js_1 = require("hash.js"); | ||
const varuint = require("varuint-bitcoin"); | ||
const bufferutils_1 = require("./bufferutils"); | ||
const Script = require("./script"); | ||
const coindef_1 = require("./coindef"); | ||
const utility_1 = require("@secux/utility"); | ||
const logger = utility_1.Logger === null || utility_1.Logger === void 0 ? void 0 : utility_1.Logger.child({ id: "transaction" }); | ||
const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); | ||
const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'); | ||
const EMPTY = Buffer.alloc(0); | ||
const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); | ||
const BLANK_OUTPUT = { | ||
script: EMPTY, | ||
valueBuffer: VALUE_UINT64_MAX, | ||
value: 0 | ||
}; | ||
class Transaction { | ||
constructor() { | ||
this.ins = []; | ||
this.outs = []; | ||
this.version = 2; | ||
this.locktime = 0; | ||
} | ||
static fromBuffer(buffer) { | ||
const bufferReader = new bufferutils_1.BufferReader(buffer); | ||
const tx = new Transaction(); | ||
tx.version = bufferReader.readInt32(); | ||
const marker = bufferReader.readUInt8(); | ||
const flag = bufferReader.readUInt8(); | ||
let hasWitnesses = false; | ||
if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && | ||
flag === Transaction.ADVANCED_TRANSACTION_FLAG) { | ||
hasWitnesses = true; | ||
} | ||
else { | ||
bufferReader.offset -= 2; | ||
} | ||
const vinLen = bufferReader.readVarInt(); | ||
for (let i = 0; i < vinLen; ++i) { | ||
tx.ins.push({ | ||
hash: bufferReader.readSlice(32), | ||
index: bufferReader.readUInt32(), | ||
script: bufferReader.readVarSlice(), | ||
sequence: bufferReader.readUInt32(), | ||
witness: [], | ||
}); | ||
} | ||
const voutLen = bufferReader.readVarInt(); | ||
for (let i = 0; i < voutLen; ++i) { | ||
tx.outs.push({ | ||
value: bufferReader.readUInt64(), | ||
script: bufferReader.readVarSlice(), | ||
}); | ||
} | ||
if (hasWitnesses) { | ||
for (let i = 0; i < vinLen; ++i) { | ||
tx.ins[i].witness = bufferReader.readVector(); | ||
} | ||
// was this pointless? | ||
if (!tx.hasWitnesses()) | ||
throw new Error('Transaction has superfluous witness data'); | ||
} | ||
tx.locktime = bufferReader.readUInt32(); | ||
if (bufferReader.offset !== buffer.length) | ||
throw new Error('Transaction has unexpected data'); | ||
return tx; | ||
} | ||
static dataForSignature(trans, inIndex, prevOutScript, hashType) { | ||
// https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 | ||
if (inIndex >= trans.ins.length) | ||
return ONE; | ||
// ignore OP_CODESEPARATOR | ||
const ourScript = Script.compile(Script.decompile(prevOutScript).filter(x => { | ||
return x !== coindef_1.OPCODES.OP_CODESEPARATOR; | ||
})); | ||
const txTmp = trans.clone(); | ||
// SIGHASH_NONE: ignore all outputs? (wildcard payee) | ||
if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { | ||
txTmp.outs = []; | ||
// ignore sequence numbers (except at inIndex) | ||
txTmp.ins.forEach((input, i) => { | ||
if (i === inIndex) | ||
return; | ||
input.sequence = 0; | ||
}); | ||
// SIGHASH_SINGLE: ignore all outputs, except at the same index? | ||
} | ||
else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { | ||
// https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 | ||
if (inIndex >= trans.outs.length) | ||
return ONE; | ||
// truncate outputs after | ||
txTmp.outs.length = inIndex + 1; | ||
// "blank" outputs before | ||
for (let i = 0; i < inIndex; i++) { | ||
txTmp.outs[i] = BLANK_OUTPUT; | ||
} | ||
// ignore sequence numbers (except at inIndex) | ||
txTmp.ins.forEach((input, y) => { | ||
if (y === inIndex) | ||
return; | ||
input.sequence = 0; | ||
}); | ||
} | ||
// SIGHASH_ANYONECANPAY: ignore inputs entirely? | ||
if (hashType & Transaction.SIGHASH_ANYONECANPAY) { | ||
txTmp.ins = [txTmp.ins[inIndex]]; | ||
txTmp.ins[0].script = ourScript; | ||
// SIGHASH_ALL: only ignore input scripts | ||
} | ||
else { | ||
// "blank" others input scripts | ||
txTmp.ins.forEach(input => { | ||
input.script = EMPTY; | ||
}); | ||
txTmp.ins[inIndex].script = ourScript; | ||
} | ||
// serialize and hash | ||
const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); | ||
buffer.writeInt32LE(hashType, buffer.length - 4); | ||
txTmp.toBuffer(buffer, 0, false); | ||
return buffer; | ||
} | ||
static dataForWitnessV0(trans, inIndex, prevOutScript, value, hashType) { | ||
let tbuffer = Buffer.from([]); | ||
let bufferWriter; | ||
let hashOutputs = ZERO; | ||
let hashPrevouts = ZERO; | ||
let hashSequence = ZERO; | ||
logger === null || logger === void 0 ? void 0 : logger.debug("begin dataForWitnessV0"); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`hashType: 0x${hashType.toString(16)}`); | ||
if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { | ||
tbuffer = Buffer.allocUnsafe(36 * trans.ins.length); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
trans.ins.forEach(txIn => { | ||
bufferWriter.writeSlice(txIn.hash); | ||
bufferWriter.writeUInt32(txIn.index); | ||
}); | ||
hashPrevouts = hash256(tbuffer); | ||
} | ||
if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && | ||
(hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && | ||
(hashType & 0x1f) !== Transaction.SIGHASH_NONE) { | ||
tbuffer = Buffer.allocUnsafe(4 * trans.ins.length); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
trans.ins.forEach(txIn => { | ||
bufferWriter.writeUInt32(txIn.sequence); | ||
}); | ||
hashSequence = hash256(tbuffer); | ||
} | ||
if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && | ||
(hashType & 0x1f) !== Transaction.SIGHASH_NONE) { | ||
const txOutsSize = trans.outs.reduce((sum, output) => { | ||
return sum + 8 + varSliceSize(output.script); | ||
}, 0); | ||
tbuffer = Buffer.allocUnsafe(txOutsSize); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
trans.outs.forEach(out => { | ||
bufferWriter.writeUInt64(out.value); | ||
bufferWriter.writeVarSlice(out.script); | ||
}); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`outputs: ${tbuffer.toString("hex")}`); | ||
hashOutputs = hash256(tbuffer); | ||
} | ||
else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && | ||
inIndex < trans.outs.length) { | ||
const output = trans.outs[inIndex]; | ||
tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
bufferWriter.writeUInt64(output.value); | ||
bufferWriter.writeVarSlice(output.script); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`single output: ${tbuffer.toString("hex")}`); | ||
hashOutputs = hash256(tbuffer); | ||
} | ||
tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); | ||
bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); | ||
const input = trans.ins[inIndex]; | ||
bufferWriter.writeUInt32(trans.version); | ||
bufferWriter.writeSlice(hashPrevouts); | ||
bufferWriter.writeSlice(hashSequence); | ||
bufferWriter.writeSlice(input.hash); | ||
bufferWriter.writeUInt32(input.index); | ||
bufferWriter.writeVarSlice(prevOutScript); | ||
bufferWriter.writeUInt64(value); | ||
bufferWriter.writeUInt32(input.sequence); | ||
bufferWriter.writeSlice(hashOutputs); | ||
bufferWriter.writeUInt32(trans.locktime); | ||
bufferWriter.writeUInt32(hashType); | ||
logger === null || logger === void 0 ? void 0 : logger.debug("end dataForWitnessV0"); | ||
return tbuffer; | ||
} | ||
static dataForWitnessV1(trans, inIndex, prevOutScripts, values, hashType, leafHash, annex) { | ||
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message | ||
if (values.length !== trans.ins.length || | ||
prevOutScripts.length !== trans.ins.length) { | ||
throw new Error('Must supply prevout script and value for all inputs'); | ||
} | ||
const outputType = (hashType === Transaction.SIGHASH_DEFAULT) ? Transaction.SIGHASH_ALL | ||
: hashType & Transaction.SIGHASH_OUTPUT_MASK; | ||
const inputType = hashType & Transaction.SIGHASH_INPUT_MASK; | ||
const isAnyoneCanPay = inputType === Transaction.SIGHASH_ANYONECANPAY; | ||
const isNone = outputType === Transaction.SIGHASH_NONE; | ||
const isSingle = outputType === Transaction.SIGHASH_SINGLE; | ||
let hashPrevouts = EMPTY; | ||
let hashAmounts = EMPTY; | ||
let hashScriptPubKeys = EMPTY; | ||
let hashSequences = EMPTY; | ||
let hashOutputs = EMPTY; | ||
logger === null || logger === void 0 ? void 0 : logger.debug("begin dataForWitnessV1"); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`hashType: 0x${hashType.toString(16)}`); | ||
if (!isAnyoneCanPay) { | ||
let buf = Buffer.alloc(36 * trans.ins.length); | ||
let bufferWriter = new bufferutils_1.BufferWriter(buf); | ||
trans.ins.forEach(txIn => { | ||
bufferWriter.writeSlice(txIn.hash); | ||
bufferWriter.writeUInt32(txIn.index); | ||
}); | ||
hashPrevouts = _sha256(buf); | ||
buf = Buffer.alloc(8 * trans.ins.length); | ||
bufferWriter = new bufferutils_1.BufferWriter(buf); | ||
values.forEach(value => bufferWriter.writeUInt64(value)); | ||
hashAmounts = _sha256(buf); | ||
buf = Buffer.alloc(prevOutScripts.map(varSliceSize).reduce((a, b) => a + b)); | ||
bufferWriter = new bufferutils_1.BufferWriter(buf); | ||
prevOutScripts.forEach(prevOutScript => bufferWriter.writeVarSlice(prevOutScript)); | ||
hashScriptPubKeys = _sha256(buf); | ||
buf = Buffer.alloc(4 * trans.ins.length); | ||
bufferWriter = new bufferutils_1.BufferWriter(buf); | ||
trans.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); | ||
hashSequences = _sha256(buf); | ||
} | ||
if (!(isNone || isSingle)) { | ||
const txOutsSize = trans.outs | ||
.map(output => 8 + varSliceSize(output.script)) | ||
.reduce((a, b) => a + b); | ||
const buf = Buffer.alloc(txOutsSize); | ||
const bufferWriter = new bufferutils_1.BufferWriter(buf); | ||
trans.outs.forEach(out => { | ||
bufferWriter.writeUInt64(out.value); | ||
bufferWriter.writeVarSlice(out.script); | ||
}); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`outputs: ${buf.toString("hex")}`); | ||
hashOutputs = _sha256(buf); | ||
} | ||
else if (isSingle && inIndex < trans.outs.length) { | ||
const output = trans.outs[inIndex]; | ||
const buf = Buffer.alloc(8 + varSliceSize(output.script)); | ||
const bufferWriter = new bufferutils_1.BufferWriter(buf); | ||
bufferWriter.writeUInt64(output.value); | ||
bufferWriter.writeVarSlice(output.script); | ||
logger === null || logger === void 0 ? void 0 : logger.debug(`single output: ${buf.toString("hex")}`); | ||
hashOutputs = _sha256(buf); | ||
} | ||
const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); | ||
// Length calculation from: | ||
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-14 | ||
// With extension from: | ||
// https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#signature-validation | ||
const sigMsgSize = 174 - | ||
(isAnyoneCanPay ? 49 : 0) - | ||
(isNone ? 32 : 0) + | ||
(annex ? 32 : 0) + | ||
(leafHash ? 37 : 0); | ||
const buf = Buffer.alloc(sigMsgSize); | ||
const sigMsgWriter = new bufferutils_1.BufferWriter(buf); | ||
sigMsgWriter.writeUInt8(hashType); | ||
// Transaction | ||
sigMsgWriter.writeInt32(trans.version); | ||
sigMsgWriter.writeUInt32(trans.locktime); | ||
sigMsgWriter.writeSlice(hashPrevouts); | ||
sigMsgWriter.writeSlice(hashAmounts); | ||
sigMsgWriter.writeSlice(hashScriptPubKeys); | ||
sigMsgWriter.writeSlice(hashSequences); | ||
if (!(isNone || isSingle)) { | ||
sigMsgWriter.writeSlice(hashOutputs); | ||
} | ||
// Input | ||
sigMsgWriter.writeUInt8(spendType); | ||
if (isAnyoneCanPay) { | ||
const input = trans.ins[inIndex]; | ||
sigMsgWriter.writeSlice(input.hash); | ||
sigMsgWriter.writeUInt32(input.index); | ||
sigMsgWriter.writeUInt64(values[inIndex]); | ||
sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); | ||
sigMsgWriter.writeUInt32(input.sequence); | ||
} | ||
else { | ||
sigMsgWriter.writeUInt32(inIndex); | ||
} | ||
if (annex) { | ||
const buf = Buffer.alloc(varSliceSize(annex)); | ||
const bufferWriter = new bufferutils_1.BufferWriter(buf); | ||
bufferWriter.writeVarSlice(annex); | ||
sigMsgWriter.writeSlice(_sha256(buf)); | ||
} | ||
// Output | ||
if (isSingle) { | ||
sigMsgWriter.writeSlice(hashOutputs); | ||
} | ||
// BIP342 extension | ||
if (leafHash) { | ||
sigMsgWriter.writeSlice(leafHash); | ||
sigMsgWriter.writeUInt8(0); | ||
sigMsgWriter.writeUInt32(0xffffffff); | ||
} | ||
logger === null || logger === void 0 ? void 0 : logger.debug("end dataForWitnessV1"); | ||
// Extra zero byte because: | ||
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 | ||
return Buffer.concat([Buffer.from([0x00]), buf]); | ||
} | ||
static getHash(trans, forWitness) { | ||
// wtxid for coinbase is always 32 bytes of 0x00 | ||
if (forWitness && trans.isCoinbase()) | ||
return Buffer.alloc(32, 0); | ||
return hash256(trans.toBuffer(undefined, undefined, forWitness)); | ||
} | ||
static getId(trans) { | ||
return this.getHash(trans).reverse().toString("hex"); | ||
} | ||
addInput(hash, index, sequence, scriptSig) { | ||
if (!sequence || sequence === 0) | ||
sequence = Transaction.DEFAULT_SEQUENCE; | ||
this.ins.push({ | ||
hash, | ||
index, | ||
script: scriptSig !== null && scriptSig !== void 0 ? scriptSig : EMPTY, | ||
sequence: sequence, | ||
witness: [], | ||
}); | ||
} | ||
addOutput(scriptPubKey, value, path) { | ||
this.outs.push({ | ||
script: scriptPubKey, | ||
value, | ||
path | ||
}); | ||
} | ||
toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) { | ||
if (!buffer) | ||
buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)); | ||
const bufferWriter = new bufferutils_1.BufferWriter(buffer, initialOffset !== null && initialOffset !== void 0 ? initialOffset : 0); | ||
bufferWriter.writeInt32(this.version); | ||
const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); | ||
if (hasWitnesses) { | ||
bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); | ||
bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); | ||
} | ||
bufferWriter.writeVarInt(this.ins.length); | ||
this.ins.forEach(txIn => { | ||
bufferWriter.writeSlice(txIn.hash); | ||
bufferWriter.writeUInt32(txIn.index); | ||
bufferWriter.writeVarSlice(txIn.script); | ||
bufferWriter.writeUInt32(txIn.sequence); | ||
}); | ||
bufferWriter.writeVarInt(this.outs.length); | ||
this.outs.forEach(txOut => { | ||
if (txOut.value !== undefined) { | ||
bufferWriter.writeUInt64(txOut.value); | ||
} | ||
else { | ||
//@ts-ignore | ||
bufferWriter.writeSlice(txOut.valueBuffer); | ||
} | ||
bufferWriter.writeVarSlice(txOut.script); | ||
}); | ||
if (hasWitnesses) { | ||
this.ins.forEach(input => { | ||
bufferWriter.writeVector(input.witness); | ||
}); | ||
} | ||
bufferWriter.writeUInt32(this.locktime); | ||
// avoid slicing unless necessary | ||
if (initialOffset !== undefined) | ||
return buffer.slice(initialOffset, bufferWriter.offset); | ||
return buffer; | ||
} | ||
toHex() { | ||
return this.toBuffer(undefined, undefined, true).toString('hex'); | ||
} | ||
hasWitnesses() { | ||
return this.ins.some(x => { | ||
return x.witness.length !== 0; | ||
}); | ||
} | ||
isCoinbase() { | ||
if (this.ins.length !== 1) | ||
return false; | ||
const hash = this.ins[0].hash; | ||
for (let i = 0; i < 32; ++i) { | ||
if (hash[i] !== 0) | ||
return false; | ||
} | ||
return true; | ||
} | ||
clone() { | ||
const newTx = new Transaction(); | ||
newTx.version = this.version; | ||
newTx.locktime = this.locktime; | ||
newTx.ins = this.ins.map(txIn => { | ||
return { | ||
hash: txIn.hash, | ||
index: txIn.index, | ||
script: txIn.script, | ||
sequence: txIn.sequence, | ||
witness: txIn.witness, | ||
}; | ||
}); | ||
newTx.outs = this.outs.map(txOut => { | ||
return { | ||
script: txOut.script, | ||
value: txOut.value, | ||
}; | ||
}); | ||
return newTx; | ||
} | ||
weight() { | ||
const base = this.byteLength(false); | ||
const total = this.byteLength(true); | ||
return base * 3 + total; | ||
} | ||
virtualSize() { | ||
return Math.ceil(this.weight() / 4); | ||
} | ||
byteLength(_ALLOW_WITNESS = true) { | ||
const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); | ||
return ((hasWitnesses ? 10 : 8) + | ||
varuint.encodingLength(this.ins.length) + | ||
varuint.encodingLength(this.outs.length) + | ||
this.ins.reduce((sum, input) => { | ||
return sum + 40 + varSliceSize(input.script); | ||
}, 0) + | ||
this.outs.reduce((sum, output) => { | ||
return sum + 8 + varSliceSize(output.script); | ||
}, 0) + | ||
(hasWitnesses | ||
? this.ins.reduce((sum, input) => { | ||
return sum + vectorSize(input.witness); | ||
}, 0) | ||
: 0)); | ||
} | ||
} | ||
exports.Transaction = Transaction; | ||
Transaction.DEFAULT_SEQUENCE = 0xffffffff; | ||
Transaction.SIGHASH_DEFAULT = 0x00; | ||
Transaction.SIGHASH_ALL = 0x01; | ||
Transaction.SIGHASH_NONE = 0x02; | ||
Transaction.SIGHASH_SINGLE = 0x03; | ||
Transaction.SIGHASH_ANYONECANPAY = 0x80; | ||
Transaction.SIGHASH_OUTPUT_MASK = 0x03; | ||
Transaction.SIGHASH_INPUT_MASK = 0x80; | ||
Transaction.ADVANCED_TRANSACTION_MARKER = 0x00; | ||
Transaction.ADVANCED_TRANSACTION_FLAG = 0x01; | ||
function _sha256(data) { | ||
return Buffer.from((0, hash_js_1.sha256)().update(data).digest()); | ||
} | ||
function hash256(data) { | ||
const hash1 = (0, hash_js_1.sha256)().update(data).digest(); | ||
const hash2 = (0, hash_js_1.sha256)().update(hash1).digest(); | ||
return Buffer.from(hash2); | ||
} | ||
function varSliceSize(someScript) { | ||
const length = someScript.length; | ||
return varuint.encodingLength(length) + length; | ||
} | ||
exports.varSliceSize = varSliceSize; | ||
function vectorSize(someVector) { | ||
const length = someVector.length; | ||
return (varuint.encodingLength(length) + | ||
someVector.reduce((sum, witness) => { | ||
return sum + varSliceSize(witness); | ||
}, 0)); | ||
} | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.varSliceSize=exports.Transaction=void 0;const e=require("hash.js"),t=require("varuint-bitcoin"),r=require("./bufferutils"),i=require("./script"),n=require("./coindef"),s=require("@secux/utility"),u=null===s.Logger||void 0===s.Logger?void 0:s.Logger.child({id:"transaction"}),o=Buffer.from("0000000000000000000000000000000000000000000000000000000000000000","hex"),f=Buffer.from("0000000000000000000000000000000000000000000000000000000000000001","hex"),c=Buffer.alloc(0),l=Buffer.from("ffffffffffffffff","hex"),a={script:c,valueBuffer:l,value:0};class h{constructor(){this.ins=[],this.outs=[],this.version=2,this.locktime=0}static fromBuffer(e){const t=new r.BufferReader(e),i=new h;i.version=t.readInt32();const n=t.readUInt8(),s=t.readUInt8();let u=!1;n===h.ADVANCED_TRANSACTION_MARKER&&s===h.ADVANCED_TRANSACTION_FLAG?u=!0:t.offset-=2;const o=t.readVarInt();for(let e=0;e<o;++e)i.ins.push({hash:t.readSlice(32),index:t.readUInt32(),script:t.readVarSlice(),sequence:t.readUInt32(),witness:[]});const f=t.readVarInt();for(let e=0;e<f;++e)i.outs.push({value:t.readUInt64(),script:t.readVarSlice()});if(u){for(let e=0;e<o;++e)i.ins[e].witness=t.readVector();if(!i.hasWitnesses())throw new Error("Transaction has superfluous witness data")}if(i.locktime=t.readUInt32(),t.offset!==e.length)throw new Error("Transaction has unexpected data");return i}static dataForSignature(e,t,r,s){if(t>=e.ins.length)return f;const u=i.compile(i.decompile(r).filter((e=>e!==n.OPCODES.OP_CODESEPARATOR))),o=e.clone();if((31&s)===h.SIGHASH_NONE)o.outs=[],o.ins.forEach(((e,r)=>{r!==t&&(e.sequence=0)}));else if((31&s)===h.SIGHASH_SINGLE){if(t>=e.outs.length)return f;o.outs.length=t+1;for(let e=0;e<t;e++)o.outs[e]=a;o.ins.forEach(((e,r)=>{r!==t&&(e.sequence=0)}))}s&h.SIGHASH_ANYONECANPAY?(o.ins=[o.ins[t]],o.ins[0].script=u):(o.ins.forEach((e=>{e.script=c})),o.ins[t].script=u);const l=Buffer.allocUnsafe(o.byteLength(!1)+4);return l.writeInt32LE(s,l.length-4),o.toBuffer(l,0,!1),l}static dataForWitnessV0(e,t,i,n,s){let f,c=Buffer.from([]),l=o,a=o,S=o;if(null==u||u.debug("begin dataForWitnessV0"),null==u||u.debug(`hashType: 0x${s.toString(16)}`),s&h.SIGHASH_ANYONECANPAY||(c=Buffer.allocUnsafe(36*e.ins.length),f=new r.BufferWriter(c,0),e.ins.forEach((e=>{f.writeSlice(e.hash),f.writeUInt32(e.index)})),a=w(c)),s&h.SIGHASH_ANYONECANPAY||(31&s)===h.SIGHASH_SINGLE||(31&s)===h.SIGHASH_NONE||(c=Buffer.allocUnsafe(4*e.ins.length),f=new r.BufferWriter(c,0),e.ins.forEach((e=>{f.writeUInt32(e.sequence)})),S=w(c)),(31&s)!==h.SIGHASH_SINGLE&&(31&s)!==h.SIGHASH_NONE){const t=e.outs.reduce(((e,t)=>e+8+I(t.script)),0);c=Buffer.allocUnsafe(t),f=new r.BufferWriter(c,0),e.outs.forEach((e=>{f.writeUInt64(e.value),f.writeVarSlice(e.script)})),null==u||u.debug(`outputs: ${c.toString("hex")}`),l=w(c)}else if((31&s)===h.SIGHASH_SINGLE&&t<e.outs.length){const i=e.outs[t];c=Buffer.allocUnsafe(8+I(i.script)),f=new r.BufferWriter(c,0),f.writeUInt64(i.value),f.writeVarSlice(i.script),null==u||u.debug(`single output: ${c.toString("hex")}`),l=w(c)}c=Buffer.allocUnsafe(156+I(i)),f=new r.BufferWriter(c,0);const d=e.ins[t];return f.writeUInt32(e.version),f.writeSlice(a),f.writeSlice(S),f.writeSlice(d.hash),f.writeUInt32(d.index),f.writeVarSlice(i),f.writeUInt64(n),f.writeUInt32(d.sequence),f.writeSlice(l),f.writeUInt32(e.locktime),f.writeUInt32(s),null==u||u.debug("end dataForWitnessV0"),c}static dataForWitnessV1(e,t,i,n,s,o,f){if(n.length!==e.ins.length||i.length!==e.ins.length)throw new Error("Must supply prevout script and value for all inputs");const l=s===h.SIGHASH_DEFAULT?h.SIGHASH_ALL:s&h.SIGHASH_OUTPUT_MASK,a=(s&h.SIGHASH_INPUT_MASK)===h.SIGHASH_ANYONECANPAY,w=l===h.SIGHASH_NONE,d=l===h.SIGHASH_SINGLE;let A=c,g=c,p=c,E=c,U=c;if(null==u||u.debug("begin dataForWitnessV1"),null==u||u.debug(`hashType: 0x${s.toString(16)}`),!a){let t=Buffer.alloc(36*e.ins.length),s=new r.BufferWriter(t);e.ins.forEach((e=>{s.writeSlice(e.hash),s.writeUInt32(e.index)})),A=S(t),t=Buffer.alloc(8*e.ins.length),s=new r.BufferWriter(t),n.forEach((e=>s.writeUInt64(e))),g=S(t),t=Buffer.alloc(i.map(I).reduce(((e,t)=>e+t))),s=new r.BufferWriter(t),i.forEach((e=>s.writeVarSlice(e))),p=S(t),t=Buffer.alloc(4*e.ins.length),s=new r.BufferWriter(t),e.ins.forEach((e=>s.writeUInt32(e.sequence))),E=S(t)}if(w||d){if(d&&t<e.outs.length){const i=e.outs[t],n=Buffer.alloc(8+I(i.script)),s=new r.BufferWriter(n);s.writeUInt64(i.value),s.writeVarSlice(i.script),null==u||u.debug(`single output: ${n.toString("hex")}`),U=S(n)}}else{const t=e.outs.map((e=>8+I(e.script))).reduce(((e,t)=>e+t)),i=Buffer.alloc(t),n=new r.BufferWriter(i);e.outs.forEach((e=>{n.writeUInt64(e.value),n.writeVarSlice(e.script)})),null==u||u.debug(`outputs: ${i.toString("hex")}`),U=S(i)}const N=(o?2:0)+(f?1:0),H=174-(a?49:0)-(w?32:0)+(f?32:0)+(o?37:0),B=Buffer.alloc(H),_=new r.BufferWriter(B);if(_.writeUInt8(s),_.writeInt32(e.version),_.writeUInt32(e.locktime),_.writeSlice(A),_.writeSlice(g),_.writeSlice(p),_.writeSlice(E),w||d||_.writeSlice(U),_.writeUInt8(N),a){const r=e.ins[t];_.writeSlice(r.hash),_.writeUInt32(r.index),_.writeUInt64(n[t]),_.writeVarSlice(i[t]),_.writeUInt32(r.sequence)}else _.writeUInt32(t);if(f){const e=Buffer.alloc(I(f));new r.BufferWriter(e).writeVarSlice(f),_.writeSlice(S(e))}return d&&_.writeSlice(U),o&&(_.writeSlice(o),_.writeUInt8(0),_.writeUInt32(4294967295)),null==u||u.debug("end dataForWitnessV1"),Buffer.concat([Buffer.from([0]),B])}static getHash(e,t){return t&&e.isCoinbase()?Buffer.alloc(32,0):w(e.toBuffer(void 0,void 0,t))}static getId(e){return this.getHash(e).reverse().toString("hex")}addInput(e,t,r,i){r&&0!==r||(r=h.DEFAULT_SEQUENCE),this.ins.push({hash:e,index:t,script:null!=i?i:c,sequence:r,witness:[]})}addOutput(e,t,r){this.outs.push({script:e,value:t,path:r})}toBuffer(e,t,i=!1){e||(e=Buffer.allocUnsafe(this.byteLength(i)));const n=new r.BufferWriter(e,null!=t?t:0);n.writeInt32(this.version);const s=i&&this.hasWitnesses();return s&&(n.writeUInt8(h.ADVANCED_TRANSACTION_MARKER),n.writeUInt8(h.ADVANCED_TRANSACTION_FLAG)),n.writeVarInt(this.ins.length),this.ins.forEach((e=>{n.writeSlice(e.hash),n.writeUInt32(e.index),n.writeVarSlice(e.script),n.writeUInt32(e.sequence)})),n.writeVarInt(this.outs.length),this.outs.forEach((e=>{void 0!==e.value?n.writeUInt64(e.value):n.writeSlice(e.valueBuffer),n.writeVarSlice(e.script)})),s&&this.ins.forEach((e=>{n.writeVector(e.witness)})),n.writeUInt32(this.locktime),void 0!==t?e.slice(t,n.offset):e}toHex(){return this.toBuffer(void 0,void 0,!0).toString("hex")}hasWitnesses(){return this.ins.some((e=>0!==e.witness.length))}isCoinbase(){if(1!==this.ins.length)return!1;const e=this.ins[0].hash;for(let t=0;t<32;++t)if(0!==e[t])return!1;return!0}clone(){const e=new h;return e.version=this.version,e.locktime=this.locktime,e.ins=this.ins.map((e=>({hash:e.hash,index:e.index,script:e.script,sequence:e.sequence,witness:e.witness}))),e.outs=this.outs.map((e=>({script:e.script,value:e.value}))),e}weight(){return 3*this.byteLength(!1)+this.byteLength(!0)}virtualSize(){return Math.ceil(this.weight()/4)}byteLength(e=!0){const r=e&&this.hasWitnesses();return(r?10:8)+t.encodingLength(this.ins.length)+t.encodingLength(this.outs.length)+this.ins.reduce(((e,t)=>e+40+I(t.script)),0)+this.outs.reduce(((e,t)=>e+8+I(t.script)),0)+(r?this.ins.reduce(((e,r)=>e+function(e){const r=e.length;return t.encodingLength(r)+e.reduce(((e,t)=>e+I(t)),0)}(r.witness)),0):0)}}function S(t){return Buffer.from((0,e.sha256)().update(t).digest())}function w(t){const r=(0,e.sha256)().update(t).digest(),i=(0,e.sha256)().update(r).digest();return Buffer.from(i)}function I(e){const r=e.length;return t.encodingLength(r)+r}exports.Transaction=h,h.DEFAULT_SEQUENCE=4294967295,h.SIGHASH_DEFAULT=0,h.SIGHASH_ALL=1,h.SIGHASH_NONE=2,h.SIGHASH_SINGLE=3,h.SIGHASH_ANYONECANPAY=128,h.SIGHASH_OUTPUT_MASK=3,h.SIGHASH_INPUT_MASK=128,h.ADVANCED_TRANSACTION_MARKER=0,h.ADVANCED_TRANSACTION_FLAG=1,exports.varSliceSize=I; |
184
lib/utils.js
@@ -1,183 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.taggedHash = exports.toTweakedPublickey = exports.getPublickey = exports.scriptWitnessToWitnessStack = exports.witnessStackToScriptWitness = exports.vectorSize = exports.sliceSize = exports.getOutScriptSize = exports.getWitnessSize = exports.getInScriptSize = exports.getSerializer = exports.getDefaultScript = exports.getPurpose = exports.getCoinType = exports.getPayment = void 0; | ||
const secp256k1 = require('secp256k1/elliptic'); | ||
const varuint = require("varuint-bitcoin"); | ||
const interface_1 = require("./interface"); | ||
const payment_1 = require("./payment"); | ||
const payment_bch_1 = require("./payment_bch"); | ||
const payment_grs_1 = require("./payment_grs"); | ||
const transaction_1 = require("./transaction"); | ||
const transaction_grs_1 = require("./transaction_grs"); | ||
const ow_1 = require("ow"); | ||
const hash_js_1 = require("hash.js"); | ||
const bip340_1 = require("./bip340"); | ||
function getPayment(coin) { | ||
switch (coin) { | ||
case interface_1.CoinType.BITCOINCASH: | ||
return payment_bch_1.PaymentBCH; | ||
case interface_1.CoinType.GROESTL: | ||
return payment_grs_1.PaymentGRS; | ||
default: | ||
return payment_1.PaymentBTC; | ||
} | ||
} | ||
exports.getPayment = getPayment; | ||
function getCoinType(path) { | ||
const bip32 = path.match(/\d+/g); | ||
const cointype = parseInt(bip32[1], 10); | ||
for (let i = 0; i < interface_1.coinmap.length; i++) { | ||
if (cointype === interface_1.coinmap[i].coinType) | ||
return i; | ||
} | ||
throw Error(`ArgumentError: unsupport cointype of BIP32 path, got ${path}`); | ||
} | ||
exports.getCoinType = getCoinType; | ||
function getPurpose(script) { | ||
switch (script) { | ||
case interface_1.ScriptType.P2PKH: return 44; | ||
case interface_1.ScriptType.P2SH_P2PKH: return 49; | ||
case interface_1.ScriptType.P2SH_P2WPKH: return 49; | ||
case interface_1.ScriptType.P2WPKH: return 84; | ||
case interface_1.ScriptType.P2TR: return 86; | ||
} | ||
throw Error(`ArgumentError: unsupport ScriptType, got ${script}`); | ||
} | ||
exports.getPurpose = getPurpose; | ||
function getDefaultScript(path) { | ||
const bip32 = path.match(/\d+/g); | ||
const purpose = parseInt(bip32[0], 10); | ||
const coin = bip32[1] ? getCoinType(path) : interface_1.CoinType.BITCOIN; | ||
switch (purpose) { | ||
case 44: return interface_1.ScriptType.P2PKH; | ||
case 49: return (coin !== interface_1.CoinType.BITCOINCASH) ? interface_1.ScriptType.P2SH_P2WPKH : interface_1.ScriptType.P2SH_P2PKH; | ||
case 84: return interface_1.ScriptType.P2WPKH; | ||
case 86: return interface_1.ScriptType.P2TR; | ||
} | ||
throw Error(`ArgumentError: unsupport purpose of path, got "${purpose}" from ${path}`); | ||
} | ||
exports.getDefaultScript = getDefaultScript; | ||
function getSerializer(coin) { | ||
switch (coin) { | ||
case interface_1.CoinType.GROESTL: | ||
return transaction_grs_1.TransactionGRS; | ||
default: | ||
return transaction_1.Transaction; | ||
} | ||
} | ||
exports.getSerializer = getSerializer; | ||
function getInScriptSize(type) { | ||
switch (type) { | ||
case interface_1.ScriptType.P2PKH: | ||
case interface_1.ScriptType.P2SH_P2PKH: return 107; | ||
case interface_1.ScriptType.P2SH_P2WPKH: return 23; | ||
} | ||
return 0; | ||
} | ||
exports.getInScriptSize = getInScriptSize; | ||
function getWitnessSize(type, sighashType = transaction_1.Transaction.SIGHASH_DEFAULT) { | ||
switch (type) { | ||
case interface_1.ScriptType.P2SH_P2WPKH: | ||
case interface_1.ScriptType.P2WPKH: return [72, 33]; | ||
case interface_1.ScriptType.P2TR: return (sighashType === transaction_1.Transaction.SIGHASH_DEFAULT) ? [64] : [65]; | ||
} | ||
return []; | ||
} | ||
exports.getWitnessSize = getWitnessSize; | ||
function getOutScriptSize(type) { | ||
switch (type) { | ||
case interface_1.ScriptType.P2PKH: return 25; | ||
case interface_1.ScriptType.P2SH_P2PKH: | ||
case interface_1.ScriptType.P2SH_P2WPKH: return 23; | ||
case interface_1.ScriptType.P2WPKH: return 22; | ||
case interface_1.ScriptType.P2TR: return 34; | ||
} | ||
return 0; | ||
} | ||
exports.getOutScriptSize = getOutScriptSize; | ||
function sliceSize(size) { | ||
return varuint.encodingLength(size) + size; | ||
} | ||
exports.sliceSize = sliceSize; | ||
function vectorSize(sizes) { | ||
return varuint.encodingLength(sizes.length) + | ||
sizes.reduce((sum, size) => sum + sliceSize(size), 0); | ||
} | ||
exports.vectorSize = vectorSize; | ||
function witnessStackToScriptWitness(witness) { | ||
let buffer = Buffer.allocUnsafe(0); | ||
const writeVarInt = (i) => { | ||
const currentLen = buffer.length; | ||
const varintLen = varuint.encodingLength(i); | ||
buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); | ||
varuint.encode(i, buffer, currentLen); | ||
}; | ||
writeVarInt(witness.length); | ||
for (const w of witness) { | ||
writeVarInt(w.length); | ||
buffer = Buffer.concat([buffer, Buffer.from(w)]); | ||
} | ||
return buffer; | ||
} | ||
exports.witnessStackToScriptWitness = witnessStackToScriptWitness; | ||
function scriptWitnessToWitnessStack(buffer) { | ||
let offset = 0; | ||
const readVarInt = () => { | ||
const vi = varuint.decode(buffer, offset); | ||
offset += varuint.decode.bytes; | ||
return vi; | ||
}; | ||
const readVarSlice = () => { | ||
const n = readVarInt(); | ||
offset += n; | ||
return buffer.slice(offset - n, offset); | ||
}; | ||
const count = readVarInt(); | ||
const vector = []; | ||
for (let i = 0; i < count; i++) { | ||
vector.push(readVarSlice()); | ||
} | ||
return vector; | ||
} | ||
exports.scriptWitnessToWitnessStack = scriptWitnessToWitnessStack; | ||
function getPublickey(data) { | ||
(0, ow_1.default)(data, ow_1.default.any(interface_1.ow_hexString, ow_1.default.buffer)); | ||
const pk = (typeof data === "string") ? Buffer.from(data, "hex") : data; | ||
(0, ow_1.default)(pk, ow_1.default.buffer.is(x => x.length === 33 || x.length === 65)); | ||
if (!secp256k1.publicKeyVerify(pk)) { | ||
throw Error(`ArgumentError: invalid secp256k1 publickey, got "${pk.toString("hex")}"`); | ||
} | ||
return pk; | ||
} | ||
exports.getPublickey = getPublickey; | ||
function toTweakedPublickey(data) { | ||
const publickey = getPublickey(data); | ||
const XOnlyPubkey = publickey.slice(1, 33); | ||
const commitHash = taggedHash("TapTweak", XOnlyPubkey); | ||
return (0, bip340_1.taprootConvert)(XOnlyPubkey, commitHash); | ||
} | ||
exports.toTweakedPublickey = toTweakedPublickey; | ||
const TAGS = [ | ||
'BIP0340/challenge', | ||
'BIP0340/aux', | ||
'BIP0340/nonce', | ||
'TapLeaf', | ||
'TapBranch', | ||
'TapSighash', | ||
'TapTweak', | ||
'KeyAgg list', | ||
'KeyAgg coefficient', | ||
]; | ||
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */ | ||
const TAGGED_HASH_PREFIXES = Object.fromEntries(TAGS.map(tag => { | ||
const tagHash = _sha256(tag); | ||
return [tag, Buffer.concat([tagHash, tagHash])]; | ||
})); | ||
function taggedHash(prefix, data) { | ||
const buf = Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]); | ||
return Buffer.from((0, hash_js_1.sha256)().update(buf).digest()); | ||
} | ||
exports.taggedHash = taggedHash; | ||
function _sha256(tag) { | ||
return Buffer.from((0, hash_js_1.sha256)().update(tag).digest()); | ||
} | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.taggedHash=exports.toTweakedPublickey=exports.getPublickey=exports.scriptWitnessToWitnessStack=exports.witnessStackToScriptWitness=exports.vectorSize=exports.sliceSize=exports.getOutScriptSize=exports.getWitnessSize=exports.getInScriptSize=exports.getSerializer=exports.getDefaultScript=exports.getPurpose=exports.getCoinType=exports.getPayment=void 0;const e=require("secp256k1/elliptic"),t=require("varuint-bitcoin"),r=require("./interface"),n=require("./payment"),c=require("./payment_bch"),i=require("./payment_grs"),o=require("./transaction"),s=require("./transaction_grs"),p=require("ow"),u=require("hash.js"),a=require("./bip340");function f(e){const t=e.match(/\d+/g),n=parseInt(t[1],10);for(let e=0;e<r.coinmap.length;e++)if(n===r.coinmap[e].coinType)return e;throw Error(`ArgumentError: unsupport cointype of BIP32 path, got ${e}`)}function S(e){return t.encodingLength(e)+e}function P(t){(0,p.default)(t,p.default.any(r.ow_hexString,p.default.buffer));const n="string"==typeof t?Buffer.from(t,"hex"):t;if((0,p.default)(n,p.default.buffer.is((e=>33===e.length||65===e.length))),!e.publicKeyVerify(n))throw Error(`ArgumentError: invalid secp256k1 publickey, got "${n.toString("hex")}"`);return n}exports.getPayment=function(e){switch(e){case r.CoinType.BITCOINCASH:return c.PaymentBCH;case r.CoinType.GROESTL:return i.PaymentGRS;default:return n.PaymentBTC}},exports.getCoinType=f,exports.getPurpose=function(e){switch(e){case r.ScriptType.P2PKH:return 44;case r.ScriptType.P2SH_P2PKH:case r.ScriptType.P2SH_P2WPKH:return 49;case r.ScriptType.P2WPKH:return 84;case r.ScriptType.P2TR:return 86}throw Error(`ArgumentError: unsupport ScriptType, got ${e}`)},exports.getDefaultScript=function(e){const t=e.match(/\d+/g),n=parseInt(t[0],10),c=t[1]?f(e):r.CoinType.BITCOIN;switch(n){case 44:return r.ScriptType.P2PKH;case 49:return c!==r.CoinType.BITCOINCASH?r.ScriptType.P2SH_P2WPKH:r.ScriptType.P2SH_P2PKH;case 84:return r.ScriptType.P2WPKH;case 86:return r.ScriptType.P2TR}throw Error(`ArgumentError: unsupport purpose of path, got "${n}" from ${e}`)},exports.getSerializer=function(e){return e===r.CoinType.GROESTL?s.TransactionGRS:o.Transaction},exports.getInScriptSize=function(e){switch(e){case r.ScriptType.P2PKH:case r.ScriptType.P2SH_P2PKH:return 107;case r.ScriptType.P2SH_P2WPKH:return 23}return 0},exports.getWitnessSize=function(e,t=o.Transaction.SIGHASH_DEFAULT){switch(e){case r.ScriptType.P2SH_P2WPKH:case r.ScriptType.P2WPKH:return[72,33];case r.ScriptType.P2TR:return t===o.Transaction.SIGHASH_DEFAULT?[64]:[65]}return[]},exports.getOutScriptSize=function(e){switch(e){case r.ScriptType.P2PKH:return 25;case r.ScriptType.P2SH_P2PKH:case r.ScriptType.P2SH_P2WPKH:return 23;case r.ScriptType.P2WPKH:return 22;case r.ScriptType.P2TR:return 34}return 0},exports.sliceSize=S,exports.vectorSize=function(e){return t.encodingLength(e.length)+e.reduce(((e,t)=>e+S(t)),0)},exports.witnessStackToScriptWitness=function(e){let r=Buffer.allocUnsafe(0);const n=e=>{const n=r.length,c=t.encodingLength(e);r=Buffer.concat([r,Buffer.allocUnsafe(c)]),t.encode(e,r,n)};n(e.length);for(const t of e)n(t.length),r=Buffer.concat([r,Buffer.from(t)]);return r},exports.scriptWitnessToWitnessStack=function(e){let r=0;const n=()=>{const n=t.decode(e,r);return r+=t.decode.bytes,n},c=()=>{const t=n();return r+=t,e.slice(r-t,r)},i=n(),o=[];for(let e=0;e<i;e++)o.push(c());return o},exports.getPublickey=P,exports.toTweakedPublickey=function(e){const t=P(e).slice(1,33),r=g("TapTweak",t);return(0,a.taprootConvert)(t,r)};const T=Object.fromEntries(["BIP0340/challenge","BIP0340/aux","BIP0340/nonce","TapLeaf","TapBranch","TapSighash","TapTweak","KeyAgg list","KeyAgg coefficient"].map((e=>{const t=function(e){return Buffer.from((0,u.sha256)().update(e).digest())}(e);return[e,Buffer.concat([t,t])]})));function g(e,t){const r=Buffer.concat([T[e],t]);return Buffer.from((0,u.sha256)().update(r).digest())}exports.taggedHash=g; |
{ | ||
"name": "@secux/app-btc", | ||
"version": "3.2.4", | ||
"version": "3.2.5", | ||
"description": "SecuX Hardware Wallet BTC API", | ||
@@ -39,3 +39,3 @@ "keywords": [ | ||
"@secux/protocol-transaction": "^3.0.0", | ||
"@secux/utility": "^3.0.7", | ||
"@secux/utility": "^3.0.8", | ||
"bech32": "^2.0.0", | ||
@@ -42,0 +42,0 @@ "bigi": "^1.4.2", |
Sorry, the diff of this file is too big to display
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
558385
672
15
Updated@secux/utility@^3.0.8