UNPKG

send-crypto

Version:

A minimal JavaScript library / wallet for sending crypto assets

124 lines 15.8 kB
import BigNumber from "bignumber.js"; import * as bitcoin from "bitgo-utxo-lib"; import { List } from "immutable"; import { Blockchain, BlockchainNetwork } from "../../common/apis/blockchain"; import { Blockchair } from "../../common/apis/blockchair"; import { Blockstream } from "../../common/apis/blockstream"; import { ElectrumX } from "../../common/apis/electrumx"; import { JSONRPC, MULTICHAIN_URLS } from "../../common/apis/jsonrpc"; import { Sochain } from "../../common/apis/sochain"; import { BitgoUTXOLib } from "../../common/libraries/bitgoUtxoLib"; import { subscribeToConfirmations } from "../../lib/confirmations"; import { newPromiEvent } from "../../lib/promiEvent"; import { fallback, retryNTimes } from "../../lib/retry"; import { shuffleArray } from "../../lib/utils"; export const _apiFallbacks = { fetchUTXO: (testnet, txHash, vOut) => [ ...shuffleArray(() => Blockstream.fetchUTXO(testnet)(txHash, vOut), () => Blockchair.fetchUTXO(testnet ? Blockchair.networks.BITCOIN_TESTNET : Blockchair.networks.BITCOIN)(txHash, vOut)), () => Blockchain.fetchUTXO(testnet ? BlockchainNetwork.BitcoinTestnet : BlockchainNetwork.Bitcoin)(txHash, vOut), ], fetchUTXOs: (testnet, address, confirmations, scriptHash) => [ ...shuffleArray(() => Blockstream.fetchUTXOs(testnet)(address, confirmations), () => Blockchair.fetchUTXOs(testnet ? Blockchair.networks.BITCOIN_TESTNET : Blockchair.networks.BITCOIN)(address, confirmations)), () => Sochain.fetchUTXOs(testnet ? "BTCTEST" : "BTC")(address, confirmations), () => Blockchain.fetchUTXOs(testnet ? BlockchainNetwork.BitcoinTestnet : BlockchainNetwork.Bitcoin)(address, confirmations), () => ElectrumX.fetchUTXOs("bitcoin", testnet)(address, confirmations, scriptHash), ], fetchTXs: (testnet, address, confirmations = 0, scriptHash) => [ ...shuffleArray(() => Blockstream.fetchTXs(testnet)(address), () => Blockchair.fetchTXs(testnet ? Blockchair.networks.BITCOIN_TESTNET : Blockchair.networks.BITCOIN)(address, confirmations), () => Sochain.fetchTXs(testnet ? "BTCTEST" : "BTC")(address, confirmations), () => Blockchain.fetchUTXOs(testnet ? BlockchainNetwork.BitcoinTestnet : BlockchainNetwork.Bitcoin)(address, confirmations)), ], broadcastTransaction: (testnet, hex) => [ ...shuffleArray(() => Blockstream.broadcastTransaction(testnet)(hex), () => Blockchair.broadcastTransaction(testnet ? Blockchair.networks.BITCOIN_TESTNET : Blockchair.networks.BITCOIN)(hex)), () => Sochain.broadcastTransaction(testnet ? "BTCTEST" : "BTC")(hex), () => JSONRPC.broadcastTransaction(testnet ? MULTICHAIN_URLS.BTCTEST : MULTICHAIN_URLS.BTC)(hex), testnet ? undefined : () => Blockchain.broadcastTransaction(BlockchainNetwork.Bitcoin)(hex), ], }; export class BTCHandler { privateKey; testnet; decimals = 8; static getUTXOs = async (testnet, options) => { const confirmations = options && options.confirmations !== undefined ? options.confirmations : 0; const endpoints = _apiFallbacks.fetchUTXOs(testnet, options.address, confirmations, options.scriptHash); return fallback(endpoints); }; static getUTXO = async (testnet, txHash, vOut) => { const endpoints = _apiFallbacks.fetchUTXO(testnet, txHash, vOut); return fallback(endpoints); }; static getTransactions = async (testnet, options) => { const confirmations = options && options.confirmations !== undefined ? options.confirmations : 0; const endpoints = _apiFallbacks.fetchTXs(testnet, options.address, confirmations, options.scriptHash); return fallback(endpoints); }; constructor(privateKey, network) { this.testnet = network !== "mainnet"; this.privateKey = BitgoUTXOLib.loadPrivateKey(this.testnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin, privateKey); } // Returns whether or not this can handle the asset handlesAsset = (asset) => typeof asset === "string" && ["BTC", "BITCOIN"].indexOf(asset.toUpperCase()) !== -1; address = async (asset, options) => this.privateKey.getAddress(); // Balance getBalance = async (asset, options) => (await this.getBalanceInSats(asset, options)).dividedBy(new BigNumber(10).exponentiatedBy(this.decimals)); getBalanceInSats = async (asset, options) => { const utxos = await BTCHandler.getUTXOs(this.testnet, { ...options, address: (options && options.address) || (await this.address(asset)), }); return utxos.reduce((sum, utxo) => sum.plus(utxo.amount), new BigNumber(0)); }; // Transfer send = (to, value, asset, options) => this.sendSats(to, value.times(new BigNumber(10).exponentiatedBy(this.decimals)), asset, options); sendSats = (to, valueIn, asset, options) => { const promiEvent = newPromiEvent(); let txHash; let errored; (async () => { const fromAddress = await this.address(asset); const changeAddress = fromAddress; const utxos = List(await BTCHandler.getUTXOs(this.testnet, { ...options, address: fromAddress, })) .sortBy((utxo) => utxo.amount) .reverse() .toArray(); const built = await BitgoUTXOLib.buildUTXO(this.testnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin, this.privateKey, changeAddress, to, valueIn, utxos, options); txHash = await retryNTimes(() => fallback(_apiFallbacks.broadcastTransaction(this.testnet, built.toHex())), 3); promiEvent.emit("transactionHash", txHash); promiEvent.resolve(txHash); })().catch((error) => { errored = true; promiEvent.reject(error); }); subscribeToConfirmations(promiEvent, () => errored, async () => (txHash ? this._getConfirmations(txHash) : 0)); return promiEvent; }; _getConfirmations = async (txHash) => (await fallback( // Fetch confirmations for first output of transaction. _apiFallbacks.fetchUTXO(this.testnet, txHash, 0))).confirmations; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQlRDSGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9oYW5kbGVycy9CVEMvQlRDSGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFNBQVMsTUFBTSxjQUFjLENBQUM7QUFDckMsT0FBTyxLQUFLLE9BQU8sTUFBTSxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRWpDLE9BQU8sRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM3RSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzVELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDbkUsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDbkUsT0FBTyxFQUFFLGFBQWEsRUFBYyxNQUFNLHNCQUFzQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBYy9DLE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRztJQUN6QixTQUFTLEVBQUUsQ0FBQyxPQUFnQixFQUFFLE1BQWMsRUFBRSxJQUFZLEVBQUUsRUFBRSxDQUFDO1FBQzNELEdBQUcsWUFBWSxDQUNYLEdBQUcsRUFBRSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsT0FB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