@tatumio/tatum-v1
Version:
Tatum API client allows browsers and Node.js clients to interact with Tatum API.
171 lines • 16.7 kB
JavaScript
;
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.prepareBitcoinCashSignedOffchainTransaction = exports.signBitcoinCashOffchainKMSTransaction = exports.sendBitcoinCashOffchainTransaction = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
// @ts-ignore
const coininfo_1 = __importDefault(require("coininfo"));
const tatum_1 = require("../connector/tatum");
const model_1 = require("../model");
const wallet_1 = require("../wallet");
const common_1 = require("./common");
const kms_1 = require("./kms");
// tslint:disable-next-line:no-var-requires
const bcash = require('@tatumio/bitcoincashjs2-lib');
/**
* Send Bitcoin Cash transaction from Tatum Ledger account to the blockchain. This method broadcasts signed transaction to the blockchain.
* This operation is irreversible.
* @param testnet mainnet or testnet version
* @param body content of the transaction to broadcast
* @returns transaction id of the transaction in the blockchain or id of the withdrawal, if it was not cancelled automatically
*/
const sendBitcoinCashOffchainTransaction = async (testnet, body) => {
if (body.signatureId) {
return kms_1.offchainTransferBcashKMS(body);
}
await tatum_1.validateBody(body, model_1.TransferBtcBasedOffchain);
const { mnemonic, keyPair, attr: changeAddress } = body, withdrawal = __rest(body, ["mnemonic", "keyPair", "attr"]);
if (!withdrawal.fee) {
withdrawal.fee = '0.00005';
}
const { id, data } = await common_1.offchainStoreWithdrawal(withdrawal);
const { amount, address, } = withdrawal;
let txData;
try {
txData = await exports.prepareBitcoinCashSignedOffchainTransaction(testnet, data, amount, address, mnemonic, keyPair, changeAddress, withdrawal.multipleAmounts);
}
catch (e) {
console.error(e);
await common_1.offchainCancelWithdrawal(id);
throw e;
}
try {
return Object.assign(Object.assign({}, await common_1.offchainBroadcast({ txData, withdrawalId: id, currency: model_1.Currency.BCH })), { id });
}
catch (e) {
console.error(e);
try {
await common_1.offchainCancelWithdrawal(id);
}
catch (e1) {
console.log(e);
return { id };
}
throw e;
}
};
exports.sendBitcoinCashOffchainTransaction = sendBitcoinCashOffchainTransaction;
/**
* Sign Bitcoin Cash pending transaction from Tatum KMS
* @param tx pending transaction from KMS
* @param mnemonic mnemonic to generate private keys to sign transaction with.
* @param testnet mainnet or testnet version
* @returns transaction data to be broadcast to blockchain.
*/
const signBitcoinCashOffchainKMSTransaction = async (tx, mnemonic, testnet) => {
var _a;
if (tx.chain !== model_1.Currency.BCH || !tx.withdrawalResponses) {
throw Error('Unsupported chain.');
}
const [data, amountsToDecode] = tx.serializedTransaction.split(':');
const transaction = bcash.Transaction.fromHex(data);
const amountsToSign = JSON.parse(amountsToDecode);
const network = testnet ? coininfo_1.default.bitcoincash.test.toBitcoinJS() : coininfo_1.default.bitcoincash.main.toBitcoinJS();
const builder = bcash.TransactionBuilder.fromTransaction(transaction, network);
for (const [i, response] of tx.withdrawalResponses.entries()) {
if (response.vIn === '-1') {
continue;
}
const ecPair = bcash.ECPair.fromWIF(await wallet_1.generatePrivateKeyFromMnemonic(model_1.Currency.BCH, testnet, mnemonic, ((_a = response.address) === null || _a === void 0 ? void 0 : _a.derivationKey) || 0), network);
builder.sign(i, ecPair, undefined, 0x01, amountsToSign[i], undefined, bcash.ECSignature.SCHNORR);
}
return builder.build().toHex();
};
exports.signBitcoinCashOffchainKMSTransaction = signBitcoinCashOffchainKMSTransaction;
const getAddress = (address) => {
try {
return wallet_1.toLegacyAddress(address);
}
catch (e) {
return address;
}
};
/**
* Sign Bitcoin Cash transaction with private keys locally. Nothing is broadcast to the blockchain.
* @param testnet mainnet or testnet version
* @param data data from Tatum system to prepare transaction from
* @param amount amount to send
* @param address recipient address, if multiple recipients are present, it should be string separated by ','
* @param mnemonic mnemonic to sign transaction from. mnemonic or keyPair must be present
* @param keyPair keyPair to sign transaction from. keyPair or mnemonic must be present
* @param changeAddress address to send the rest of the unused coins
* @param multipleAmounts if multiple recipients are present in the address separated by ',', this should be list of amounts to send
* @returns transaction data to be broadcast to blockchain.
*/
const prepareBitcoinCashSignedOffchainTransaction = async (testnet, data, amount, address, mnemonic, keyPair, changeAddress, multipleAmounts) => {
const network = testnet ? coininfo_1.default.bitcoincash.test.toBitcoinJS() : coininfo_1.default.bitcoincash.main.toBitcoinJS();
const tx = new bcash.TransactionBuilder(network);
data.forEach((input) => {
if (input.vIn !== '-1') {
tx.addInput(input.vIn, input.vInIndex, 0xffffffff, null);
}
});
const lastVin = data.find(d => d.vIn === '-1');
if (multipleAmounts === null || multipleAmounts === void 0 ? void 0 : multipleAmounts.length) {
for (const [i, multipleAmount] of multipleAmounts.entries()) {
tx.addOutput(getAddress(address.split(',')[i]), Number(new bignumber_js_1.default(multipleAmount).multipliedBy(100000000).toFixed(8, bignumber_js_1.default.ROUND_FLOOR)));
}
}
else {
tx.addOutput(getAddress(address), Number(new bignumber_js_1.default(amount).multipliedBy(100000000).toFixed(0, bignumber_js_1.default.ROUND_FLOOR)));
}
if (new bignumber_js_1.default(lastVin.amount).isGreaterThan(0)) {
if (mnemonic && !changeAddress) {
const { xpub } = await wallet_1.generateBchWallet(testnet, mnemonic);
tx.addOutput(getAddress(wallet_1.generateAddressFromXPub(model_1.Currency.BCH, testnet, xpub, 0)), Number(new bignumber_js_1.default(lastVin.amount).multipliedBy(100000000).toFixed(0, bignumber_js_1.default.ROUND_FLOOR)));
}
else if (changeAddress) {
tx.addOutput(getAddress(changeAddress), Number(new bignumber_js_1.default(lastVin.amount).multipliedBy(100000000).toFixed(0, bignumber_js_1.default.ROUND_FLOOR)));
}
else {
throw new Error('Impossible to prepare transaction. Either mnemonic or keyPair and attr must be present.');
}
}
for (const [i, input] of data.entries()) {
// when there is no address field present, input is pool transfer to 0
if (input.vIn === '-1') {
continue;
}
const value = Number(new bignumber_js_1.default(data[i].amount).multipliedBy(100000000).toFixed(0, bignumber_js_1.default.ROUND_FLOOR));
if (mnemonic) {
const derivationKey = input.address && input.address.derivationKey ? input.address.derivationKey : 0;
const privateKey = await wallet_1.generatePrivateKeyFromMnemonic(model_1.Currency.BCH, testnet, mnemonic, derivationKey);
const ecPair = bcash.ECPair.fromWIF(privateKey, network);
tx.sign(i, ecPair, undefined, 0x01, value, undefined, bcash.ECSignature.SCHNORR);
}
else if (keyPair) {
// @ts-ignore
const privateKey = keyPair.find(k => k.address === input.address.address);
if (privateKey) {
const ecPair = bcash.ECPair.fromWIF(privateKey.privateKey, network);
tx.sign(i, ecPair, undefined, 0x01, value, undefined, bcash.ECSignature.SCHNORR);
}
}
}
return tx.build().toHex();
};
exports.prepareBitcoinCashSignedOffchainTransaction = prepareBitcoinCashSignedOffchainTransaction;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmNhc2guanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvb2ZmY2hhaW4vYmNhc2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxnRUFBb0M7QUFDcEMsYUFBYTtBQUNiLHdEQUErQjtBQUMvQiw4Q0FBK0M7QUFDL0Msb0NBQTRHO0FBQzVHLHNDQUFxSDtBQUNySCxxQ0FBNkY7QUFDN0YsK0JBQWdEO0FBQ2hELDJDQUEyQztBQUMzQyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsNkJBQTZCLENBQUMsQ0FBQTtBQUVwRDs7Ozs7O0dBTUc7QUFDSSxNQUFNLGtDQUFrQyxHQUFHLEtBQUssRUFBRSxPQUFnQixFQUFFLElBQThCLEVBQUUsRUFBRTtJQUN6RyxJQUFHLElBQUksQ0FBQyxXQUFXLEVBQUU7UUFDakIsT0FBTyw4QkFBd0IsQ0FBQyxJQUFJLENBQUMsQ0FBQTtLQUN4QztJQUNELE1BQU0sb0JBQVksQ0FBQyxJQUFJLEVBQUUsZ0NBQXdCLENBQUMsQ0FBQTtJQUNsRCxNQUFNLEVBQ0YsUUFBUSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsYUFBYSxLQUN0QyxJQUFJLEVBRHVDLFVBQVUsVUFDckQsSUFBSSxFQUZGLCtCQUVMLENBQU8sQ0FBQTtJQUNSLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2pCLFVBQVUsQ0FBQyxHQUFHLEdBQUcsU0FBUyxDQUFBO0tBQzdCO0lBQ0QsTUFBTSxFQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUMsR0FBRyxNQUFNLGdDQUF1QixDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQzVELE1BQU0sRUFDRixNQUFNLEVBQUUsT0FBTyxHQUNsQixHQUFHLFVBQVUsQ0FBQTtJQUNkLElBQUksTUFBTSxDQUFBO0lBQ1YsSUFBSTtRQUNBLE1BQU0sR0FBRyxNQUFNLG1EQUEyQyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxR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