UNPKG

@trezor/connect

Version:

High-level javascript interface for Trezor hardware wallet.

131 lines 6.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.verifyTicketTx = exports.verifyTx = void 0; const utxo_lib_1 = require("@trezor/utxo-lib"); const constants_1 = require("../../constants"); const derivePubKeyHash = async (address_n, getHDNode, coinInfo, unlockPath) => { if (address_n.length === 5) { const response = await getHDNode({ address_n: address_n.slice(0, 4) }, { coinInfo, unlockPath }); const node = utxo_lib_1.bip32.fromBase58(response.xpub, coinInfo.network); return node.derive(address_n[address_n.length - 1]); } const response = await getHDNode({ address_n }, { coinInfo, unlockPath }); return utxo_lib_1.bip32.fromBase58(response.xpub, coinInfo.network); }; const deriveOutputScript = async (getHDNode, output, coinInfo, unlockPath) => { if ('multisig' in output) return; if ('op_return_data' in output) { return utxo_lib_1.payments.embed({ data: [Buffer.from(output.op_return_data, 'hex')] }) .output; } if (output.address) { return utxo_lib_1.address.toOutputScript(output.address, coinInfo.network); } if (!output.address_n) { throw constants_1.ERRORS.TypedError('Runtime', 'deriveOutputScript: Neither address or address_n is set'); } const node = await derivePubKeyHash(output.address_n, getHDNode, coinInfo, unlockPath); const payment = { hash: node.identifier, network: coinInfo.network }; if (output.script_type === 'PAYTOADDRESS') { return utxo_lib_1.payments.p2pkh(payment).output; } if (output.script_type === 'PAYTOSCRIPTHASH') { return utxo_lib_1.payments.p2sh(payment).output; } if (output.script_type === 'PAYTOP2SHWITNESS') { return utxo_lib_1.payments.p2sh({ redeem: utxo_lib_1.payments.p2wpkh(payment), }).output; } if (output.script_type === 'PAYTOWITNESS') { return utxo_lib_1.payments.p2wpkh(payment).output; } if (output.script_type === 'PAYTOTAPROOT') { return utxo_lib_1.payments.p2tr({ pubkey: node.publicKey, network: coinInfo.network, }).output; } if (output.script_type === 'PAYTOMULTISIG') { throw constants_1.ERRORS.TypedError('Runtime', `deriveOutputScript: script_type PAYTOMULTISIG not expected without multisig defined`); } throw constants_1.ERRORS.TypedError('Runtime', `deriveOutputScript: Unknown script type ${output.script_type}`); }; const verifyTx = async (getHDNode, inputs, outputs, serializedTx, coinInfo, unlockPath) => { const bitcoinTx = utxo_lib_1.Transaction.fromHex(serializedTx, { network: coinInfo.network }); if (inputs.length !== bitcoinTx.ins.length) { throw constants_1.ERRORS.TypedError('Runtime', 'verifyTx: Signed transaction inputs invalid length'); } if (outputs.length !== bitcoinTx.outs.length) { throw constants_1.ERRORS.TypedError('Runtime', 'verifyTx: Signed transaction outputs invalid length'); } for (let i = 0; i < outputs.length; i++) { const scriptB = bitcoinTx.outs[i].script; if (outputs[i].amount) { const { amount } = outputs[i]; if (amount.toString() !== bitcoinTx.outs[i].value) { throw constants_1.ERRORS.TypedError('Runtime', `verifyTx: Wrong output amount at output ${i}. Requested: ${amount}, signed: ${bitcoinTx.outs[i].value}`); } } const scriptA = await deriveOutputScript(getHDNode, outputs[i], coinInfo, unlockPath); if (scriptA && scriptA.compare(scriptB) !== 0) { throw constants_1.ERRORS.TypedError('Runtime', `verifyTx: Output ${i} scripts differ`); } } return bitcoinTx; }; exports.verifyTx = verifyTx; const verifyTicketTx = async (getHDNode, inputs, outputs, serializedTx, coinInfo) => { const bitcoinTx = utxo_lib_1.Transaction.fromHex(serializedTx, { network: coinInfo.network }); if (inputs.length !== bitcoinTx.ins.length) { throw constants_1.ERRORS.TypedError('Runtime', 'verifyTicketTx: Signed transaction inputs invalid length'); } if (outputs.length !== bitcoinTx.outs.length || outputs.length !== 3) { throw constants_1.ERRORS.TypedError('Runtime', 'verifyTicketTx: Signed transaction outputs invalid length'); } for (let i = 0; i < outputs.length; i++) { const scriptB = bitcoinTx.outs[i].script; const output = outputs[i]; let scriptA; if (i === 0) { const { amount } = output; if (amount !== bitcoinTx.outs[i].value) { throw constants_1.ERRORS.TypedError('Runtime', `verifyTicketTx: Wrong output amount at output ${i}. Requested: ${amount}, signed: ${bitcoinTx.outs[i].value}`); } scriptA = utxo_lib_1.payments.sstxpkh({ address: output.address, network: coinInfo.network, }).output; } else if (i === 1) { if (output.address) { throw constants_1.ERRORS.TypedError('Runtime', `verifyTicketTx: Output 1 should not have address.`); } if (!output.address_n) { throw constants_1.ERRORS.TypedError('Runtime', `verifyTicketTx: Output 1 should have address_n.`); } const node = await derivePubKeyHash(output.address_n, getHDNode, coinInfo); scriptA = utxo_lib_1.payments.sstxcommitment({ hash: node.identifier, amount: output.amount.toString(), network: coinInfo.network, }).output; } else { const { amount } = output; if (amount !== bitcoinTx.outs[i].value) { throw constants_1.ERRORS.TypedError('Runtime', `verifyTicketTx: Wrong output amount at output ${i}. Requested: ${amount}, signed: ${bitcoinTx.outs[i].value}`); } scriptA = utxo_lib_1.payments.sstxchange({ address: output.address, network: coinInfo.network, }).output; } if (scriptA && scriptA.compare(scriptB) !== 0) { throw constants_1.ERRORS.TypedError('Runtime', `verifyTx: Output ${i} scripts differ`); } } }; exports.verifyTicketTx = verifyTicketTx; //# sourceMappingURL=signtxVerify.js.map