send-crypto
Version:
A minimal JavaScript library / wallet for sending crypto assets
146 lines • 16.5 kB
JavaScript
import { toCashAddress, toLegacyAddress } from "bchaddrjs";
import BigNumber from "bignumber.js";
import * as bitcoin from "bitgo-utxo-lib";
import { List } from "immutable";
import { BitcoinDotCom } from "../../common/apis/bitcoinDotCom";
import { Blockchain, BlockchainNetwork } from "../../common/apis/blockchain";
import { Blockchair } from "../../common/apis/blockchair";
import { Insight } from "../../common/apis/insight";
import { JSONRPC, MULTICHAIN_URLS } from "../../common/apis/jsonrpc";
import { BitgoUTXOLib } from "../../common/libraries/bitgoUtxoLib";
import { subscribeToConfirmations } from "../../lib/confirmations";
import { newPromiEvent } from "../../lib/promiEvent";
import { fallback, retryNTimes } from "../../lib/retry";
const testnetInsight = "https://api.bitcore.io/api/BCH/testnet/";
const mainnetInsight = "https://api.bitcore.io/api/BCH/mainnet/";
const toCashAddr = (legacyAddress) => {
try {
return toCashAddress(legacyAddress);
}
catch (error) {
return legacyAddress;
}
};
export const _apiFallbacks = {
fetchUTXO: (testnet, txHash, vOut) => [
() => Blockchain.fetchUTXO(testnet
? BlockchainNetwork.BitcoinCashTestnet
: BlockchainNetwork.BitcoinCash)(txHash, vOut),
() => Insight.fetchUTXO(testnet ? testnetInsight : mainnetInsight)(txHash, vOut),
() => BitcoinDotCom.fetchUTXO(testnet)(txHash, vOut),
testnet
? undefined
: () => Blockchair.fetchUTXO(Blockchair.networks.BITCOIN_CASH)(txHash, vOut),
],
fetchUTXOs: (testnet, address, confirmations) => [
() => Blockchain.fetchUTXOs(testnet
? BlockchainNetwork.BitcoinCashTestnet
: BlockchainNetwork.BitcoinCash)(address, confirmations),
() => Insight.fetchUTXOs(testnet ? testnetInsight : mainnetInsight)(address, confirmations),
() => BitcoinDotCom.fetchUTXOs(testnet)(address, confirmations),
testnet
? undefined
: () => Blockchair.fetchUTXOs(Blockchair.networks.BITCOIN_CASH)(address, confirmations),
],
fetchTXs: (testnet, address, confirmations = 0) => [
() => Blockchain.fetchTXs(testnet
? BlockchainNetwork.BitcoinCashTestnet
: BlockchainNetwork.BitcoinCash)(address, confirmations),
() => Insight.fetchTXs(testnet ? testnetInsight : mainnetInsight)(address, confirmations),
// () => BitcoinDotCom.fetchTXs(testnet)(address, confirmations),
testnet
? undefined
: () => Blockchair.fetchTXs(Blockchair.networks.BITCOIN_CASH)(address, confirmations),
],
broadcastTransaction: (testnet, hex) => [
() => JSONRPC.broadcastTransaction(testnet ? MULTICHAIN_URLS.BCHTEST : MULTICHAIN_URLS.BCH)(hex),
() => Insight.broadcastTransaction(testnet ? testnetInsight : mainnetInsight)(hex),
() => BitcoinDotCom.broadcastTransaction(testnet)(hex),
testnet
? undefined
: () => Blockchair.broadcastTransaction(Blockchair.networks.BITCOIN_CASH)(hex),
],
};
export class BCHHandler {
privateKey;
testnet;
decimals = 8;
static getUTXOs = async (testnet, options) => {
const address = toCashAddr(options.address);
const confirmations = options.confirmations || 0;
const endpoints = _apiFallbacks.fetchUTXOs(testnet, address, confirmations);
const utxos = await fallback(endpoints);
return utxos;
};
static getUTXO = async (testnet, txHash, vOut) => {
const endpoints = _apiFallbacks.fetchUTXO(testnet, txHash, vOut);
return fallback(endpoints);
};
static getTransactions = async (testnet, options) => {
const address = toCashAddr(options.address);
const confirmations = options && options.confirmations !== undefined
? options.confirmations
: 0;
const endpoints = _apiFallbacks.fetchTXs(testnet, address, confirmations);
return fallback(endpoints);
};
constructor(privateKey, network) {
this.testnet = network !== "mainnet";
this.privateKey = BitgoUTXOLib.loadPrivateKey(this._bitgoNetwork(), privateKey);
}
// Returns whether or not this can handle the asset
handlesAsset = (asset) => typeof asset === "string" &&
["BCH", "BITCOIN CASH", "BCASH", "BITCOINCASH", "BITCOIN-CASH"].indexOf(asset.toUpperCase()) !== -1;
address = async (asset, options) => toCashAddr(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 BCHHandler.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 = toLegacyAddress(await this.address(asset));
const toAddress = toLegacyAddress(to);
const changeAddress = fromAddress;
const utxos = List(await BCHHandler.getUTXOs(this.testnet, {
...options,
address: fromAddress,
}))
.sortBy((utxo) => utxo.amount)
.reverse()
.toArray();
const built = await BitgoUTXOLib.buildUTXO(this._bitgoNetwork(), this.privateKey, changeAddress, toAddress, valueIn, utxos, {
...options,
signFlag:
// bitcoin.Transaction.SIGHASH_ALL |
// tslint:disable-next-line: no-bitwise
bitcoin.Transaction.SIGHASH_SINGLE |
bitcoin.Transaction.SIGHASH_BITCOINCASHBIP143,
});
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;
_bitgoNetwork = () => this.testnet
? bitcoin.networks.bitcoincashTestnet
: bitcoin.networks.bitcoincash;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQkNISGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9oYW5kbGVycy9CQ0gvQkNISGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFFLGVBQWUsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUMzRCxPQUFPLFNBQVMsTUFBTSxjQUFjLENBQUM7QUFDckMsT0FBTyxLQUFLLE9BQU8sTUFBTSxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRWpDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNoRSxPQUFPLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDN0UsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzFELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUNuRSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNuRSxPQUFPLEVBQUUsYUFBYSxFQUFjLE1BQU0sc0JBQXNCLENBQUM7QUFDakUsT0FBTyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUl4RCxNQUFNLGNBQWMsR0FBRyx5Q0FBeUMsQ0FBQztBQUNqRSxNQUFNLGNBQWMsR0FBRyx5Q0FBeUMsQ0FBQztBQVlqRSxNQUFNLFVBQVUsR0FBRyxDQUFDLGFBQXFCLEVBQUUsRUFBRTtJQUN6QyxJQUFJO1FBQ0EsT0FBTyxhQUFhLENBQUMsYUFBYSxDQUFDLENBQUM7S0FDdkM7SUFBQyxPQUFPLEtBQVUsRUFBRTtRQUNqQixP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