send-crypto
Version:
A minimal JavaScript library / wallet for sending crypto assets
124 lines • 15.8 kB
JavaScript
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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