@algorandfoundation/algokit-utils 9.1.1-beta.3 → 9.1.1-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/testing/transaction-logger.d.ts +2 -0
- package/testing/transaction-logger.js +26 -7
- package/testing/transaction-logger.js.map +1 -1
- package/testing/transaction-logger.mjs +26 -7
- package/testing/transaction-logger.mjs.map +1 -1
- package/types/app-client.d.ts +1 -1
- package/types/app-client.js +11 -7
- package/types/app-client.js.map +1 -1
- package/types/app-client.mjs +11 -7
- package/types/app-client.mjs.map +1 -1
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"**"
|
|
7
7
|
],
|
|
8
8
|
"name": "@algorandfoundation/algokit-utils",
|
|
9
|
-
"version": "9.1.1-beta.
|
|
9
|
+
"version": "9.1.1-beta.5",
|
|
10
10
|
"private": false,
|
|
11
11
|
"description": "A set of core Algorand utilities written in TypeScript and released via npm that make it easier to build solutions on Algorand.",
|
|
12
12
|
"author": "Algorand Foundation",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var algosdk = require('algosdk');
|
|
4
|
+
var config = require('../config.js');
|
|
4
5
|
var indexer = require('./indexer.js');
|
|
5
6
|
|
|
6
7
|
var decodeSignedTransaction = algosdk.decodeSignedTransaction;
|
|
@@ -12,6 +13,13 @@ class TransactionLogger {
|
|
|
12
13
|
constructor() {
|
|
13
14
|
this._sentTransactionIds = [];
|
|
14
15
|
}
|
|
16
|
+
_pushTxn(stxn) {
|
|
17
|
+
const decoded = decodeSignedTransaction(stxn);
|
|
18
|
+
if (decoded.txn.lastValid > (this._latestLastValidRound ?? BigInt(0))) {
|
|
19
|
+
this._latestLastValidRound = BigInt(decoded.txn.lastValid);
|
|
20
|
+
}
|
|
21
|
+
this._sentTransactionIds.push(decoded.txn.txID());
|
|
22
|
+
}
|
|
15
23
|
/**
|
|
16
24
|
* The list of transaction IDs that has been logged thus far.
|
|
17
25
|
*/
|
|
@@ -29,14 +37,10 @@ class TransactionLogger {
|
|
|
29
37
|
*/
|
|
30
38
|
logRawTransaction(signedTransactions) {
|
|
31
39
|
if (Array.isArray(signedTransactions)) {
|
|
32
|
-
|
|
33
|
-
const decoded = decodeSignedTransaction(stxn);
|
|
34
|
-
this._sentTransactionIds.push(decoded.txn.txID());
|
|
35
|
-
}
|
|
40
|
+
signedTransactions.forEach((stxn) => this._pushTxn(stxn));
|
|
36
41
|
}
|
|
37
42
|
else {
|
|
38
|
-
|
|
39
|
-
this._sentTransactionIds.push(decoded.txn.txID());
|
|
43
|
+
this._pushTxn(signedTransactions);
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
46
|
/** Return a proxy that wraps the given Algodv2 with this transaction logger.
|
|
@@ -52,7 +56,22 @@ class TransactionLogger {
|
|
|
52
56
|
if (this._sentTransactionIds.length === 0)
|
|
53
57
|
return;
|
|
54
58
|
const lastTxId = this._sentTransactionIds[this._sentTransactionIds.length - 1];
|
|
55
|
-
await indexer.runWhenIndexerCaughtUp(() =>
|
|
59
|
+
await indexer.runWhenIndexerCaughtUp(async () => {
|
|
60
|
+
try {
|
|
61
|
+
await indexer$1.lookupTransactionByID(lastTxId).do();
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
// If the txid lookup failed, then try to look up the last valid round
|
|
65
|
+
// If that round exists, then we know indexer is caught up
|
|
66
|
+
if (this._latestLastValidRound) {
|
|
67
|
+
await indexer$1.lookupBlock(this._latestLastValidRound).do();
|
|
68
|
+
config.Config.getLogger().debug(`waitForIndexer has waited until the last valid round ${this._latestLastValidRound} was indexed, but did not find transaction ${lastTxId} in the indexer.`);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw e;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
56
75
|
}
|
|
57
76
|
}
|
|
58
77
|
class TransactionLoggingAlgodv2ProxyHandler {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-logger.js","sources":["../../src/testing/transaction-logger.ts"],"sourcesContent":["import algosdk from 'algosdk'\nimport { runWhenIndexerCaughtUp } from './indexer'\nimport Algodv2 = algosdk.Algodv2\nimport decodeSignedTransaction = algosdk.decodeSignedTransaction\nimport Indexer = algosdk.Indexer\n\n/**\n * Allows you to keep track of Algorand transaction IDs by wrapping an `Algodv2` in a proxy.\n * Useful for automated tests.\n */\nexport class TransactionLogger {\n private _sentTransactionIds: string[] = []\n\n /**\n * The list of transaction IDs that has been logged thus far.\n */\n get sentTransactionIds(): Readonly<string[]> {\n return this._sentTransactionIds\n }\n\n /**\n * Clear all logged IDs.\n */\n clear() {\n this._sentTransactionIds = []\n }\n\n /**\n * The method that captures raw transactions and stores the transaction IDs.\n */\n logRawTransaction(signedTransactions: Uint8Array | Uint8Array[]) {\n if (Array.isArray(signedTransactions)) {\n
|
|
1
|
+
{"version":3,"file":"transaction-logger.js","sources":["../../src/testing/transaction-logger.ts"],"sourcesContent":["import algosdk from 'algosdk'\nimport { Config } from '../config'\nimport { runWhenIndexerCaughtUp } from './indexer'\nimport Algodv2 = algosdk.Algodv2\nimport decodeSignedTransaction = algosdk.decodeSignedTransaction\nimport Indexer = algosdk.Indexer\n\n/**\n * Allows you to keep track of Algorand transaction IDs by wrapping an `Algodv2` in a proxy.\n * Useful for automated tests.\n */\nexport class TransactionLogger {\n private _sentTransactionIds: string[] = []\n private _latestLastValidRound?: bigint\n\n private _pushTxn(stxn: Uint8Array) {\n const decoded = decodeSignedTransaction(stxn)\n if (decoded.txn.lastValid > (this._latestLastValidRound ?? BigInt(0))) {\n this._latestLastValidRound = BigInt(decoded.txn.lastValid)\n }\n this._sentTransactionIds.push(decoded.txn.txID())\n }\n\n /**\n * The list of transaction IDs that has been logged thus far.\n */\n get sentTransactionIds(): Readonly<string[]> {\n return this._sentTransactionIds\n }\n\n /**\n * Clear all logged IDs.\n */\n clear() {\n this._sentTransactionIds = []\n }\n\n /**\n * The method that captures raw transactions and stores the transaction IDs.\n */\n logRawTransaction(signedTransactions: Uint8Array | Uint8Array[]) {\n if (Array.isArray(signedTransactions)) {\n signedTransactions.forEach((stxn) => this._pushTxn(stxn))\n } else {\n this._pushTxn(signedTransactions)\n }\n }\n\n /** Return a proxy that wraps the given Algodv2 with this transaction logger.\n *\n * @param algod The `Algodv2` to wrap\n * @returns The wrapped `Algodv2`, any transactions sent using this algod instance will be logged by this transaction logger\n */\n capture(algod: Algodv2): Algodv2 {\n return new Proxy<Algodv2>(algod, new TransactionLoggingAlgodv2ProxyHandler(this))\n }\n\n /** Wait until all logged transactions IDs appear in the given `Indexer`. */\n async waitForIndexer(indexer: Indexer) {\n if (this._sentTransactionIds.length === 0) return\n const lastTxId = this._sentTransactionIds[this._sentTransactionIds.length - 1]\n await runWhenIndexerCaughtUp(async () => {\n try {\n await indexer.lookupTransactionByID(lastTxId).do()\n } catch (e) {\n // If the txid lookup failed, then try to look up the last valid round\n // If that round exists, then we know indexer is caught up\n if (this._latestLastValidRound) {\n await indexer.lookupBlock(this._latestLastValidRound).do()\n Config.getLogger().debug(\n `waitForIndexer has waited until the last valid round ${this._latestLastValidRound} was indexed, but did not find transaction ${lastTxId} in the indexer.`,\n )\n } else {\n throw e\n }\n }\n })\n }\n}\n\nclass TransactionLoggingAlgodv2ProxyHandler implements ProxyHandler<Algodv2> {\n private transactionLogger: TransactionLogger\n\n constructor(transactionLogger: TransactionLogger) {\n this.transactionLogger = transactionLogger\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n get(target: Algodv2, property: string | symbol, receiver: any) {\n if (property === 'sendRawTransaction') {\n return (stxOrStxs: Uint8Array | Uint8Array[]) => {\n this.transactionLogger.logRawTransaction(stxOrStxs)\n return target[property].call(receiver, stxOrStxs)\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (target as any)[property]\n }\n}\n"],"names":["indexer","runWhenIndexerCaughtUp","Config"],"mappings":";;;;;;AAIA,IAAO,uBAAuB,GAAG,OAAO,CAAC,uBAAuB;AAGhE;;;AAGG;MACU,iBAAiB,CAAA;AAA9B,IAAA,WAAA,GAAA;QACU,IAAmB,CAAA,mBAAA,GAAa,EAAE;;AAGlC,IAAA,QAAQ,CAAC,IAAgB,EAAA;AAC/B,QAAA,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC;AAC7C,QAAA,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,qBAAqB,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;YACrE,IAAI,CAAC,qBAAqB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;;AAE5D,QAAA,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;;AAGnD;;AAEG;AACH,IAAA,IAAI,kBAAkB,GAAA;QACpB,OAAO,IAAI,CAAC,mBAAmB;;AAGjC;;AAEG;IACH,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,mBAAmB,GAAG,EAAE;;AAG/B;;AAEG;AACH,IAAA,iBAAiB,CAAC,kBAA6C,EAAA;AAC7D,QAAA,IAAI,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE;AACrC,YAAA,kBAAkB,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;;aACpD;AACL,YAAA,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;;;AAIrC;;;;AAIG;AACH,IAAA,OAAO,CAAC,KAAc,EAAA;QACpB,OAAO,IAAI,KAAK,CAAU,KAAK,EAAE,IAAI,qCAAqC,CAAC,IAAI,CAAC,CAAC;;;IAInF,MAAM,cAAc,CAACA,SAAgB,EAAA;AACnC,QAAA,IAAI,IAAI,CAAC,mBAAmB,CAAC,MAAM,KAAK,CAAC;YAAE;AAC3C,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9E,QAAA,MAAMC,8BAAsB,CAAC,YAAW;AACtC,YAAA,IAAI;gBACF,MAAMD,SAAO,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE;;YAClD,OAAO,CAAC,EAAE;;;AAGV,gBAAA,IAAI,IAAI,CAAC,qBAAqB,EAAE;oBAC9B,MAAMA,SAAO,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,EAAE,EAAE;AAC1D,oBAAAE,aAAM,CAAC,SAAS,EAAE,CAAC,KAAK,CACtB,CAAA,qDAAA,EAAwD,IAAI,CAAC,qBAAqB,CAAA,2CAAA,EAA8C,QAAQ,CAAA,gBAAA,CAAkB,CAC3J;;qBACI;AACL,oBAAA,MAAM,CAAC;;;AAGb,SAAC,CAAC;;AAEL;AAED,MAAM,qCAAqC,CAAA;AAGzC,IAAA,WAAA,CAAY,iBAAoC,EAAA;AAC9C,QAAA,IAAI,CAAC,iBAAiB,GAAG,iBAAiB;;;AAI5C,IAAA,GAAG,CAAC,MAAe,EAAE,QAAyB,EAAE,QAAa,EAAA;AAC3D,QAAA,IAAI,QAAQ,KAAK,oBAAoB,EAAE;YACrC,OAAO,CAAC,SAAoC,KAAI;AAC9C,gBAAA,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,SAAS,CAAC;gBACnD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC;AACnD,aAAC;;;AAGH,QAAA,OAAQ,MAAc,CAAC,QAAQ,CAAC;;AAEnC;;;;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import algosdk from 'algosdk';
|
|
2
|
+
import { Config } from '../config.mjs';
|
|
2
3
|
import { runWhenIndexerCaughtUp } from './indexer.mjs';
|
|
3
4
|
|
|
4
5
|
var decodeSignedTransaction = algosdk.decodeSignedTransaction;
|
|
@@ -10,6 +11,13 @@ class TransactionLogger {
|
|
|
10
11
|
constructor() {
|
|
11
12
|
this._sentTransactionIds = [];
|
|
12
13
|
}
|
|
14
|
+
_pushTxn(stxn) {
|
|
15
|
+
const decoded = decodeSignedTransaction(stxn);
|
|
16
|
+
if (decoded.txn.lastValid > (this._latestLastValidRound ?? BigInt(0))) {
|
|
17
|
+
this._latestLastValidRound = BigInt(decoded.txn.lastValid);
|
|
18
|
+
}
|
|
19
|
+
this._sentTransactionIds.push(decoded.txn.txID());
|
|
20
|
+
}
|
|
13
21
|
/**
|
|
14
22
|
* The list of transaction IDs that has been logged thus far.
|
|
15
23
|
*/
|
|
@@ -27,14 +35,10 @@ class TransactionLogger {
|
|
|
27
35
|
*/
|
|
28
36
|
logRawTransaction(signedTransactions) {
|
|
29
37
|
if (Array.isArray(signedTransactions)) {
|
|
30
|
-
|
|
31
|
-
const decoded = decodeSignedTransaction(stxn);
|
|
32
|
-
this._sentTransactionIds.push(decoded.txn.txID());
|
|
33
|
-
}
|
|
38
|
+
signedTransactions.forEach((stxn) => this._pushTxn(stxn));
|
|
34
39
|
}
|
|
35
40
|
else {
|
|
36
|
-
|
|
37
|
-
this._sentTransactionIds.push(decoded.txn.txID());
|
|
41
|
+
this._pushTxn(signedTransactions);
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
44
|
/** Return a proxy that wraps the given Algodv2 with this transaction logger.
|
|
@@ -50,7 +54,22 @@ class TransactionLogger {
|
|
|
50
54
|
if (this._sentTransactionIds.length === 0)
|
|
51
55
|
return;
|
|
52
56
|
const lastTxId = this._sentTransactionIds[this._sentTransactionIds.length - 1];
|
|
53
|
-
await runWhenIndexerCaughtUp(() =>
|
|
57
|
+
await runWhenIndexerCaughtUp(async () => {
|
|
58
|
+
try {
|
|
59
|
+
await indexer.lookupTransactionByID(lastTxId).do();
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
// If the txid lookup failed, then try to look up the last valid round
|
|
63
|
+
// If that round exists, then we know indexer is caught up
|
|
64
|
+
if (this._latestLastValidRound) {
|
|
65
|
+
await indexer.lookupBlock(this._latestLastValidRound).do();
|
|
66
|
+
Config.getLogger().debug(`waitForIndexer has waited until the last valid round ${this._latestLastValidRound} was indexed, but did not find transaction ${lastTxId} in the indexer.`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
54
73
|
}
|
|
55
74
|
}
|
|
56
75
|
class TransactionLoggingAlgodv2ProxyHandler {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-logger.mjs","sources":["../../src/testing/transaction-logger.ts"],"sourcesContent":["import algosdk from 'algosdk'\nimport { runWhenIndexerCaughtUp } from './indexer'\nimport Algodv2 = algosdk.Algodv2\nimport decodeSignedTransaction = algosdk.decodeSignedTransaction\nimport Indexer = algosdk.Indexer\n\n/**\n * Allows you to keep track of Algorand transaction IDs by wrapping an `Algodv2` in a proxy.\n * Useful for automated tests.\n */\nexport class TransactionLogger {\n private _sentTransactionIds: string[] = []\n\n /**\n * The list of transaction IDs that has been logged thus far.\n */\n get sentTransactionIds(): Readonly<string[]> {\n return this._sentTransactionIds\n }\n\n /**\n * Clear all logged IDs.\n */\n clear() {\n this._sentTransactionIds = []\n }\n\n /**\n * The method that captures raw transactions and stores the transaction IDs.\n */\n logRawTransaction(signedTransactions: Uint8Array | Uint8Array[]) {\n if (Array.isArray(signedTransactions)) {\n
|
|
1
|
+
{"version":3,"file":"transaction-logger.mjs","sources":["../../src/testing/transaction-logger.ts"],"sourcesContent":["import algosdk from 'algosdk'\nimport { Config } from '../config'\nimport { runWhenIndexerCaughtUp } from './indexer'\nimport Algodv2 = algosdk.Algodv2\nimport decodeSignedTransaction = algosdk.decodeSignedTransaction\nimport Indexer = algosdk.Indexer\n\n/**\n * Allows you to keep track of Algorand transaction IDs by wrapping an `Algodv2` in a proxy.\n * Useful for automated tests.\n */\nexport class TransactionLogger {\n private _sentTransactionIds: string[] = []\n private _latestLastValidRound?: bigint\n\n private _pushTxn(stxn: Uint8Array) {\n const decoded = decodeSignedTransaction(stxn)\n if (decoded.txn.lastValid > (this._latestLastValidRound ?? BigInt(0))) {\n this._latestLastValidRound = BigInt(decoded.txn.lastValid)\n }\n this._sentTransactionIds.push(decoded.txn.txID())\n }\n\n /**\n * The list of transaction IDs that has been logged thus far.\n */\n get sentTransactionIds(): Readonly<string[]> {\n return this._sentTransactionIds\n }\n\n /**\n * Clear all logged IDs.\n */\n clear() {\n this._sentTransactionIds = []\n }\n\n /**\n * The method that captures raw transactions and stores the transaction IDs.\n */\n logRawTransaction(signedTransactions: Uint8Array | Uint8Array[]) {\n if (Array.isArray(signedTransactions)) {\n signedTransactions.forEach((stxn) => this._pushTxn(stxn))\n } else {\n this._pushTxn(signedTransactions)\n }\n }\n\n /** Return a proxy that wraps the given Algodv2 with this transaction logger.\n *\n * @param algod The `Algodv2` to wrap\n * @returns The wrapped `Algodv2`, any transactions sent using this algod instance will be logged by this transaction logger\n */\n capture(algod: Algodv2): Algodv2 {\n return new Proxy<Algodv2>(algod, new TransactionLoggingAlgodv2ProxyHandler(this))\n }\n\n /** Wait until all logged transactions IDs appear in the given `Indexer`. */\n async waitForIndexer(indexer: Indexer) {\n if (this._sentTransactionIds.length === 0) return\n const lastTxId = this._sentTransactionIds[this._sentTransactionIds.length - 1]\n await runWhenIndexerCaughtUp(async () => {\n try {\n await indexer.lookupTransactionByID(lastTxId).do()\n } catch (e) {\n // If the txid lookup failed, then try to look up the last valid round\n // If that round exists, then we know indexer is caught up\n if (this._latestLastValidRound) {\n await indexer.lookupBlock(this._latestLastValidRound).do()\n Config.getLogger().debug(\n `waitForIndexer has waited until the last valid round ${this._latestLastValidRound} was indexed, but did not find transaction ${lastTxId} in the indexer.`,\n )\n } else {\n throw e\n }\n }\n })\n }\n}\n\nclass TransactionLoggingAlgodv2ProxyHandler implements ProxyHandler<Algodv2> {\n private transactionLogger: TransactionLogger\n\n constructor(transactionLogger: TransactionLogger) {\n this.transactionLogger = transactionLogger\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n get(target: Algodv2, property: string | symbol, receiver: any) {\n if (property === 'sendRawTransaction') {\n return (stxOrStxs: Uint8Array | Uint8Array[]) => {\n this.transactionLogger.logRawTransaction(stxOrStxs)\n return target[property].call(receiver, stxOrStxs)\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (target as any)[property]\n }\n}\n"],"names":[],"mappings":";;;;AAIA,IAAO,uBAAuB,GAAG,OAAO,CAAC,uBAAuB;AAGhE;;;AAGG;MACU,iBAAiB,CAAA;AAA9B,IAAA,WAAA,GAAA;QACU,IAAmB,CAAA,mBAAA,GAAa,EAAE;;AAGlC,IAAA,QAAQ,CAAC,IAAgB,EAAA;AAC/B,QAAA,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC;AAC7C,QAAA,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,qBAAqB,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;YACrE,IAAI,CAAC,qBAAqB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;;AAE5D,QAAA,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;;AAGnD;;AAEG;AACH,IAAA,IAAI,kBAAkB,GAAA;QACpB,OAAO,IAAI,CAAC,mBAAmB;;AAGjC;;AAEG;IACH,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,mBAAmB,GAAG,EAAE;;AAG/B;;AAEG;AACH,IAAA,iBAAiB,CAAC,kBAA6C,EAAA;AAC7D,QAAA,IAAI,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE;AACrC,YAAA,kBAAkB,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;;aACpD;AACL,YAAA,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;;;AAIrC;;;;AAIG;AACH,IAAA,OAAO,CAAC,KAAc,EAAA;QACpB,OAAO,IAAI,KAAK,CAAU,KAAK,EAAE,IAAI,qCAAqC,CAAC,IAAI,CAAC,CAAC;;;IAInF,MAAM,cAAc,CAAC,OAAgB,EAAA;AACnC,QAAA,IAAI,IAAI,CAAC,mBAAmB,CAAC,MAAM,KAAK,CAAC;YAAE;AAC3C,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9E,QAAA,MAAM,sBAAsB,CAAC,YAAW;AACtC,YAAA,IAAI;gBACF,MAAM,OAAO,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE;;YAClD,OAAO,CAAC,EAAE;;;AAGV,gBAAA,IAAI,IAAI,CAAC,qBAAqB,EAAE;oBAC9B,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,EAAE,EAAE;AAC1D,oBAAA,MAAM,CAAC,SAAS,EAAE,CAAC,KAAK,CACtB,CAAA,qDAAA,EAAwD,IAAI,CAAC,qBAAqB,CAAA,2CAAA,EAA8C,QAAQ,CAAA,gBAAA,CAAkB,CAC3J;;qBACI;AACL,oBAAA,MAAM,CAAC;;;AAGb,SAAC,CAAC;;AAEL;AAED,MAAM,qCAAqC,CAAA;AAGzC,IAAA,WAAA,CAAY,iBAAoC,EAAA;AAC9C,QAAA,IAAI,CAAC,iBAAiB,GAAG,iBAAiB;;;AAI5C,IAAA,GAAG,CAAC,MAAe,EAAE,QAAyB,EAAE,QAAa,EAAA;AAC3D,QAAA,IAAI,QAAQ,KAAK,oBAAoB,EAAE;YACrC,OAAO,CAAC,SAAoC,KAAI;AAC9C,gBAAA,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,SAAS,CAAC;gBACnD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC;AACnD,aAAC;;;AAGH,QAAA,OAAQ,MAAc,CAAC,QAAQ,CAAC;;AAEnC;;;;"}
|
package/types/app-client.d.ts
CHANGED
|
@@ -1826,7 +1826,7 @@ export declare class ApplicationClient {
|
|
|
1826
1826
|
deletable?: boolean | undefined;
|
|
1827
1827
|
updatable?: boolean | undefined;
|
|
1828
1828
|
return?: ABIReturn | undefined;
|
|
1829
|
-
/**
|
|
1829
|
+
/** The maximum opcode budget for a simulate call as per https://github.com/algorand/go-algorand/blob/807b29a91c371d225e12b9287c5d56e9b33c4e4c/ledger/simulation/trace.go#L104 */
|
|
1830
1830
|
operationPerformed: "update" | "create";
|
|
1831
1831
|
} | {
|
|
1832
1832
|
compiledApproval: import("./app").CompiledTeal;
|
package/types/app-client.js
CHANGED
|
@@ -20,6 +20,8 @@ var getApplicationAddress = algosdk.getApplicationAddress;
|
|
|
20
20
|
var Indexer = algosdk.Indexer;
|
|
21
21
|
var OnApplicationComplete = algosdk.OnApplicationComplete;
|
|
22
22
|
var SourceMap = algosdk.ProgramSourceMap;
|
|
23
|
+
/** The maximum opcode budget for a simulate call as per https://github.com/algorand/go-algorand/blob/807b29a91c371d225e12b9287c5d56e9b33c4e4c/ledger/simulation/trace.go#L104 */
|
|
24
|
+
const MAX_SIMULATE_OPCODE_BUDGET = 20000 * 16;
|
|
23
25
|
/**
|
|
24
26
|
* Determines deploy time control (UPDATABLE, DELETABLE) value by inspecting application specification
|
|
25
27
|
* @param approval TEAL Approval program, not the base64 version found on the appSpec
|
|
@@ -915,13 +917,11 @@ class AppClient {
|
|
|
915
917
|
...params,
|
|
916
918
|
};
|
|
917
919
|
// Read-only calls do not require fees to be paid, as they are only simulated on the network.
|
|
918
|
-
//
|
|
919
|
-
//
|
|
920
|
-
//
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
throw Error(`Please provide a maxFee for the transaction when coverAppCallInnerTransactionFees is enabled.`);
|
|
924
|
-
}
|
|
920
|
+
// With maximum opcode budget provided, ensure_budget (and similar op-up utilities) won't need to create inner transactions,
|
|
921
|
+
// so fee coverage for op-up inner transactions does not need to be accounted for in readonly calls.
|
|
922
|
+
// If max_fee is provided, use it as static_fee, as there may still be inner transactions sent which need to be covered by the outermost transaction,
|
|
923
|
+
// even though ARC-22 specifies that readonly methods should not send inner transactions.
|
|
924
|
+
if (params.coverAppCallInnerTransactionFees && params.maxFee) {
|
|
925
925
|
readonlyParams.staticFee = params.maxFee;
|
|
926
926
|
readonlyParams.extraFee = undefined;
|
|
927
927
|
}
|
|
@@ -933,6 +933,8 @@ class AppClient {
|
|
|
933
933
|
allowUnnamedResources: params.populateAppCallResources ?? true,
|
|
934
934
|
// Simulate calls for a readonly method shouldn't invoke signing
|
|
935
935
|
skipSignatures: true,
|
|
936
|
+
// Simulate calls for a readonly method can use the max opcode budget
|
|
937
|
+
extraOpcodeBudget: MAX_SIMULATE_OPCODE_BUDGET,
|
|
936
938
|
});
|
|
937
939
|
return this.processMethodCallReturn({
|
|
938
940
|
...result,
|
|
@@ -944,6 +946,8 @@ class AppClient {
|
|
|
944
946
|
}
|
|
945
947
|
catch (e) {
|
|
946
948
|
const error = e;
|
|
949
|
+
// For read-only calls with max opcode budget, fee issues should be rare
|
|
950
|
+
// but we can still provide helpful error message if they occur
|
|
947
951
|
if (params.coverAppCallInnerTransactionFees && error && error.message && error.message.match(/fee too small/)) {
|
|
948
952
|
throw Error(`Fees were too small. You may need to increase the transaction maxFee.`);
|
|
949
953
|
}
|