UNPKG

@algodex/algodex-sdk

Version:

API calls for interacting with the Algorand blockchain

320 lines (292 loc) 9.58 kB
/* * Copyright (C) 2021-2022 Algodex VASP (BVI) Corp. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ const algosdk = require('algosdk'); const logger = require('../logger'); const txns = require('./txns'); const {default: axios} = require('axios'); const getTransactionParams = require('./getTransactionParams'); /** * @deprecated * @type {string} */ const ALGOD_SERVER='http:/ec2-3-18-80-65.us-east-2.compute.amazonaws.com'; /** * @deprecated * @type {string} */ const ALGOD_TOKEN = '11e4dcfb445a8c7e8380848747f18afcd5d84ccb395e003e5b72127ca5e9a259'; // { 'X-API-Key': 'VELyABA1dGqGbAVktbew4oACvp0c0298gMgYtYIb' } /** * @deprecated * @type {string} */ const ALGOD_PORT='8080'; /** * @param {string} addr * @return {Promise<any>} * @deprecated */ async function getAccountInfo(addr) { try { const port = (ALGOD_PORT) ? ':' + ALGOD_PORT : ''; const response = await axios.get( ALGOD_SERVER + port + '/v2/accounts/'+addr, {headers: {'X-Algo-API-Token': ALGOD_TOKEN}}, ); return response.data; } catch (e) { logger.error(undefined, e.message); throw new Error(`getAccountInfo failed: ${e.message}`); } } /** * Send Groups Transactions * * @param {algosdk.Algodv2} client Algorand Client * @param {Object<Uint8Array>} groupsOfTransactions Transactions Keyed by Group * @return {Promise<void>} */ async function sendGroupsTransactions(client, groupsOfTransactions) { // terrible practice but fine for the time being. for (const group in groupsOfTransactions) { if (group !== 'prototype') { const {txId} = await client.sendRawTransaction(groupsOfTransactions[group]).do(); await algosdk.waitForConfirmation(client, txId, 10); } } } /** * Check Pending * * @param {algosdk.Algodv2} client Algorand Client * @param {string} txId Transaction ID * @return {Promise<PendingTransactionInformation>} */ async function checkPending(client, txId) { const pendingInfo = await client.pendingTransactionInformation(txId).do(); if (pendingInfo != null && pendingInfo.txn != null && pendingInfo.txn.txn != null) { return pendingInfo; } else { console.log('Looping'); return checkPending(client, txId); } } /** * Deprecated Wait For Confirmation * @deprecated * @param {algosdk.Algodv2} client Algorand Client * @param {string} txId Transaction ID * @return {Promise<PendingTransactionInformation>} */ async function waitForConfirmation(client, txId) { const status = (await client.status().do()); let lastRound = status['last-round']; const pendingInfo = await client.pendingTransactionInformation().do(); if (pendingInfo['confirmed-round'] !== null && pendingInfo['confirmed-round'] > 0) { // Got the completed Transaction logger.debug('Transaction ' + txId + ' confirmed in round ' + pendingInfo['confirmed-round']); return pendingInfo; } else { lastRound++; await client.statusAfterBlock(lastRound).do(); return waitForConfirmation(client, txId); } } /** * @param {algosdk.Algodv2} client Algorand Client * @param {Uint8Array | Uint8Array[]} stxOrStxs * @return {Promise<void>} */ async function sendAndCheckConfirmed(client, stxOrStxs) { const sendRawTxn = await client.sendRawTransaction(stxOrStxs).do(); await waitForConfirmation(client, sendRawTxn.txId); } /** * @param {algosdk.Algodv2} client Algorand Client * @param {Uint8Array | Uint8Array[]} stxOrStxs * @return {Promise<void>} */ async function sendAndCheckPending(client, stxOrStxs) { const sendRawTxn = await client.sendRawTransaction(stxOrStxs).do(); await checkPending(client, sendRawTxn.txId); } /** * Delete Application * * @param {algosdk.Algodv2} client Algorand Client * @param {algosdk.Account} sender Algorand Sender * @param {string|number} appId Application ID * @return {Promise<void>} */ async function deleteApplication(client, sender, appId) { // create unsigned transaction const params = await getTransactionParams(client); const txn = algosdk.makeApplicationDeleteTxn(sender.addr, params, appId); // sign, send, await const signedTxn = txn.signTxn(sender.sk); const txId = txn.txID().toString(); logger.debug('Signed transaction with txID: %s', txId); // Submit the transaction try { await client.sendRawTransaction(signedTxn).do(); } catch (e) { logger.error({'fn': 'deleteApplication'}, e.message ); } // display results await algosdk.waitForConfirmation(client, txId, 10); logger.debug('Deleted app-id: ', appId); } /** * Close Account * @param {algosdk.Algodv2} client * @param {algosdk.Account} fromAccount * @param {algosdk.Account} toAccount * @return {Promise<void>} */ async function closeAccount(client, fromAccount, toAccount) { logger.debug('teal.closeAccount - checking account info for: ' + fromAccount.addr); const fromAccountInfo = await getAccountInfo(fromAccount.addr); if (fromAccountInfo != null && fromAccountInfo['assets'] != null && fromAccountInfo['assets'].length > 0) { for (let i = 0; i < fromAccountInfo['assets'].length; i++) { const asset = fromAccountInfo['assets'][i]; const assetId = asset['asset-id']; logger.info('closing asset: ' + assetId + ' for account: ' + fromAccount.addr); const txn = await txns.makeAssetTransferTxn(client, fromAccount, toAccount, 0, assetId, undefined, true); const signedTxn = algosdk.signTransaction(txn, fromAccount.sk); await sendAndCheckPending(client, [signedTxn.blob]); } } const fundTxn = await txns.makePaymentTxn(client, fromAccount, toAccount, 0, true); const fundTxnId = fundTxn.txID().toString(); const signedTxn = fundTxn.signTxn(fromAccount.sk); logger.info('Signed transaction with txID: %s', fundTxnId); // Submit the transaction try { await client.sendRawTransaction(signedTxn).do(); } catch (e) { logger.error(undefined, e.message); } await checkPending(client, fundTxnId); } /** * @param {algosdk.Algodv2} client * @param {algosdk.Account} fromAccount * @param {algosdk.Account} toAccount * @param {number} amount * @return {Promise<void>} */ async function transferFunds(client, fromAccount, toAccount, amount) { const fundTxn = await txns.makePaymentTxn( client, fromAccount, toAccount, amount, false, ); const fundTxnId = fundTxn.txID().toString(); const signedFundTxn = fundTxn.signTxn(fromAccount.sk); logger.debug('Signed transaction with txID: %s', fundTxnId); // Submit the transaction try { await client.sendRawTransaction(signedFundTxn).do(); } catch (e) { logger.debug(JSON.stringify(e)); } // Wait for confirmation await checkPending(client, fundTxnId); } /** * @param {string} accountAddr * @param {number} assetId * @return {Promise<null|*>} */ async function getAssetBalance(accountAddr, assetId) { logger.debug('checking account info for: ' + accountAddr); const accountInfo = await getAccountInfo(accountAddr); if (accountInfo != null && accountInfo['assets'] != null && accountInfo['assets'].length > 0) { for (let i = 0; i < accountInfo['assets'].length; i++) { const asset = accountInfo['assets'][i]; logger.debug({asset} ); if (asset['asset-id'] === assetId) { return asset['amount']; } } } return null; } /** * @param {Array<Object>} outerTxns * @return {Array} */ function groupAndSignTransactions(outerTxns) { logger.info('inside signAndSend transactions'); const _txns = []; for (let i = 0; i < outerTxns.length; i++) { _txns.push(outerTxns[i].unsignedTxn); } const groupID = algosdk.computeGroupID(_txns); for (let i = 0; i < _txns.length; i++) { _txns[i].group = groupID; } for (let i = 0; i < outerTxns.length; i++) { const txn = outerTxns[i]; if (txn.lsig != null) { const signedLsig = algosdk.signLogicSigTransactionObject(txn.unsignedTxn, txn.lsig); txn.signedTxn = signedLsig.blob; } else { const signedTxn = algosdk.signTransaction(txn.unsignedTxn, txn.senderAcct.sk); txn.signedTxn = signedTxn.blob; } } const signed = []; for (let i = 0; i < outerTxns.length; i++) { signed.push(outerTxns[i].signedTxn); } logger.debug('printing transaction debug'); // algodex.printTransactionDebug(signed); return signed; } /** * @param {algosdk.Algodv2} client Algorand Client * @param {algosdk.Account} fromAccount * @param {algosdk.Account} toAccount * @param {number} amount * @param {string|number} assetId * @return {Promise<void>} */ async function transferASA( client, fromAccount, toAccount, amount, assetId, ) { const asaTransferTxn = await txns.makeAssetTransferTxn(client, fromAccount, toAccount, amount, assetId, false); const asaTxnId = asaTransferTxn.txID().toString(); const signedFundTxn = asaTransferTxn.signTxn(fromAccount.sk); logger.debug('Signed transaction with txID: %s', asaTxnId); // Submit the transaction try { await client.sendRawTransaction(signedFundTxn).do(); } catch (e) { logger.error(undefined, e.message); } // Wait for confirmation await checkPending(client, asaTxnId); } module.exports = { sendGroupsTransactions, deleteApplication, closeAccount, getAssetBalance, getAccountInfo, transferFunds, checkPending, transferASA, sendAndCheckConfirmed, sendAndCheckPending, waitForConfirmation, groupAndSignTransactions, };