UNPKG

@tatumio/tatum-v1

Version:

Tatum API client allows browsers and Node.js clients to interact with Tatum API.

231 lines 20.5 kB
"use strict"; 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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