@algodex/algodex-sdk-patch
Version:
API calls for interacting with the Algorand blockchain
385 lines (340 loc) • 11.6 kB
JavaScript
/////////////////////////////
// Alexander Trefonas //
// 7/9/2021 //
// Copyright Algodev Inc //
// All Rights Reserved. //
/////////////////////////////
const http = require('http');
const algosdk = require('algosdk');
const axios = require('axios').default;
const algoDelegateTemplate = require('./algo_delegate_template_teal.js');
const asaDelegateTemplate = require('./ASA_delegate_template_teal.js');
const algoOrderBook = require('./dex_teal.js');
const asaOrderBook = require('./asa_dex_teal.js');
//require('./dex_teal.js');
const dexInternal = require('./algodex_internal_api.js');
const algodex = require('./algodex_api.js');
const constants = require('./constants.js');
const transactionGenerator = require('./generate_transaction_types.js');
let ALGO_ESCROW_ORDER_BOOK_ID = -1;
let ASA_ESCROW_ORDER_BOOK_ID = -1;
const ALGOD_SERVER = 'https://testnet-api.algonode.cloud';
const ALGOD_TOKEN = ''; //{ 'X-API-Key': 'VELyABA1dGqGbAVktbew4oACvp0c0298gMgYtYIb' }
const ALGOD_PORT = '';
const TestHelper = {
getLocalClient: function getLocalClientAndEnv() {
//const algodClient = algodex.initAlgodClient("test");
const algodClient = new algosdk.Algodv2(
ALGOD_TOKEN,
ALGOD_SERVER,
ALGOD_PORT
);
return algodClient;
},
getRandomAccount: function getRandomAccount() {
return algosdk.generateAccount();
},
getAccountInfo: async function getAccountInfo(addr) {
return algodex.getAccountInfo(addr);
// This is the old account info that uses algod, not the indexer
// This is necessary for the tests to go faster as the indexer takes time to update.
/*try {
let port = (!!ALGOD_PORT) ? ':' + ALGOD_PORT : '';
const response = await axios.get(ALGOD_SERVER + port + "/v2/accounts/"+addr, {headers: {'X-Algo-API-Token': ALGOD_TOKEN}});
//console.debug(response);
return response.data;
} catch (error) {
console.error(error);
throw new Error("getAccountInfo failed: ", error);
}*/
},
printOuterTransactions: function (outerTxns) {
for (let i = 0; i < outerTxns.length; i++) {
console.log(outerTxns[i]);
}
},
checkFailureType: function (error) {
let hasKnownError = false;
if (error != null && error.response.body.message != null) {
const msg = error.response.body.message;
if (msg.includes('rejected by logic err=')) {
hasKnownError = true;
} else if (msg.includes('TEAL runtime encountered err opcode')) {
hasKnownError = true;
} else {
throw 'Unknown error type: ' + msg;
}
}
return hasKnownError;
},
getOpenAccount: function getOpenAccount() {
//WYWRYK42XADLY3O62N52BOLT27DMPRA3WNBT2OBRT65N6OEZQWD4OSH6PI
let mn =
'mass army warrior number blush distance enroll vivid horse become spend asthma hat desert amazing room asset ivory lucky ridge now deputy erase absorb above';
let openAccount = algosdk.mnemonicToSecretKey(mn);
return openAccount;
},
transferASA: async function (
client,
fromAccount,
toAccount,
amount,
assetId
) {
const asaTransferTxn = await transactionGenerator.getAssetSendTxn(
client,
fromAccount,
toAccount,
amount,
assetId,
false
);
const asaTxnId = asaTransferTxn.txID().toString();
let signedFundTxn = asaTransferTxn.signTxn(fromAccount.sk);
console.log('Signed transaction with txID: %s', asaTxnId);
// Submit the transaction
try {
await client.sendRawTransaction(signedFundTxn).do();
} catch (e) {
console.log(JSON.stringify(e));
}
// Wait for confirmation
await this.checkPending(client, asaTxnId);
},
transferFunds: async function (client, fromAccount, toAccount, amount) {
const fundTxn = await transactionGenerator.getPayTxn(
client,
fromAccount,
toAccount,
amount,
false
);
const fundTxnId = fundTxn.txID().toString();
let signedFundTxn = fundTxn.signTxn(fromAccount.sk);
console.log('Signed transaction with txID: %s', fundTxnId);
// Submit the transaction
try {
await client.sendRawTransaction(signedFundTxn).do();
} catch (e) {
console.log(JSON.stringify(e));
}
// Wait for confirmation
await this.checkPending(client, fundTxnId);
},
sendAndCheckConfirmed: async function (client, signedTxns) {
// Submit the transaction
let txId = null;
try {
let sentTxns = await client.sendRawTransaction(signedTxns).do();
txId = sentTxns.txId;
} catch (e) {
throw e;
}
// Wait for confirmation
await this.waitForConfirmation(client, txId);
},
sendAndCheckPending: async function (client, signedTxns) {
// Submit the transaction
let txId = null;
try {
let sentTxns = await client.sendRawTransaction(signedTxns).do();
txId = sentTxns.txId;
} catch (e) {
throw e;
}
// Wait for confirmation
await this.checkPending(client, txId);
},
getOrderLsig: async function (
algodClient,
makerAccount,
price,
assetId,
isASAEscrow
) {
const orderCreatorAddr = makerAccount.addr;
const numAndDenom = algodex.getNumeratorAndDenominatorFromPrice(price);
const n = numAndDenom.n;
const d = numAndDenom.d;
const escrowSource = algodex.buildDelegateTemplateFromArgs(
0,
assetId,
n,
d,
orderCreatorAddr,
isASAEscrow,
constants.ESCROW_CONTRACT_VERSION
);
const lsig = await algodex.getLsigFromProgramSource(
algosdk,
algodClient,
escrowSource,
constants.DEBUG_SMART_CONTRACT_SOURCE
);
return lsig;
},
getAssetBalance: async function (accountAddr, assetId) {
console.log('checking account info for: ' + accountAddr);
const accountInfo = await this.getAccountInfo(accountAddr);
if (
accountInfo != null &&
accountInfo['assets'] != null &&
accountInfo['assets'].length > 0
) {
for (let i = 0; i < accountInfo['assets'].length; i++) {
let asset = accountInfo['assets'][i];
console.log({ asset });
if (asset['asset-id'] == assetId) {
return asset['amount'];
}
}
}
return null;
},
closeAccount: async function closeAccount(client, fromAccount, toAccount) {
console.log('checking account info for: ' + fromAccount.addr);
const fromAccountInfo = await this.getAccountInfo(fromAccount.addr);
if (
fromAccountInfo != null &&
fromAccountInfo['assets'] != null &&
fromAccountInfo['assets'].length > 0
) {
for (let i = 0; i < fromAccountInfo['assets'].length; i++) {
let asset = fromAccountInfo['assets'][i];
let assetId = asset['asset-id'];
console.log(
'closing asset: ' + assetId + ' for account: ' + fromAccount.addr
);
let txn = await transactionGenerator.getAssetSendTxn(
client,
fromAccount,
toAccount,
0,
assetId,
true
);
let signedTxn = algosdk.signTransaction(txn, fromAccount.sk);
await this.sendAndCheckPending(client, [signedTxn.blob]);
}
}
const fundTxn = await transactionGenerator.getPayTxn(
client,
fromAccount,
toAccount,
0,
true
);
const fundTxnId = fundTxn.txID().toString();
let signedTxn = fundTxn.signTxn(fromAccount.sk);
console.log('Signed transaction with txID: %s', fundTxnId);
// Submit the transaction
try {
await client.sendRawTransaction(signedTxn).do();
} catch (e) {
console.log(JSON.stringify(e));
}
await this.checkPending(client, fundTxnId);
},
deleteApplication: async function deleteApplication(client, sender, appId) {
// create unsigned transaction
let params = await client.getTransactionParams().do();
let txn = algosdk.makeApplicationDeleteTxn(sender.addr, params, appId);
// sign, send, await
let signedTxn = txn.signTxn(sender.sk);
let txId = txn.txID().toString();
console.log('Signed transaction with txID: %s', txId);
// Submit the transaction
try {
await client.sendRawTransaction(signedTxn).do();
} catch (e) {
console.log(JSON.stringify(e));
}
// display results
let transactionResponse = await client
.pendingTransactionInformation(txId)
.do();
console.log('Deleted app-id: ', appId);
},
getExecuteAccount: function getExecuteAccount() {
//UUEUTRNQY7RUXESXRDO7HSYRSJJSSVKYVB4DI7X2HVVDWYOBWJOP5OSM3A
let mn =
'three satisfy build purse lens another idle fashion base equal echo recall proof hill shadow coach early palm act wealth dawn menu portion above mystery';
let executeAccount = algosdk.mnemonicToSecretKey(mn);
return executeAccount;
},
// helper function to await transaction confirmation
waitForConfirmation: async function waitForConfirmation(algodClient, txId) {
let status = await algodClient.status().do();
let lastRound = status['last-round'];
while (true) {
const pendingInfo = await algodClient
.pendingTransactionInformation(txId)
.do();
if (
pendingInfo['confirmed-round'] !== null &&
pendingInfo['confirmed-round'] > 0
) {
//Got the completed Transaction
console.log(
'Transaction ' +
txId +
' confirmed in round ' +
pendingInfo['confirmed-round']
);
break;
}
lastRound++;
await algodClient.statusAfterBlock(lastRound).do();
}
},
// helper function to await transaction confirmation
checkPending: async function checkPending(algodClient, txId) {
while (true) {
const pendingInfo = await algodClient
.pendingTransactionInformation(txId)
.do();
if (
pendingInfo != null &&
pendingInfo.txn != null &&
pendingInfo.txn.txn != null
) {
break;
}
}
},
groupAndSignTransactions: function (outerTxns) {
console.log('inside signAndSend transactions');
let 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++) {
let txn = outerTxns[i];
if (txn.lsig != null) {
let signedLsig = algosdk.signLogicSigTransactionObject(
txn.unsignedTxn,
txn.lsig
);
txn.signedTxn = signedLsig.blob;
} else {
let signedTxn = algosdk.signTransaction(
txn.unsignedTxn,
txn.senderAcct.sk
);
txn.signedTxn = signedTxn.blob;
}
}
let signed = [];
for (let i = 0; i < outerTxns.length; i++) {
signed.push(outerTxns[i].signedTxn);
}
console.log('printing transaction debug');
algodex.printTransactionDebug(signed);
return signed;
},
};
module.exports = TestHelper;