UNPKG

@tatumio/algo-connector

Version:

ALGO Connector for Tatum API

207 lines (206 loc) 9.18 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AlgoService = void 0; const axios_1 = __importDefault(require("axios")); const tatum_1 = require("@tatumio/tatum"); const blockchain_connector_common_1 = require("@tatumio/blockchain-connector-common"); const AlgoError_1 = require("./AlgoError"); class AlgoService { constructor(logger) { this.logger = logger; } static mapBlock(block) { return { genesisHash: block['genesis-hash'], genesisId: block['genesis-id'], previousBlockHash: block['previous-block-hash'], rewards: block.rewards, round: block.round, seed: block.seed, timestamp: block.timestamp, txns: block.transactions.map(AlgoService.mapTransaction), txn: block['transactions-root'], txnc: block['txn-counter'], upgradeState: block['upgrade-state'], upgradeVote: block['upgrade-vote'] }; } static mapTransaction(tx) { return { closeRewards: tx['close-rewards'], closingAmount: tx['closing-amount'] ? tx['closing-amount'] / 1000000 : tx['closing-amount'], confirmedRound: tx['confirmed-round'], fee: tx.fee / 1000000, firstValid: tx['first-valid'], genesisHash: tx['genesis-hash'], genesisId: tx['genesis-id'], id: tx.id, intraRoundOffset: tx['intra-round-offset'], lastValid: tx['last-valid'], note: tx.note, paymentTransaction: tx['payment-transaction'] ? { ...tx['payment-transaction'], amount: tx['payment-transaction'].amount / 1000000 } : tx['payment-transaction'], receiverRewards: tx['receiver-rewards'], roundTime: tx['round-time'], sender: tx.sender, senderRewards: tx['sender-rewards'], signature: tx.signature, txType: tx['tx-type'], }; } ; async getClient(testnet) { return tatum_1.getAlgoClient(testnet !== undefined ? testnet : await this.isTestnet(), (await this.getNodesUrl(blockchain_connector_common_1.AlgoNodeType.ALGOD))[0]); } async getIndexerClient() { return tatum_1.getAlgoIndexerClient(await this.isTestnet(), (await this.getNodesUrl(blockchain_connector_common_1.AlgoNodeType.INDEXER))[0]); } async generateWallet(mnem) { return tatum_1.generateAlgoWallet(mnem); } async generateAddress(fromPrivateKey) { return tatum_1.generateAlgodAddressFromPrivatetKey(fromPrivateKey); } async sendTransaction(tx) { const txData = await tatum_1.prepareAlgoSignedTransaction(await this.isTestnet(), tx, (await this.getNodesUrl(blockchain_connector_common_1.AlgoNodeType.ALGOD))[0]); return this.broadcastOrStoreKMSTransaction({ transactionData: txData, signatureId: tx.signatureId, index: tx.index }); } async getBalance(address) { const client = await this.getClient(); const accountInfo = await client.accountInformation(address).do(); return accountInfo.amount / 1000000; } async broadcastOrStoreKMSTransaction({ transactionData, signatureId, index }) { if (signatureId) { return { signatureId: await this.storeKMSTransaction(transactionData, tatum_1.Currency.ALGO, [signatureId], index), }; } return this.broadcast(transactionData); } async waitForConfirmation(algodClient, txId) { let lastround = (await algodClient.status().do())['last-round']; let limit = 0; while (limit < 2) { const pendingInfo = await algodClient.pendingTransactionInformation(txId).do(); if (pendingInfo['confirmed-round']) { return true; } else if (pendingInfo['pool-error']) { return false; } lastround++; limit++; await algodClient.statusAfterBlock(lastround).do(); } return false; } async broadcast(txData, signatureId) { this.logger.info(`Broadcast tx for ALGO with data '${txData}'`); const client = await this.getClient(); const sendTx = await client.sendRawTransaction(txData).do(); const confirm = await this.waitForConfirmation(client, sendTx.txId); if (confirm) { if (signatureId) { try { await this.completeKMSTransaction(sendTx.txId, signatureId); } catch (e) { this.logger.error(e); return { txId: sendTx.txId, failed: true }; } } return { txId: sendTx.txId }; } else { throw new AlgoError_1.AlgoError(`Failed Algo Transaction Signing`, 'algo.error'); } } async getCurrentBlock(testnet) { const client = await this.getClient(testnet); return (await client.getTransactionParams().do()).firstRound; } async getBlock(roundNumber) { try { const indexerClient = await this.getIndexerClient(); const blockInfo = await indexerClient.lookupBlock(roundNumber).do(); return AlgoService.mapBlock(blockInfo); } catch (_) { throw new AlgoError_1.AlgoError(`Failed Algo get block by round number`, 'algo.error'); } } async getTransaction(txid) { try { const indexerClient = await this.getIndexerClient(); const transactionInfo = (await indexerClient.lookupTransactionByID(txid).do()).transaction; return AlgoService.mapTransaction(transactionInfo); } catch (_) { throw new AlgoError_1.AlgoError(`Failed Algo get transaction by transaction id`, 'algo.error'); } } async getPayTransactions(from, to, limit, next, testnet) { const isTestnet = testnet || (await this.isTestnet()); const baseurl = (await this.getNodesUrl(blockchain_connector_common_1.AlgoNodeType.INDEXER))[0]; const apiUrl = `${baseurl}/v2/transactions?tx-type=pay&after-time=${from}&before-time=${to}` + (limit ? `&limit=${limit}` : '') + (next ? `&next=${next}` : ''); try { const res = (await axios_1.default({ method: 'get', url: apiUrl, headers: isTestnet ? (process.env.TATUM_ALGORAND_TESTNET_THIRD_API_KEY ? {} : { 'X-API-Key': `${process.env.TATUM_ALGORAND_TESTNET_THIRD_API_KEY}` }) : (process.env.TATUM_ALGORAND_MAINNET_THIRD_API_KEY ? {} : { 'X-API-Key': `${process.env.TATUM_ALGORAND_MAINNET_THIRD_API_KEY}` }) })).data; const transactions = res.transactions.map(AlgoService.mapTransaction); return { nextToken: res['next-token'], transactions: transactions }; } catch (e) { this.logger.error(e); throw new AlgoError_1.AlgoError(`Failed Algo get pay transactions by from and to`, 'algo.error'); } } async getPayTransactionsByBlockRange(from, to, testnet) { const isTestnet = testnet || (await this.isTestnet()); const baseurl = (await this.getNodesUrl(blockchain_connector_common_1.AlgoNodeType.INDEXER))[0]; const apiUrl = `${baseurl}/v2/transactions?tx-type=pay&min-round=${from}&max-round=${to}`; try { const res = (await axios_1.default({ method: 'get', url: apiUrl, headers: isTestnet ? (process.env.TATUM_ALGORAND_TESTNET_THIRD_API_KEY ? {} : { 'X-API-Key': `${process.env.TATUM_ALGORAND_TESTNET_THIRD_API_KEY}` }) : (process.env.TATUM_ALGORAND_MAINNET_THIRD_API_KEY ? {} : { 'X-API-Key': `${process.env.TATUM_ALGORAND_MAINNET_THIRD_API_KEY}` }) })).data; const transations = res.transactions.map(AlgoService.mapTransaction); return { transactions: transations }; } catch (e) { this.logger.error(e); throw new AlgoError_1.AlgoError(`Failed Algo get pay transactions by from and to`, 'algo.error'); } } async nodeMethod(req, key, algoNodeType) { try { const path = req.url; const baseURL = (await this.getNodesUrl(algoNodeType))[0]; const [_, url] = path.split(`/${key}/`); const config = { method: req.method || 'GET', url, baseURL, headers: { 'content-type': 'application/json', 'X-API-Key': key, }, ...(Object.keys(req.body).length ? { data: req.body } : {}), }; return (await axios_1.default.request(config)).data; } catch (e) { this.logger.error(e); throw e; } } } exports.AlgoService = AlgoService;