@tatumio/tatum-v1
Version:
Tatum API client allows browsers and Node.js clients to interact with Tatum API.
231 lines • 20.5 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.prepareEthErc20SignedOffchainTransaction = exports.prepareEthSignedOffchainTransaction = exports.signEthOffchainKMSTransaction = exports.sendEthErc20OffchainTransaction = exports.sendEthOffchainTransaction = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const blockchain_1 = require("../blockchain");
const tatum_1 = require("../connector/tatum");
const constants_1 = require("../constants");
const token_abi_1 = __importDefault(require("../contracts/erc20/token_abi"));
const ledger_1 = require("../ledger");
const model_1 = require("../model");
const transaction_1 = require("../transaction");
const wallet_1 = require("../wallet");
const common_1 = require("./common");
const kms_1 = require("./kms");
/**
* Send Ethereum 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
* @param provider url of the Ethereum Server to connect to. If not set, default public server will be used.
* @returns transaction id of the transaction in the blockchain or id of the withdrawal, if it was not cancelled automatically
*/
const sendEthOffchainTransaction = async (testnet, body, provider) => {
if (body.signatureId) {
return kms_1.offchainTransferEthKMS(body);
}
await tatum_1.validateBody(body, model_1.TransferEthOffchain);
const { mnemonic, index, privateKey, nonce } = body, withdrawal = __rest(body, ["mnemonic", "index", "privateKey", "nonce"]);
const { amount, address } = withdrawal;
let fromPriv;
if (mnemonic && index !== undefined) {
fromPriv = mnemonic && index ? await wallet_1.generatePrivateKeyFromMnemonic(model_1.Currency.ETH, testnet, mnemonic, index) : privateKey;
}
else if (privateKey) {
fromPriv = privateKey;
}
else {
throw new Error('No mnemonic or private key is present.');
}
const web3 = await transaction_1.getClient(provider, fromPriv);
const gasPrice = body.gasPrice ? web3.utils.toWei(body.gasPrice, 'gwei') : await transaction_1.ethGetGasPriceInWeiWrapper.ethGetGasPriceInWei();
const account = await ledger_1.getAccountById(withdrawal.senderAccountId);
const { txData, gasLimit } = await exports.prepareEthSignedOffchainTransaction({
amount,
privateKey: fromPriv,
address,
currency: account.currency,
web3,
gasPrice,
nonce,
gasLimit: body.gasLimit
});
// @ts-ignore
withdrawal.fee = new bignumber_js_1.default(web3.utils.fromWei(new bignumber_js_1.default(body.gasLimit || gasLimit).multipliedBy(gasPrice).toString(), 'ether')).toString();
const { id } = await common_1.offchainStoreWithdrawal(withdrawal);
try {
return Object.assign(Object.assign({}, await common_1.offchainBroadcast({ txData, withdrawalId: id, currency: model_1.Currency.ETH })), { id });
}
catch (e) {
console.error(e);
try {
await common_1.offchainCancelWithdrawal(id);
}
catch (e1) {
console.log(e);
return { id };
}
throw e;
}
};
exports.sendEthOffchainTransaction = sendEthOffchainTransaction;
/**
* Send Ethereum ERC20 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
* @param provider url of the Ethereum Server to connect to. If not set, default public server will be used.
* @returns transaction id of the transaction in the blockchain or id of the withdrawal, if it was not cancelled automatically
*/
const sendEthErc20OffchainTransaction = async (testnet, body, provider) => {
await tatum_1.validateBody(body, model_1.TransferEthOffchain);
const { mnemonic, index, privateKey, nonce } = body, withdrawal = __rest(body, ["mnemonic", "index", "privateKey", "nonce"]);
const { amount, address } = withdrawal;
let fromPriv;
if (mnemonic && index !== undefined) {
fromPriv = mnemonic && index ? await wallet_1.generatePrivateKeyFromMnemonic(model_1.Currency.ETH, testnet, mnemonic, index) : privateKey;
}
else if (privateKey) {
fromPriv = privateKey;
}
else {
throw new Error('No mnemonic or private key is present.');
}
const web3 = await transaction_1.getClient(provider, fromPriv);
const gasPrice = body.gasPrice ? web3.utils.toWei(body.gasPrice, 'gwei') : await transaction_1.ethGetGasPriceInWeiWrapper.ethGetGasPriceInWei();
const account = await ledger_1.getAccountById(withdrawal.senderAccountId);
if (model_1.ETH_BASED_CURRENCIES.includes(account.currency)) {
return exports.sendEthOffchainTransaction(testnet, body, provider);
}
const vc = await ledger_1.getVirtualCurrencyByName(account.currency);
const { txData, gasLimit } = await exports.prepareEthErc20SignedOffchainTransaction({
amount,
privateKey: fromPriv,
address,
web3,
tokenAddress: vc.erc20Address,
gasPrice,
nonce,
gasLimit: body.gasLimit
});
// @ts-ignore
withdrawal.fee = new bignumber_js_1.default(web3.utils.fromWei(new bignumber_js_1.default(gasLimit).multipliedBy(gasPrice).toString(), 'ether')).toString();
const { id } = await common_1.offchainStoreWithdrawal(withdrawal);
try {
return Object.assign(Object.assign({}, await common_1.offchainBroadcast({ txData, withdrawalId: id, currency: model_1.Currency.ETH })), { id });
}
catch (e) {
console.error(e);
try {
await common_1.offchainCancelWithdrawal(id);
}
catch (e1) {
console.log(e);
return { id };
}
throw e;
}
};
exports.sendEthErc20OffchainTransaction = sendEthErc20OffchainTransaction;
/**
* Sign Ethereum pending transaction from Tatum KMS
* @param tx pending transaction from KMS
* @param fromPrivateKey private key to sign transaction with.
* @param testnet mainnet or testnet version
* @param provider url of the Ethereum Server to connect to. If not set, default public server will be used.
* @returns transaction data to be broadcast to blockchain.
*/
const signEthOffchainKMSTransaction = async (tx, fromPrivateKey, testnet, provider) => {
if (tx.chain !== model_1.Currency.ETH) {
throw Error('Unsupported chain.');
}
const client = await transaction_1.getClient(provider, fromPrivateKey);
const transactionConfig = JSON.parse(tx.serializedTransaction);
transactionConfig.gas = await client.eth.estimateGas(transactionConfig);
if (!transactionConfig.nonce) {
transactionConfig.nonce = await blockchain_1.ethGetTransactionsCount(client.eth.defaultAccount);
}
if (!transactionConfig.gasPrice || transactionConfig.gasPrice === '0' || transactionConfig.gasPrice === 0 || transactionConfig.gasPrice === '0x0') {
transactionConfig.gasPrice = await transaction_1.ethGetGasPriceInWeiWrapper.ethGetGasPriceInWei();
}
return (await client.eth.accounts.signTransaction(transactionConfig, fromPrivateKey)).rawTransaction;
};
exports.signEthOffchainKMSTransaction = signEthOffchainKMSTransaction;
/**
* Sign Ethereum transaction with private keys locally. Nothing is broadcast to the blockchain.
* @returns transaction data to be broadcast to blockchain.
* @param body
*/
const prepareEthSignedOffchainTransaction = async (body) => {
await tatum_1.validateBody(body, model_1.PrepareEthSignedOffchainTransaction);
const { currency, address, amount, gasLimit, gasPrice, nonce, privateKey, web3, } = body;
let tx;
if (currency === model_1.Currency.ETH) {
tx = {
from: 0,
to: address.trim(),
value: web3.utils.toWei(amount, 'ether'),
gasPrice,
nonce,
};
}
else {
if (!Object.keys(constants_1.CONTRACT_ADDRESSES).includes(currency)) {
throw new Error('Unsupported ETH ERC20 blockchain.');
}
// @ts-ignore
const contract = new web3.eth.Contract(token_abi_1.default, constants_1.CONTRACT_ADDRESSES[currency]);
tx = {
from: 0,
to: constants_1.CONTRACT_ADDRESSES[currency],
data: contract.methods.transfer(address.trim(), `0x${new bignumber_js_1.default(amount).multipliedBy(new bignumber_js_1.default(10).pow(constants_1.CONTRACT_DECIMALS[currency])).toString(16)}`).encodeABI(),
gasPrice,
nonce,
};
}
tx.gas = gasLimit || await web3.eth.estimateGas(tx);
return {
txData: (await web3.eth.accounts.signTransaction(tx, privateKey)).rawTransaction,
gasLimit: tx.gas,
};
};
exports.prepareEthSignedOffchainTransaction = prepareEthSignedOffchainTransaction;
/**
* Sign Ethereum custom ERC20 transaction with private keys locally. Nothing is broadcast to the blockchain.
* @returns transaction data to be broadcast to blockchain.
* @param body
*/
const prepareEthErc20SignedOffchainTransaction = async (body) => {
await tatum_1.validateBody(body, model_1.PrepareEthErc20SignedOffchainTransaction);
const { amount, privateKey, address, gasPrice, nonce, tokenAddress, web3, gasLimit, } = body;
// @ts-ignore
const contract = new web3.eth.Contract(token_abi_1.default, tokenAddress);
const tx = {
from: 0,
to: tokenAddress.trim(),
data: contract.methods.transfer(address.trim(), `0x${new bignumber_js_1.default(amount).multipliedBy(new bignumber_js_1.default(10).pow(18)).toString(16)}`).encodeABI(),
gasPrice,
nonce,
};
tx.gas = gasLimit || await web3.eth.estimateGas(tx);
return {
txData: (await web3.eth.accounts.signTransaction(tx, privateKey)).rawTransaction,
gasLimit: tx.gas,
};
};
exports.prepareEthErc20SignedOffchainTransaction = prepareEthErc20SignedOffchainTransaction;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXRoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL29mZmNoYWluL2V0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGdFQUFvQztBQUVwQyw4Q0FBcUQ7QUFDckQsOENBQStDO0FBQy9DLDRDQUFrRTtBQUNsRSw2RUFBbUQ7QUFDbkQsc0NBQWtFO0FBQ2xFLG9DQUE0SztBQUM1SyxnREFBc0U7QUFDdEUsc0NBQXdEO0FBQ3hELHFDQUE2RjtBQUM3RiwrQkFBOEM7QUFFOUM7Ozs7Ozs7R0FPRztBQUNJLE1BQU0sMEJBQTBCLEdBQUcsS0FBSyxFQUFFLE9BQWdCLEVBQUUsSUFBeUIsRUFBRSxRQUFpQixFQUFFLEVBQUU7SUFDL0csSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFO1FBQ2xCLE9BQU8sNEJBQXNCLENBQUMsSUFBSSxDQUFDLENBQUE7S0FDdEM7SUFDRCxNQUFNLG9CQUFZLENBQUMsSUFBSSxFQUFFLDJCQUFtQixDQUFDLENBQUE7SUFDN0MsTUFBTSxFQUNGLFFBQVEsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEtBQUssS0FDbEMsSUFBSSxFQURtQyxVQUFVLFVBQ2pELElBQUksRUFGRiw0Q0FFTCxDQUFPLENBQUE7SUFDUixNQUFNLEVBQUMsTUFBTSxFQUFFLE9BQU8sRUFBQyxHQUFHLFVBQVUsQ0FBQTtJQUVwQyxJQUFJLFFBQWdCLENBQUE7SUFDcEIsSUFBSSxRQUFRLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRTtRQUNqQyxRQUFRLEdBQUcsUUFBUSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSx1Q0FBOEIsQ0FBQyxnQkFBUSxDQUFDLEdBQUcsRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFvQixDQUFBO0tBQ3JJO1NBQU0sSUFBSSxVQUFVLEVBQUU7UUFDbkIsUUFBUSxHQUFHLFVBQVUsQ0FBQTtLQUN4QjtTQUFN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