UNPKG

@trezor/utxo-lib

Version:
205 lines (204 loc) 5.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateAndParseRequest = validateAndParseRequest; const address_1 = require("../address"); const coinselectUtils_1 = require("../coinselect/coinselectUtils"); const embed_1 = require("../payments/embed"); function validateAndParseFeeRate(rate) { const feeRate = typeof rate === 'string' ? Number(rate) : rate; if (typeof feeRate !== 'number' || Number.isNaN(feeRate) || !Number.isFinite(feeRate) || feeRate > Number.MAX_SAFE_INTEGER || feeRate <= 0) { return; } return feeRate; } function transformInput(i, utxo, txType) { if (typeof utxo.coinbase !== 'boolean') { throw new Error('Missing coinbase'); } if (typeof utxo.own !== 'boolean') { throw new Error('Missing own'); } if (typeof utxo.confirmations !== 'number') { throw new Error('Missing confirmations'); } const value = (0, coinselectUtils_1.bignumberOrNaN)(utxo.amount); if (!value) { throw new Error('Invalid amount'); } return { ...utxo, type: txType, i, script: { length: coinselectUtils_1.INPUT_SCRIPT_LENGTH[txType] }, value }; } function validateAndParseUtxos(txType, { utxos }) { if (utxos.length === 0) { return { type: 'error', error: 'MISSING-UTXOS' }; } const incorrectUtxoError = (index, message) => ({ type: 'error', error: 'INCORRECT-UTXO', message: `${message} at index ${index}` }); const result = []; for (let i = 0; i < utxos.length; i++) { try { const csInput = transformInput(i, utxos[i], txType); csInput.weight = (0, coinselectUtils_1.inputWeight)(csInput); result.push(csInput); } catch (error) { return incorrectUtxoError(i, error.message); } } return result; } function transformOutput(output, txType, network) { const script = { length: coinselectUtils_1.OUTPUT_SCRIPT_LENGTH[txType] }; if (output.type === 'payment') { const value = (0, coinselectUtils_1.bignumberOrNaN)(output.amount); if (!value) throw new Error('Invalid amount'); return { value, script: (0, address_1.toOutputScript)(output.address, network) }; } if (output.type === 'payment-noaddress') { const value = (0, coinselectUtils_1.bignumberOrNaN)(output.amount); if (!value) throw new Error('Invalid amount'); return { value, script }; } if (output.type === 'opreturn') { return { value: (0, coinselectUtils_1.bignumberOrNaN)('0', true), script: (0, embed_1.p2data)({ data: [Buffer.from(output.dataHex, 'hex')] }).output }; } if (output.type === 'send-max') { return { script: (0, address_1.toOutputScript)(output.address, network) }; } if (output.type === 'send-max-noaddress') { return { script }; } throw new Error('Unknown output type'); } function validateAndParseOutputs(txType, { outputs, network }) { if (outputs.length === 0) { return { type: 'error', error: 'MISSING-OUTPUTS' }; } const incorrectOutputError = (index, message) => ({ type: 'error', error: 'INCORRECT-OUTPUT', message: `${message} at index ${index}` }); let sendMaxOutputIndex = -1; const result = []; for (let i = 0; i < outputs.length; i++) { const output = outputs[i]; if (output.type === 'send-max-noaddress' || output.type === 'send-max') { if (sendMaxOutputIndex >= 0) { return incorrectOutputError(i, 'Multiple send-max'); } sendMaxOutputIndex = i; } try { const csOutput = transformOutput(output, txType, network); csOutput.weight = (0, coinselectUtils_1.outputWeight)(csOutput); result.push(csOutput); } catch (error) { return incorrectOutputError(i, error.message); } } return { outputs: result, sendMaxOutputIndex }; } function validateAndParseChangeOutput(txType, { changeAddress, network }) { try { return transformOutput({ type: 'send-max', ...changeAddress }, txType, network); } catch (error) { return { type: 'error', error: 'INCORRECT-OUTPUT', message: error.message }; } } function validateAndParseRequest(request) { const feeRate = validateAndParseFeeRate(request.feeRate); if (!feeRate) { return { type: 'error', error: 'INCORRECT-FEE-RATE' }; } const longTermFeeRate = validateAndParseFeeRate(request.longTermFeeRate); if (request.longTermFeeRate != null && !longTermFeeRate) { return { type: 'error', error: 'INCORRECT-FEE-RATE' }; } const txType = request.txType || 'p2pkh'; const inputs = validateAndParseUtxos(txType, request); if ('error' in inputs) { return inputs; } const outputs = validateAndParseOutputs(txType, request); if ('error' in outputs) { return outputs; } const changeOutput = validateAndParseChangeOutput(txType, request); if ('error' in changeOutput) { return changeOutput; } const feePolicy = (0, coinselectUtils_1.getFeePolicy)(request.network); return { txType, inputs, ...outputs, changeOutput, feeRate, feePolicy, longTermFeeRate, dustThreshold: request.dustThreshold, baseFee: request.baseFee, floorBaseFee: request.floorBaseFee, sortingStrategy: request.sortingStrategy }; } //# sourceMappingURL=request.js.map