import type Transport from "@ledgerhq/hw-transport"; import type { Transaction } from "./types"; import { createVarint } from "./varint"; import { MAX_SCRIPT_BLOCK } from "./constants"; export function startUntrustedHashTransactionInputRaw( transport: Transport, newTransaction: boolean, firstRound: boolean, transactionData: Buffer, bip143 = false, overwinter = false, additionals: Array = [], ): Promise { const p2 = additionals.includes("cashaddr") ? 0x03 : bip143 ? additionals.includes("sapling") ? 0x05 : overwinter ? 0x04 : 0x02 : 0x00; return transport.send( 0xe0, 0x44, firstRound ? 0x00 : 0x80, newTransaction ? p2 : 0x80, transactionData, ); } export async function startUntrustedHashTransactionInput( transport: Transport, newTransaction: boolean, transaction: Transaction, inputs: Array<{ trustedInput: boolean; value: Buffer; }>, bip143 = false, overwinter = false, additionals: Array = [], useTrustedInputForSegwit = false, ): Promise { const isZcash = additionals.includes("zcash"); const zCashConsensusBranchId = transaction.consensusBranchId || Buffer.alloc(0); let data = Buffer.concat([ transaction.version, transaction.timestamp || Buffer.alloc(0), transaction.nVersionGroupId || Buffer.alloc(0), isZcash ? zCashConsensusBranchId : Buffer.alloc(0), createVarint(transaction.inputs.length), ]); await startUntrustedHashTransactionInputRaw( transport, newTransaction, true, data, bip143, overwinter, additionals, ); let i = 0; const isDecred = additionals.includes("decred"); for (const input of transaction.inputs) { let prefix; const inputValue = inputs[i].value; if (bip143) { if (useTrustedInputForSegwit && inputs[i].trustedInput) { prefix = Buffer.from([0x01, inputValue.length]); } else { prefix = Buffer.from([0x02]); } } else { if (inputs[i].trustedInput) { prefix = Buffer.from([0x01, inputs[i].value.length]); } else { prefix = Buffer.from([0x00]); } } data = Buffer.concat([ prefix, inputValue, isDecred ? Buffer.from([0x00]) : Buffer.alloc(0), createVarint(input.script.length), ]); await startUntrustedHashTransactionInputRaw( transport, newTransaction, false, data, bip143, overwinter, additionals, ); const scriptBlocks: Buffer[] = []; let offset = 0; if (input.script.length === 0) { scriptBlocks.push(input.sequence); } else { while (offset !== input.script.length) { const blockSize = input.script.length - offset > MAX_SCRIPT_BLOCK ? MAX_SCRIPT_BLOCK : input.script.length - offset; if (offset + blockSize !== input.script.length) { scriptBlocks.push(input.script.slice(offset, offset + blockSize)); } else { scriptBlocks.push( Buffer.concat([input.script.slice(offset, offset + blockSize), input.sequence]), ); } offset += blockSize; } } for (const scriptBlock of scriptBlocks) { await startUntrustedHashTransactionInputRaw( transport, newTransaction, false, scriptBlock, bip143, overwinter, additionals, ); } i++; } }