/* * This file is part of the Flowee project * Copyright (C) 2019-2020 Tom Zander * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ const Message = require('./message'); /** * Blockchain information service. * @param {Flowee} instance Instance of Flowee */ class LiveTransactionsService { constructor(network) { this.network = network; } /** * Get Live transaction can return not yet mined transactions by txid * @example * try { * let answer = await flowee.getLiveTransaction(txid); * } catch (e) { * console.log(e); * } * * Please be aware that when the txid is not available it will reject * the promise. Which is why you likely want to use the try/catch or * similar solution. * * The return type is a byte buffer. */ async getLiveTransaction(txid) { let message = new Message(2, 0); if (typeof txid === 'string') message.body[4] = Buffer.from(txid, 'hex').reverse(); else if (typeof txid === 'object') // a buffer is an object message.body[4] = txid; else throw "Invalid arguments"; let reply = await this.network.sendMessage(message); return reply[1]; } /** * Fetch the UTXO status of a certain output. * This returns a simple true or false to state if the output is unspent. * If the transaction is not found, your promise will fail. * * @example * let answer = await flowee.isUnspent({ * txid: "82f8dc85e292696c99323b397dc3027d7f4e074f5b5e2b81dc4d5e7f666a9127", * outIndex: 0 * }); * * or: * let answer = await flowee.isUnspent({ * blockHeight: 500000, * offsetInBlock: 29710, * outIndex: 0 * }); * * The return type is a boolean */ async isUnspent(param) { let message = new Message(2, 4); LiveTransactionsService.#processUTXOParams(param, message); let reply = await this.network.sendMessage(message); return reply[26]; } /** * Fetch the UTXO status of a certain output. * This returns an object like: * { * unspent: true, * blockHeight: 645736, * offsetInBlock: 87073, * outputIndex: 0, * amount: 11504, * outputScript: Uint8Array(25) [ * 118, 169, 20, 192, 85, 8, 224, * 42, 205, 62, 52, 105, 131, 102, * 11, 149, 159, 183, 143, 57, 145, * 62, 22, 136, 172 * ] * } * * Please check isUnspent() for similar functionality that is much cheaper to run * if all you need is the unspent status. * * @example * let answer = await flowee.getUnspentOutput({ * txid: "82f8dc85e292696c99323b397dc3027d7f4e074f5b5e2b81dc4d5e7f666a9127", * outIndex: 0 * }); * * or: * let answer = await flowee.getUnspentOutput({ * blockHeight: 500000, * offsetInBlock: 29710, * outIndex: 0 * }); */ async getUnspentOutput(param) { let message = new Message(2, 6); LiveTransactionsService.#processUTXOParams(param, message); let reply = await this.network.sendMessage(message); return { unspent: reply[22], blockHeight: reply[7], offsetInBlock: reply[8], outputIndex: reply[21], amount: reply[6], // in satoshis outputScript: reply[23] }; } // private helper method static #processUTXOParams(param, message) { if (typeof param !== 'object') throw "Invalid arguments"; if (typeof param.blockHeight === 'number' && typeof param.offsetInBlock === 'number' && typeof param.outIndex === 'number') { message.body[7] = param.blockHeight; message.body[8] = param.offsetInBlock + 1; } else if (typeof param.txid === 'string' && typeof param.outIndex === 'number') { message.body[4] = Buffer.from(param.txid, 'hex').reverse(); } else { throw "Invalid arguments"; } message.body[21] = param.outIndex; } } module.exports = LiveTransactionsService;