@trezor/connect
Version:
High-level javascript interface for Trezor hardware wallet.
131 lines • 6.36 kB
JavaScript
;
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