@tatumio/algo-connector
Version:
ALGO Connector for Tatum API
207 lines (206 loc) • 9.18 kB
JavaScript
;
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;