UNPKG

@tatumio/tatum-v1

Version:

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

169 lines 15.6 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.signAdaOffchainKMSTransaction = exports.sendAdaOffchainTransaction = void 0; const cardano_serialization_lib_nodejs_1 = require("@emurgo/cardano-serialization-lib-nodejs"); const bignumber_js_1 = __importDefault(require("bignumber.js")); const tatum_1 = require("../connector/tatum"); 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 Ada 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 sendAdaOffchainTransaction = async (testnet, body) => { if (body.signatureId) { return kms_1.offchainTransferAdaKMS(body); } await tatum_1.validateBody(body, model_1.TransferBtcBasedOffchain); const { mnemonic, keyPair, xpub, attr: changeAddress } = body, withdrawal = __rest(body, ["mnemonic", "keyPair", "xpub", "attr"]); if (!withdrawal.fee) { withdrawal.fee = '1'; } const { id, data } = await common_1.offchainStoreWithdrawal(withdrawal); const { amount, address, } = withdrawal; let txData; try { txData = await prepareAdaSignedOffchainTransaction(testnet, data, amount, address, mnemonic, keyPair, changeAddress, xpub, 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.ADA })), { id }); } catch (e) { console.error(e); try { await common_1.offchainCancelWithdrawal(id); } catch (e1) { console.log(e); return { id }; } throw e; } }; exports.sendAdaOffchainTransaction = sendAdaOffchainTransaction; const prepareAdaSignedOffchainTransaction = async (testnet, data, amount, address, mnemonic, keyPair, changeAddress, xpub, multipleAmounts, signatureId) => { var _a; const txBuilder = await transaction_1.initTransactionBuilder(); const fromAddress = data.filter(input => input.address).map(input => ({ address: input.address.address })); await transaction_1.addAddressInputsWithoutPrivateKey(txBuilder, fromAddress); addOffchainInputs(txBuilder, data); if (multipleAmounts === null || multipleAmounts === void 0 ? void 0 : multipleAmounts.length) { for (const [i, multipleAmount] of multipleAmounts.entries()) { transaction_1.addOutputAda(txBuilder, address.split(',')[i], multipleAmount); } } else { transaction_1.addOutputAda(txBuilder, address, amount); } const lastVin = data.find(d => d.vIn === '-1'); if (new bignumber_js_1.default(lastVin.amount).isGreaterThan(0)) { if (xpub) { const zeroAddress = await wallet_1.generateAddressFromXPub(model_1.Currency.ADA, testnet, xpub, 0); transaction_1.addOutputAda(txBuilder, zeroAddress, lastVin.amount); } else if (changeAddress) { transaction_1.addOutputAda(txBuilder, changeAddress, lastVin.amount); } else { throw new Error('Impossible to prepare transaction. Either xpub or keyPair and attr must be present.'); } } const lovelaceFee = transaction_1.adaToLovelace(1); txBuilder.set_fee(cardano_serialization_lib_nodejs_1.BigNum.from_str(lovelaceFee)); const txBody = txBuilder.build(); if (signatureId) { return JSON.stringify({ txData: txBody.to_bytes().toString() }); } const vKeyWitnesses = cardano_serialization_lib_nodejs_1.Vkeywitnesses.new(); const txHash = cardano_serialization_lib_nodejs_1.hash_transaction(txBody); for (const input of data) { // when there is no address field present, input is pool transfer to 0 if (input.vIn === '-1') { continue; } if (mnemonic) { const derivationKey = ((_a = input.address) === null || _a === void 0 ? void 0 : _a.derivationKey) || 0; const privateKey = await wallet_1.generatePrivateKeyFromMnemonic(model_1.Currency.ADA, testnet, mnemonic, derivationKey); transaction_1.makeWitness(privateKey, txHash, vKeyWitnesses); } else if (keyPair) { const { privateKey } = keyPair.find(k => k.address === input.address.address); transaction_1.makeWitness(privateKey, txHash, vKeyWitnesses); } else { throw new Error('Impossible to prepare transaction. Either mnemonic or keyPair and attr must be present.'); } } const witnesses = cardano_serialization_lib_nodejs_1.TransactionWitnessSet.new(); witnesses.set_vkeys(vKeyWitnesses); return Buffer.from(cardano_serialization_lib_nodejs_1.Transaction.new(txBody, witnesses).to_bytes()).toString('hex'); }; const addOffchainInputs = (transactionBuilder, inputs) => { var _a; let amount = new bignumber_js_1.default(0); for (const input of inputs) { if (input.vIn !== '-1' && input.amount && input.vInIndex !== undefined && ((_a = input.address) === null || _a === void 0 ? void 0 : _a.address)) { transaction_1.addInput(transactionBuilder, { value: transaction_1.adaToLovelace(input.amount), index: input.vInIndex, txHash: input.vIn, }, input.address.address); amount = amount.plus(input.amount); } } return amount; }; /** * Sign Ada 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 signAdaOffchainKMSTransaction = async (tx, mnemonic, testnet) => { var _a; if (tx.chain !== model_1.Currency.ADA || !tx.withdrawalResponses) { throw Error('Unsupported chain.'); } const txData = JSON.parse(tx.serializedTransaction).txData; const transactionBody = cardano_serialization_lib_nodejs_1.TransactionBody.from_bytes(Uint8Array.from(txData.split(','))); const txHash = cardano_serialization_lib_nodejs_1.hash_transaction(transactionBody); const vKeyWitnesses = cardano_serialization_lib_nodejs_1.Vkeywitnesses.new(); for (const response of tx.withdrawalResponses) { if (response.vIn === '-1') { continue; } const privateKey = await wallet_1.generatePrivateKeyFromMnemonic(model_1.Currency.ADA, testnet, mnemonic, ((_a = response.address) === null || _a === void 0 ? void 0 : _a.derivationKey) || 0); transaction_1.makeWitness(privateKey, txHash, vKeyWitnesses); } const witnesses = cardano_serialization_lib_nodejs_1.TransactionWitnessSet.new(); witnesses.set_vkeys(vKeyWitnesses); return Buffer.from(cardano_serialization_lib_nodejs_1.Transaction.new(transactionBody, witnesses).to_bytes()).toString('hex'); }; exports.signAdaOffchainKMSTransaction = signAdaOffchainKMSTransaction; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL29mZmNoYWluL2FkYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLCtGQVFrRDtBQUNsRCxnRUFBcUM7QUFDckMsOENBQWtEO0FBQ2xELG9DQUErRztBQUMvRyxnREFPd0I7QUFDeEIsc0NBQW9GO0FBQ3BGLHFDQUFnRztBQUNoRywrQkFBOEM7QUFFOUM7Ozs7OztHQU1HO0FBQ0ksTUFBTSwwQkFBMEIsR0FBRyxLQUFLLEVBQUUsT0FBZ0IsRUFBRSxJQUE4QixFQUFFLEVBQUU7SUFDakcsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFO1FBQ2xCLE9BQU8sNEJBQXNCLENBQUMsSUFBSSxDQUFDLENBQUE7S0FDdEM7SUFDRCxNQUFNLG9CQUFZLENBQUMsSUFBSSxFQUFFLGdDQUF3QixDQUFDLENBQUM7SUFDbkQsTUFBTSxFQUNGLFFBQVEsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxhQUFhLEtBQzVDLElBQUksRUFENkMsVUFBVSxVQUMzRCxJQUFJLEVBRkYsdUNBRUwsQ0FBTyxDQUFBO0lBQ1IsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUU7UUFDakIsVUFBVSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUE7S0FDdkI7SUFDRCxNQUFNLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sZ0NBQXVCLENBQUMsVUFBVSxDQUFDLENBQUE7SUFDOUQsTUFBTSxFQUNGLE1BQU0sRUFBRSxPQUFPLEdBQ2xCLEdBQUcsVUFBVSxDQUFBO0lBQ2QsSUFBSSxNQUFNLENBQUE7SUFDVixJQUFJO1FBQ0EsTUFBTSxHQUFHLE1BQU0sbUNBQW1DLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSxVQUFVLENBQUMsZUFB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