@algorandfoundation/algokit-utils 9.2.0 → 9.2.1-beta.2

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.
Files changed (340) hide show
  1. package/_virtual/_rolldown/runtime.js +33 -0
  2. package/_virtual/_rolldown/runtime.mjs +13 -0
  3. package/account/account.d.ts +25 -30
  4. package/account/account.js +151 -146
  5. package/account/account.js.map +1 -1
  6. package/account/account.mjs +149 -144
  7. package/account/account.mjs.map +1 -1
  8. package/account/get-account-config-from-environment.d.ts +7 -2
  9. package/account/get-account-config-from-environment.js +19 -21
  10. package/account/get-account-config-from-environment.js.map +1 -1
  11. package/account/get-account-config-from-environment.mjs +19 -19
  12. package/account/get-account-config-from-environment.mjs.map +1 -1
  13. package/account/get-account.d.ts +14 -12
  14. package/account/get-account.js +56 -59
  15. package/account/get-account.js.map +1 -1
  16. package/account/get-account.mjs +56 -57
  17. package/account/get-account.mjs.map +1 -1
  18. package/account/get-dispenser-account.d.ts +9 -5
  19. package/account/get-dispenser-account.js +20 -18
  20. package/account/get-dispenser-account.js.map +1 -1
  21. package/account/get-dispenser-account.mjs +20 -16
  22. package/account/get-dispenser-account.mjs.map +1 -1
  23. package/account/mnemonic-account.d.ts +7 -3
  24. package/account/mnemonic-account.js +17 -17
  25. package/account/mnemonic-account.js.map +1 -1
  26. package/account/mnemonic-account.mjs +15 -15
  27. package/account/mnemonic-account.mjs.map +1 -1
  28. package/amount.d.ts +40 -35
  29. package/amount.js +33 -34
  30. package/amount.js.map +1 -1
  31. package/amount.mjs +33 -32
  32. package/amount.mjs.map +1 -1
  33. package/app-client.d.ts +10 -6
  34. package/app-client.js +91 -86
  35. package/app-client.js.map +1 -1
  36. package/app-client.mjs +91 -84
  37. package/app-client.mjs.map +1 -1
  38. package/app-deploy.d.ts +26 -24
  39. package/app-deploy.js +235 -253
  40. package/app-deploy.js.map +1 -1
  41. package/app-deploy.mjs +233 -251
  42. package/app-deploy.mjs.map +1 -1
  43. package/app.d.ts +45 -46
  44. package/app.js +253 -271
  45. package/app.js.map +1 -1
  46. package/app.mjs +249 -267
  47. package/app.mjs.map +1 -1
  48. package/asset.d.ts +16 -12
  49. package/asset.js +116 -122
  50. package/asset.js.map +1 -1
  51. package/asset.mjs +116 -120
  52. package/asset.mjs.map +1 -1
  53. package/config.d.ts +7 -2
  54. package/config.js +5 -7
  55. package/config.js.map +1 -1
  56. package/config.mjs +5 -4
  57. package/config.mjs.map +1 -1
  58. package/debugging/debugging.d.ts +5 -1
  59. package/debugging/debugging.js +11 -11
  60. package/debugging/debugging.js.map +1 -1
  61. package/debugging/debugging.mjs +11 -9
  62. package/debugging/debugging.mjs.map +1 -1
  63. package/dispenser-client.d.ts +7 -2
  64. package/dispenser-client.js +23 -24
  65. package/dispenser-client.js.map +1 -1
  66. package/dispenser-client.mjs +23 -22
  67. package/dispenser-client.mjs.map +1 -1
  68. package/index.d.ts +27 -18
  69. package/index.js +140 -143
  70. package/index.mjs +27 -29
  71. package/indexer-lookup.d.ts +18 -11
  72. package/indexer-lookup.js +112 -120
  73. package/indexer-lookup.js.map +1 -1
  74. package/indexer-lookup.mjs +105 -118
  75. package/indexer-lookup.mjs.map +1 -1
  76. package/localnet/get-kmd-wallet-account.d.ts +9 -7
  77. package/localnet/get-kmd-wallet-account.js +28 -26
  78. package/localnet/get-kmd-wallet-account.js.map +1 -1
  79. package/localnet/get-kmd-wallet-account.mjs +28 -24
  80. package/localnet/get-kmd-wallet-account.mjs.map +1 -1
  81. package/localnet/get-localnet-dispenser-account.d.ts +7 -5
  82. package/localnet/get-localnet-dispenser-account.js +17 -15
  83. package/localnet/get-localnet-dispenser-account.js.map +1 -1
  84. package/localnet/get-localnet-dispenser-account.mjs +17 -13
  85. package/localnet/get-localnet-dispenser-account.mjs.map +1 -1
  86. package/localnet/get-or-create-kmd-wallet-account.d.ts +10 -8
  87. package/localnet/get-or-create-kmd-wallet-account.js +28 -26
  88. package/localnet/get-or-create-kmd-wallet-account.js.map +1 -1
  89. package/localnet/get-or-create-kmd-wallet-account.mjs +28 -24
  90. package/localnet/get-or-create-kmd-wallet-account.mjs.map +1 -1
  91. package/localnet/is-localnet.d.ts +7 -3
  92. package/localnet/is-localnet.js +9 -10
  93. package/localnet/is-localnet.js.map +1 -1
  94. package/localnet/is-localnet.mjs +9 -8
  95. package/localnet/is-localnet.mjs.map +1 -1
  96. package/network-client.d.ts +17 -15
  97. package/network-client.js +115 -116
  98. package/network-client.js.map +1 -1
  99. package/network-client.mjs +115 -114
  100. package/network-client.mjs.map +1 -1
  101. package/package.json +12 -3
  102. package/testing/account.d.ts +11 -9
  103. package/testing/account.js +31 -33
  104. package/testing/account.js.map +1 -1
  105. package/testing/account.mjs +29 -31
  106. package/testing/account.mjs.map +1 -1
  107. package/testing/fixtures/algokit-log-capture-fixture.d.ts +7 -2
  108. package/testing/fixtures/algokit-log-capture-fixture.js +36 -41
  109. package/testing/fixtures/algokit-log-capture-fixture.js.map +1 -1
  110. package/testing/fixtures/algokit-log-capture-fixture.mjs +36 -39
  111. package/testing/fixtures/algokit-log-capture-fixture.mjs.map +1 -1
  112. package/testing/fixtures/algorand-fixture.d.ts +9 -4
  113. package/testing/fixtures/algorand-fixture.js +67 -62
  114. package/testing/fixtures/algorand-fixture.js.map +1 -1
  115. package/testing/fixtures/algorand-fixture.mjs +66 -59
  116. package/testing/fixtures/algorand-fixture.mjs.map +1 -1
  117. package/testing/index.d.ts +7 -5
  118. package/testing/index.js +13 -18
  119. package/testing/index.mjs +7 -7
  120. package/testing/indexer.d.ts +5 -1
  121. package/testing/indexer.js +28 -37
  122. package/testing/indexer.js.map +1 -1
  123. package/testing/indexer.mjs +28 -35
  124. package/testing/indexer.mjs.map +1 -1
  125. package/testing/test-logger.d.ts +41 -36
  126. package/testing/test-logger.js +71 -76
  127. package/testing/test-logger.js.map +1 -1
  128. package/testing/test-logger.mjs +71 -74
  129. package/testing/test-logger.mjs.map +1 -1
  130. package/testing/transaction-logger.d.ts +30 -27
  131. package/testing/transaction-logger.js +77 -93
  132. package/testing/transaction-logger.js.map +1 -1
  133. package/testing/transaction-logger.mjs +74 -90
  134. package/testing/transaction-logger.mjs.map +1 -1
  135. package/transaction/legacy-bridge.js +100 -111
  136. package/transaction/legacy-bridge.js.map +1 -1
  137. package/transaction/legacy-bridge.mjs +97 -108
  138. package/transaction/legacy-bridge.mjs.map +1 -1
  139. package/transaction/perform-atomic-transaction-composer-simulate.d.ts +7 -5
  140. package/transaction/perform-atomic-transaction-composer-simulate.js +31 -36
  141. package/transaction/perform-atomic-transaction-composer-simulate.js.map +1 -1
  142. package/transaction/perform-atomic-transaction-composer-simulate.mjs +28 -33
  143. package/transaction/perform-atomic-transaction-composer-simulate.mjs.map +1 -1
  144. package/transaction/transaction.d.ts +34 -35
  145. package/transaction/transaction.js +716 -914
  146. package/transaction/transaction.js.map +1 -1
  147. package/transaction/transaction.mjs +713 -911
  148. package/transaction/transaction.mjs.map +1 -1
  149. package/transfer/transfer-algos.d.ts +9 -5
  150. package/transfer/transfer-algos.js +26 -27
  151. package/transfer/transfer-algos.js.map +1 -1
  152. package/transfer/transfer-algos.mjs +26 -25
  153. package/transfer/transfer-algos.mjs.map +1 -1
  154. package/transfer/transfer.d.ts +11 -8
  155. package/transfer/transfer.js +94 -100
  156. package/transfer/transfer.js.map +1 -1
  157. package/transfer/transfer.mjs +94 -98
  158. package/transfer/transfer.mjs.map +1 -1
  159. package/types/account-manager.d.ts +432 -429
  160. package/types/account-manager.js +591 -602
  161. package/types/account-manager.js.map +1 -1
  162. package/types/account-manager.mjs +587 -599
  163. package/types/account-manager.mjs.map +1 -1
  164. package/types/account.d.ts +192 -202
  165. package/types/account.js +91 -88
  166. package/types/account.js.map +1 -1
  167. package/types/account.mjs +88 -86
  168. package/types/account.mjs.map +1 -1
  169. package/types/algo-http-client-with-retry.d.ts +15 -10
  170. package/types/algo-http-client-with-retry.js +70 -92
  171. package/types/algo-http-client-with-retry.js.map +1 -1
  172. package/types/algo-http-client-with-retry.mjs +69 -90
  173. package/types/algo-http-client-with-retry.mjs.map +1 -1
  174. package/types/algorand-client-transaction-creator.d.ts +778 -771
  175. package/types/algorand-client-transaction-creator.js +733 -732
  176. package/types/algorand-client-transaction-creator.js.map +1 -1
  177. package/types/algorand-client-transaction-creator.mjs +732 -730
  178. package/types/algorand-client-transaction-creator.mjs.map +1 -1
  179. package/types/algorand-client-transaction-sender.d.ts +1090 -1360
  180. package/types/algorand-client-transaction-sender.js +930 -961
  181. package/types/algorand-client-transaction-sender.js.map +1 -1
  182. package/types/algorand-client-transaction-sender.mjs +927 -959
  183. package/types/algorand-client-transaction-sender.mjs.map +1 -1
  184. package/types/algorand-client.d.ts +239 -236
  185. package/types/algorand-client.js +322 -320
  186. package/types/algorand-client.js.map +1 -1
  187. package/types/algorand-client.mjs +321 -318
  188. package/types/algorand-client.mjs.map +1 -1
  189. package/types/amount.d.ts +47 -43
  190. package/types/amount.js +66 -70
  191. package/types/amount.js.map +1 -1
  192. package/types/amount.mjs +63 -68
  193. package/types/amount.mjs.map +1 -1
  194. package/types/app-arc56.d.ts +235 -272
  195. package/types/app-arc56.js +124 -170
  196. package/types/app-arc56.js.map +1 -1
  197. package/types/app-arc56.mjs +121 -168
  198. package/types/app-arc56.mjs.map +1 -1
  199. package/types/app-client.d.ts +1128 -2009
  200. package/types/app-client.js +1633 -1791
  201. package/types/app-client.js.map +1 -1
  202. package/types/app-client.mjs +1624 -1783
  203. package/types/app-client.mjs.map +1 -1
  204. package/types/app-deployer.d.ts +139 -141
  205. package/types/app-deployer.js +344 -384
  206. package/types/app-deployer.js.map +1 -1
  207. package/types/app-deployer.mjs +341 -382
  208. package/types/app-deployer.mjs.map +1 -1
  209. package/types/app-factory.d.ts +762 -932
  210. package/types/app-factory.js +496 -488
  211. package/types/app-factory.js.map +1 -1
  212. package/types/app-factory.mjs +491 -484
  213. package/types/app-factory.mjs.map +1 -1
  214. package/types/app-manager.d.ts +304 -310
  215. package/types/app-manager.js +422 -475
  216. package/types/app-manager.js.map +1 -1
  217. package/types/app-manager.mjs +419 -473
  218. package/types/app-manager.mjs.map +1 -1
  219. package/types/app-spec.d.ts +118 -117
  220. package/types/app-spec.js +125 -135
  221. package/types/app-spec.js.map +1 -1
  222. package/types/app-spec.mjs +121 -132
  223. package/types/app-spec.mjs.map +1 -1
  224. package/types/app.d.ts +229 -241
  225. package/types/app.js +36 -28
  226. package/types/app.js.map +1 -1
  227. package/types/app.mjs +33 -26
  228. package/types/app.mjs.map +1 -1
  229. package/types/asset-manager.d.ts +204 -199
  230. package/types/asset-manager.js +165 -174
  231. package/types/asset-manager.js.map +1 -1
  232. package/types/asset-manager.mjs +164 -172
  233. package/types/asset-manager.mjs.map +1 -1
  234. package/types/asset.d.ts +95 -91
  235. package/types/asset.js +0 -3
  236. package/types/asset.mjs +0 -2
  237. package/types/async-event-emitter.d.ts +18 -13
  238. package/types/async-event-emitter.js +37 -49
  239. package/types/async-event-emitter.js.map +1 -1
  240. package/types/async-event-emitter.mjs +36 -47
  241. package/types/async-event-emitter.mjs.map +1 -1
  242. package/types/client-manager.d.ts +453 -451
  243. package/types/client-manager.js +602 -598
  244. package/types/client-manager.js.map +1 -1
  245. package/types/client-manager.mjs +597 -594
  246. package/types/client-manager.mjs.map +1 -1
  247. package/types/composer.d.ts +1211 -1258
  248. package/types/composer.js +1436 -1498
  249. package/types/composer.js.map +1 -1
  250. package/types/composer.mjs +1430 -1493
  251. package/types/composer.mjs.map +1 -1
  252. package/types/config.d.ts +53 -48
  253. package/types/config.js +78 -77
  254. package/types/config.js.map +1 -1
  255. package/types/config.mjs +77 -75
  256. package/types/config.mjs.map +1 -1
  257. package/types/debugging.d.ts +25 -23
  258. package/types/debugging.js +9 -11
  259. package/types/debugging.js.map +1 -1
  260. package/types/debugging.mjs +8 -9
  261. package/types/debugging.mjs.map +1 -1
  262. package/types/dispenser-client.d.ts +57 -52
  263. package/types/dispenser-client.js +120 -141
  264. package/types/dispenser-client.js.map +1 -1
  265. package/types/dispenser-client.mjs +119 -139
  266. package/types/dispenser-client.mjs.map +1 -1
  267. package/types/expand.d.ts +5 -3
  268. package/types/expand.js +0 -3
  269. package/types/expand.mjs +0 -2
  270. package/types/indexer.d.ts +104 -100
  271. package/types/indexer.js +36 -31
  272. package/types/indexer.js.map +1 -1
  273. package/types/indexer.mjs +32 -30
  274. package/types/indexer.mjs.map +1 -1
  275. package/types/instance-of.d.ts +5 -3
  276. package/types/instance-of.js +0 -3
  277. package/types/instance-of.mjs +0 -2
  278. package/types/kmd-account-manager.d.ts +75 -70
  279. package/types/kmd-account-manager.js +150 -184
  280. package/types/kmd-account-manager.js.map +1 -1
  281. package/types/kmd-account-manager.mjs +147 -182
  282. package/types/kmd-account-manager.mjs.map +1 -1
  283. package/types/lifecycle-events.d.ts +13 -8
  284. package/types/lifecycle-events.js +10 -7
  285. package/types/lifecycle-events.js.map +1 -1
  286. package/types/lifecycle-events.mjs +9 -7
  287. package/types/lifecycle-events.mjs.map +1 -1
  288. package/types/logging.d.ts +15 -11
  289. package/types/logging.js +30 -31
  290. package/types/logging.js.map +1 -1
  291. package/types/logging.mjs +29 -29
  292. package/types/logging.mjs.map +1 -1
  293. package/types/logic-error.d.ts +33 -29
  294. package/types/logic-error.js +50 -49
  295. package/types/logic-error.js.map +1 -1
  296. package/types/logic-error.mjs +49 -47
  297. package/types/logic-error.mjs.map +1 -1
  298. package/types/network-client.d.ts +32 -27
  299. package/types/network-client.js +10 -9
  300. package/types/network-client.js.map +1 -1
  301. package/types/network-client.mjs +9 -7
  302. package/types/network-client.mjs.map +1 -1
  303. package/types/testing.d.ts +131 -132
  304. package/types/testing.js +0 -3
  305. package/types/testing.mjs +0 -2
  306. package/types/transaction.d.ts +110 -110
  307. package/types/transaction.js +0 -3
  308. package/types/transaction.mjs +0 -2
  309. package/types/transfer.d.ts +70 -66
  310. package/types/transfer.js +0 -3
  311. package/types/transfer.mjs +0 -2
  312. package/util.js +73 -118
  313. package/util.js.map +1 -1
  314. package/util.mjs +73 -116
  315. package/util.mjs.map +1 -1
  316. package/account/index.d.ts +0 -5
  317. package/debugging/index.d.ts +0 -1
  318. package/index.js.map +0 -1
  319. package/index.mjs.map +0 -1
  320. package/localnet/index.d.ts +0 -4
  321. package/testing/_asset.d.ts +0 -3
  322. package/testing/fixtures/index.d.ts +0 -2
  323. package/testing/index.js.map +0 -1
  324. package/testing/index.mjs.map +0 -1
  325. package/transaction/index.d.ts +0 -2
  326. package/transaction/legacy-bridge.d.ts +0 -35
  327. package/transfer/index.d.ts +0 -2
  328. package/types/asset.js.map +0 -1
  329. package/types/asset.mjs.map +0 -1
  330. package/types/expand.js.map +0 -1
  331. package/types/expand.mjs.map +0 -1
  332. package/types/instance-of.js.map +0 -1
  333. package/types/instance-of.mjs.map +0 -1
  334. package/types/testing.js.map +0 -1
  335. package/types/testing.mjs.map +0 -1
  336. package/types/transaction.js.map +0 -1
  337. package/types/transaction.mjs.map +0 -1
  338. package/types/transfer.js.map +0 -1
  339. package/types/transfer.mjs.map +0 -1
  340. package/util.d.ts +0 -48
@@ -1,1804 +1,1646 @@
1
- 'use strict';
2
-
3
- var algosdk = require('algosdk');
4
- var buffer = require('buffer');
5
- var app = require('../app.js');
6
- var appDeploy = require('../app-deploy.js');
7
- var config = require('../config.js');
8
- var legacyBridge = require('../transaction/legacy-bridge.js');
9
- var transaction = require('../transaction/transaction.js');
10
- var util = require('../util.js');
11
- var types_app = require('./app.js');
12
- var types_appArc56 = require('./app-arc56.js');
13
- var types_appSpec = require('./app-spec.js');
14
- var types_lifecycleEvents = require('./lifecycle-events.js');
15
- var types_logicError = require('./logic-error.js');
16
-
17
- var ABIMethod = algosdk.ABIMethod;
18
- var AtomicTransactionComposer = algosdk.AtomicTransactionComposer;
19
- var getApplicationAddress = algosdk.getApplicationAddress;
20
- var Indexer = algosdk.Indexer;
21
- var OnApplicationComplete = algosdk.OnApplicationComplete;
22
- var SourceMap = algosdk.ProgramSourceMap;
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("../_virtual/_rolldown/runtime.js");
3
+ const require_config = require("../config.js");
4
+ require("./lifecycle-events.js");
5
+ const require_app = require("./app.js");
6
+ const require_util = require("../util.js");
7
+ const require_transaction = require("../transaction/transaction.js");
8
+ const require_legacy_bridge = require("../transaction/legacy-bridge.js");
9
+ const require_app$1 = require("../app.js");
10
+ const require_app_deploy = require("../app-deploy.js");
11
+ const require_app_arc56 = require("./app-arc56.js");
12
+ const require_app_spec = require("./app-spec.js");
13
+ const require_logic_error = require("./logic-error.js");
14
+ let algosdk = require("algosdk");
15
+ algosdk = require_runtime.__toESM(algosdk);
16
+ let buffer = require("buffer");
17
+ //#region src/types/app-client.ts
18
+ var ABIMethod = algosdk.default.ABIMethod;
19
+ var AtomicTransactionComposer = algosdk.default.AtomicTransactionComposer;
20
+ var getApplicationAddress = algosdk.default.getApplicationAddress;
21
+ var Indexer = algosdk.default.Indexer;
22
+ var OnApplicationComplete = algosdk.default.OnApplicationComplete;
23
+ var SourceMap = algosdk.default.ProgramSourceMap;
23
24
  /** 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;
25
+ const MAX_SIMULATE_OPCODE_BUDGET = 2e4 * 16;
25
26
  /**
26
- * Determines deploy time control (UPDATABLE, DELETABLE) value by inspecting application specification
27
- * @param approval TEAL Approval program, not the base64 version found on the appSpec
28
- * @param appSpec Application Specification
29
- * @param templateVariableName Template variable
30
- * @param callConfigKey Call config type
31
- * @returns true if applicable call config is found, false if not found or undefined if variable not present
32
- */
27
+ * Determines deploy time control (UPDATABLE, DELETABLE) value by inspecting application specification
28
+ * @param approval TEAL Approval program, not the base64 version found on the appSpec
29
+ * @param appSpec Application Specification
30
+ * @param templateVariableName Template variable
31
+ * @param callConfigKey Call config type
32
+ * @returns true if applicable call config is found, false if not found or undefined if variable not present
33
+ */
33
34
  function getDeployTimeControl(approval, appSpec, templateVariableName, callConfigKey) {
34
- // variable not present, so unknown control value
35
- if (!approval.includes(templateVariableName))
36
- return undefined;
37
- // a bare call for specified CallConfig is present and configured
38
- const bareCallConfig = appSpec.bare_call_config[callConfigKey];
39
- if (!!bareCallConfig && bareCallConfig !== 'NEVER')
40
- return true;
41
- // an ABI call for specified CallConfig is present and configured
42
- return Object.values(appSpec.hints).some((h) => {
43
- const abiCallConfig = h.call_config[callConfigKey];
44
- return !!abiCallConfig && abiCallConfig !== 'NEVER';
45
- });
35
+ if (!approval.includes(templateVariableName)) return void 0;
36
+ const bareCallConfig = appSpec.bare_call_config[callConfigKey];
37
+ if (!!bareCallConfig && bareCallConfig !== "NEVER") return true;
38
+ return Object.values(appSpec.hints).some((h) => {
39
+ const abiCallConfig = h.call_config[callConfigKey];
40
+ return !!abiCallConfig && abiCallConfig !== "NEVER";
41
+ });
46
42
  }
47
43
  const BYTE_CBLOCK = 38;
48
44
  const INT_CBLOCK = 32;
49
45
  /**
50
- * Get the offset of the last constant block at the beginning of the program
51
- * This value is used to calculate the program counter for an ARC56 program that has a pcOffsetMethod of "cblocks"
52
- *
53
- * @param program The program to parse
54
- * @returns The PC value of the opcode after the last constant block
55
- */
46
+ * Get the offset of the last constant block at the beginning of the program
47
+ * This value is used to calculate the program counter for an ARC56 program that has a pcOffsetMethod of "cblocks"
48
+ *
49
+ * @param program The program to parse
50
+ * @returns The PC value of the opcode after the last constant block
51
+ */
56
52
  function getConstantBlockOffset(program) {
57
- const bytes = [...program];
58
- const programSize = bytes.length;
59
- bytes.shift(); // remove version
60
- /** The PC of the opcode after the bytecblock */
61
- let bytecblockOffset;
62
- /** The PC of the opcode after the intcblock */
63
- let intcblockOffset;
64
- while (bytes.length > 0) {
65
- /** The current byte from the beginning of the byte array */
66
- const byte = bytes.shift();
67
- // If the byte is a constant block...
68
- if (byte === BYTE_CBLOCK || byte === INT_CBLOCK) {
69
- const isBytecblock = byte === BYTE_CBLOCK;
70
- /** The byte following the opcode is the number of values in the constant block */
71
- const valuesRemaining = bytes.shift();
72
- // Iterate over all the values in the constant block
73
- for (let i = 0; i < valuesRemaining; i++) {
74
- if (isBytecblock) {
75
- /** The byte following the opcode is the length of the next element */
76
- const length = bytes.shift();
77
- bytes.splice(0, length);
78
- }
79
- else {
80
- // intcblock is a uvarint, so we need to keep reading until we find the end (MSB is not set)
81
- while ((bytes.shift() & 0x80) !== 0) {
82
- // Do nothing...
83
- }
84
- }
85
- }
86
- if (isBytecblock)
87
- bytecblockOffset = programSize - bytes.length - 1;
88
- else
89
- intcblockOffset = programSize - bytes.length - 1;
90
- if (bytes[0] !== BYTE_CBLOCK && bytes[0] !== INT_CBLOCK) {
91
- // if the next opcode isn't a constant block, we're done
92
- break;
93
- }
94
- }
95
- }
96
- return Math.max(bytecblockOffset ?? 0, intcblockOffset ?? 0);
53
+ const bytes = [...program];
54
+ const programSize = bytes.length;
55
+ bytes.shift();
56
+ /** The PC of the opcode after the bytecblock */
57
+ let bytecblockOffset;
58
+ /** The PC of the opcode after the intcblock */
59
+ let intcblockOffset;
60
+ while (bytes.length > 0) {
61
+ /** The current byte from the beginning of the byte array */
62
+ const byte = bytes.shift();
63
+ if (byte === BYTE_CBLOCK || byte === INT_CBLOCK) {
64
+ const isBytecblock = byte === BYTE_CBLOCK;
65
+ /** The byte following the opcode is the number of values in the constant block */
66
+ const valuesRemaining = bytes.shift();
67
+ for (let i = 0; i < valuesRemaining; i++) if (isBytecblock) {
68
+ /** The byte following the opcode is the length of the next element */
69
+ const length = bytes.shift();
70
+ bytes.splice(0, length);
71
+ } else while ((bytes.shift() & 128) !== 0);
72
+ if (isBytecblock) bytecblockOffset = programSize - bytes.length - 1;
73
+ else intcblockOffset = programSize - bytes.length - 1;
74
+ if (bytes[0] !== BYTE_CBLOCK && bytes[0] !== INT_CBLOCK) break;
75
+ }
76
+ }
77
+ return Math.max(bytecblockOffset ?? 0, intcblockOffset ?? 0);
97
78
  }
98
79
  /** ARC-56/ARC-32 application client that allows you to manage calls and
99
- * state for a specific deployed instance of an app (with a known app ID). */
100
- class AppClient {
101
- /**
102
- * Create a new app client.
103
- * @param params The parameters to create the app client
104
- * @returns The `AppClient` instance
105
- * @example
106
- * ```typescript
107
- * const appClient = new AppClient({
108
- * appId: 12345678n,
109
- * appSpec: appSpec,
110
- * algorand: AlgorandClient.mainNet(),
111
- * })
112
- */
113
- constructor(params) {
114
- /** Make the given call and catch any errors, augmenting with debugging information before re-throwing. */
115
- this.handleCallErrors = async (e) => {
116
- // We can't use the app ID in an error to identify new apps, so instead we check the programs
117
- // to identify if this is the correct app
118
- if (this.appId === 0n) {
119
- if (e.sentTransactions === undefined)
120
- return e;
121
- const txns = e.sentTransactions;
122
- const txn = txns.find((t) => e.message.includes(t.txID()));
123
- const programsDefinedAndEqual = (a, b) => {
124
- if (a === undefined || b === undefined)
125
- return false;
126
- if (a.length !== b.length)
127
- return false;
128
- for (let i = 0; i < a.length; i++) {
129
- if (a[i] !== b[i])
130
- return false;
131
- }
132
- return true;
133
- };
134
- if (!programsDefinedAndEqual(txn?.applicationCall?.clearProgram, this._lastCompiled.clear) ||
135
- !programsDefinedAndEqual(txn?.applicationCall?.approvalProgram, this._lastCompiled?.approval)) {
136
- return e;
137
- }
138
- }
139
- else {
140
- // Only handle errors for this app.
141
- const appIdString = `app=${this._appId.toString()}`;
142
- if (!e.message.includes(appIdString))
143
- return e;
144
- }
145
- const logicError = await this.exposeLogicError(e);
146
- if (logicError instanceof types_logicError.LogicError) {
147
- let currentLine = logicError.teal_line - logicError.lines - 1;
148
- const stackWithLines = logicError.stack
149
- ?.split('\n')
150
- .map((line) => `${(currentLine += 1)}: ${line}`)
151
- .join('\n');
152
- config.Config.logger.error(`${logicError.message}\n\n${stackWithLines}`);
153
- }
154
- return logicError;
155
- };
156
- this._appId = params.appId;
157
- this._appAddress = algosdk.getApplicationAddress(this._appId);
158
- this._appSpec = AppClient.normaliseAppSpec(params.appSpec);
159
- this._appName = params.appName ?? this._appSpec.name;
160
- this._algorand = params.algorand;
161
- this._algorand.registerErrorTransformer(this.handleCallErrors);
162
- this._defaultSender = typeof params.defaultSender === 'string' ? algosdk.Address.fromString(params.defaultSender) : params.defaultSender;
163
- this._defaultSigner = params.defaultSigner;
164
- this._lastCompiled = {};
165
- this._approvalSourceMap = params.approvalSourceMap;
166
- this._clearSourceMap = params.clearSourceMap;
167
- this._localStateMethods = (address) => this.getStateMethods(() => this.getLocalState(address), () => this._appSpec.state.keys.local, () => this._appSpec.state.maps.local);
168
- this._globalStateMethods = this.getStateMethods(() => this.getGlobalState(), () => this._appSpec.state.keys.global, () => this._appSpec.state.maps.global);
169
- this._boxStateMethods = this.getBoxMethods();
170
- this._paramsMethods = {
171
- ...this.getMethodCallParamsMethods(),
172
- /** Get parameters to define bare (raw) transactions to the current app */
173
- bare: this.getBareParamsMethods(),
174
- };
175
- this._createTransactionsMethods = {
176
- ...this.getMethodCallCreateTransactionMethods(),
177
- /** Get transactions for bare (raw) calls to the current app */
178
- bare: this.getBareCreateTransactionMethods(),
179
- };
180
- this._sendMethods = {
181
- ...this.getMethodCallSendMethods(),
182
- /** Send bare (raw) transactions to the current app */
183
- bare: this.getBareSendMethods(),
184
- };
185
- }
186
- /**
187
- * Clone this app client with different params
188
- *
189
- * @param params The params to use for the the cloned app client. Omit a param to keep the original value. Set a param to override the original value. Setting to undefined will clear the original value.
190
- * @returns A new app client with the altered params
191
- * @example
192
- * ```typescript
193
- * const appClient2 = appClient.clone({ defaultSender: 'NEW_SENDER_ADDRESS' })
194
- * ```
195
- */
196
- clone(params) {
197
- return new AppClient({
198
- appId: this._appId,
199
- appSpec: this._appSpec,
200
- algorand: this._algorand,
201
- appName: this._appName,
202
- defaultSender: this._defaultSender,
203
- defaultSigner: this._defaultSigner,
204
- approvalSourceMap: this._approvalSourceMap,
205
- clearSourceMap: this._clearSourceMap,
206
- ...params,
207
- });
208
- }
209
- /**
210
- * Returns a new `AppClient` client, resolving the app by creator address and name
211
- * using AlgoKit app deployment semantics (i.e. looking for the app creation transaction note).
212
- * @param params The parameters to create the app client
213
- * @returns The `AppClient` instance
214
- * @example
215
- * ```typescript
216
- * const appClient = await AppClient.fromCreatorAndName({
217
- * creatorAddress: 'CREATOR_ADDRESS',
218
- * name: 'APP_NAME',
219
- * appSpec: appSpec,
220
- * algorand: AlgorandClient.mainNet(),
221
- * })
222
- */
223
- static async fromCreatorAndName(params) {
224
- const appSpec = AppClient.normaliseAppSpec(params.appSpec);
225
- const appLookup = params.appLookupCache ?? (await params.algorand.appDeployer.getCreatorAppsByName(params.creatorAddress, params.ignoreCache));
226
- const appMetadata = appLookup.apps[params.appName ?? appSpec.name];
227
- if (!appMetadata) {
228
- throw new Error(`App not found for creator ${params.creatorAddress} and name ${params.appName ?? appSpec.name}`);
229
- }
230
- return new AppClient({
231
- ...params,
232
- algorand: params.algorand,
233
- appId: appMetadata.appId,
234
- });
235
- }
236
- /**
237
- * Returns an `AppClient` instance for the current network based on
238
- * pre-determined network-specific app IDs specified in the ARC-56 app spec.
239
- *
240
- * If no IDs are in the app spec or the network isn't recognised, an error is thrown.
241
- * @param params The parameters to create the app client
242
- * @returns The `AppClient` instance
243
- * @example
244
- * ```typescript
245
- * const appClient = await AppClient.fromNetwork({
246
- * appSpec: appSpec,
247
- * algorand: AlgorandClient.mainNet(),
248
- * })
249
- */
250
- static async fromNetwork(params) {
251
- const network = await params.algorand.client.network();
252
- const appSpec = AppClient.normaliseAppSpec(params.appSpec);
253
- const networkNames = [network.genesisHash];
254
- if (network.isLocalNet)
255
- networkNames.push('localnet');
256
- if (network.isTestNet)
257
- networkNames.push('testnet');
258
- if (network.isMainNet)
259
- networkNames.push('mainnet');
260
- const availableAppSpecNetworks = Object.keys(appSpec.networks ?? {});
261
- const networkIndex = availableAppSpecNetworks.findIndex((n) => networkNames.includes(n));
262
- if (networkIndex === -1) {
263
- throw new Error(`No app ID found for network ${util.asJson(networkNames)} in the app spec`);
264
- }
265
- const appId = BigInt(appSpec.networks[networkIndex].appID);
266
- return new AppClient({ ...params, appId, appSpec });
267
- }
268
- /**
269
- * Takes a string or parsed JSON object that could be ARC-32 or ARC-56 format and
270
- * normalises it into a parsed ARC-56 contract object.
271
- * @param spec The spec to normalise
272
- * @returns The normalised ARC-56 contract object
273
- * @example
274
- * ```typescript
275
- * const arc56AppSpec = AppClient.normaliseAppSpec(appSpec)
276
- * ```
277
- */
278
- static normaliseAppSpec(spec) {
279
- const parsedSpec = typeof spec === 'string' ? JSON.parse(spec) : spec;
280
- const appSpec = 'hints' in parsedSpec ? types_appSpec.arc32ToArc56(parsedSpec) : parsedSpec;
281
- return appSpec;
282
- }
283
- /** The ID of the app instance this client is linked to. */
284
- get appId() {
285
- return this._appId;
286
- }
287
- /** The app address of the app instance this client is linked to. */
288
- get appAddress() {
289
- return this._appAddress;
290
- }
291
- /** The name of the app (from the ARC-32 / ARC-56 app spec or override). */
292
- get appName() {
293
- return this._appName;
294
- }
295
- /** The ARC-56 app spec being used */
296
- get appSpec() {
297
- return this._appSpec;
298
- }
299
- /** A reference to the underlying `AlgorandClient` this app client is using. */
300
- get algorand() {
301
- return this._algorand;
302
- }
303
- /** Get parameters to create transactions for the current app.
304
- *
305
- * A good mental model for this is that these parameters represent a deferred transaction creation.
306
- * @example Create a transaction in the future using Algorand Client
307
- * ```typescript
308
- * const myMethodCall = appClient.params.call({method: 'my_method', args: [123, 'hello']})
309
- * // ...
310
- * await algorand.send.AppMethodCall(myMethodCall)
311
- * ```
312
- * @example Define a nested transaction as an ABI argument
313
- * ```typescript
314
- * const myMethodCall = appClient.params.call({method: 'my_method', args: [123, 'hello']})
315
- * await appClient.send.call({method: 'my_method2', args: [myMethodCall]})
316
- * ```
317
- */
318
- get params() {
319
- return this._paramsMethods;
320
- }
321
- /** Create transactions for the current app */
322
- get createTransaction() {
323
- return this._createTransactionsMethods;
324
- }
325
- /** Send transactions to the current app */
326
- get send() {
327
- return this._sendMethods;
328
- }
329
- /** Get state (local, global, box) from the current app */
330
- get state() {
331
- return {
332
- /**
333
- * Methods to access local state for the current app
334
- * @param address The address of the account to get the local state for
335
- */
336
- local: this._localStateMethods,
337
- /**
338
- * Methods to access global state for the current app
339
- */
340
- global: this._globalStateMethods,
341
- /**
342
- * Methods to access box storage for the current app
343
- */
344
- box: this._boxStateMethods,
345
- };
346
- }
347
- /**
348
- * Funds Algo into the app account for this app.
349
- *
350
- * An alias for `appClient.send.fundAppAccount(params)`.
351
- * @param params The parameters for the funding transaction
352
- * @returns The result of the funding
353
- * @example
354
- * ```typescript
355
- * await appClient.fundAppAccount({ amount: algo(1) })
356
- * ```
357
- */
358
- async fundAppAccount(params) {
359
- return this.send.fundAppAccount(params);
360
- }
361
- /**
362
- * Returns raw global state for the current app.
363
- * @returns The global state
364
- * @example
365
- * ```typescript
366
- * const globalState = await appClient.getGlobalState()
367
- * ```
368
- */
369
- async getGlobalState() {
370
- return await this._algorand.app.getGlobalState(this.appId);
371
- }
372
- /**
373
- * Returns raw local state for the given account address.
374
- * @param address The address of the account to get the local state for
375
- * @returns The local state
376
- * @example
377
- * ```typescript
378
- * const localState = await appClient.getLocalState('ACCOUNT_ADDRESS')
379
- * ```
380
- */
381
- async getLocalState(address) {
382
- return await this._algorand.app.getLocalState(this.appId, address);
383
- }
384
- /**
385
- * Returns the names of all current boxes for the current app.
386
- * @returns The names of the boxes
387
- * @example
388
- * ```typescript
389
- * const boxNames = await appClient.getBoxNames()
390
- * ```
391
- */
392
- async getBoxNames() {
393
- return await this._algorand.app.getBoxNames(this.appId);
394
- }
395
- /**
396
- * Returns the value of the given box for the current app.
397
- * @param name The identifier of the box to return
398
- * @returns The current box value as a byte array
399
- * @example
400
- * ```typescript
401
- * const boxValue = await appClient.getBoxValue('boxName')
402
- * ```
403
- */
404
- async getBoxValue(name) {
405
- return await this._algorand.app.getBoxValue(this.appId, name);
406
- }
407
- /**
408
- * Returns the value of the given box for the current app.
409
- * @param name The identifier of the box to return
410
- * @param type
411
- * @returns The current box value as a byte array
412
- * @example
413
- * ```typescript
414
- * const boxValue = await appClient.getBoxValueFromABIType('boxName', new ABIUintType(32))
415
- * ```
416
- */
417
- async getBoxValueFromABIType(name, type) {
418
- return await this._algorand.app.getBoxValueFromABIType({
419
- appId: this.appId,
420
- boxName: name,
421
- type,
422
- });
423
- }
424
- /**
425
- * Returns the values of all current boxes for the current app.
426
- * Note: This will issue multiple HTTP requests (one per box) and it's not an atomic operation so values may be out of sync.
427
- * @param filter Optional filter to filter which boxes' values are returned
428
- * @returns The (name, value) pair of the boxes with values as raw byte arrays
429
- * @example
430
- * ```typescript
431
- * const boxValues = await appClient.getBoxValues()
432
- * ```
433
- */
434
- async getBoxValues(filter) {
435
- const names = (await this.getBoxNames()).filter(filter ?? ((_) => true));
436
- const values = await this._algorand.app.getBoxValues(this.appId, names.map((name) => name.nameRaw));
437
- return names.map((name, i) => ({ name, value: values[i] }));
438
- }
439
- /**
440
- * Returns the values of all current boxes for the current app decoded using an ABI Type.
441
- * Note: This will issue multiple HTTP requests (one per box) and it's not an atomic operation so values may be out of sync.
442
- * @param type The ABI type to decode the values with
443
- * @param filter Optional filter to filter which boxes' values are returned
444
- * @returns The (name, value) pair of the boxes with values as the ABI Value
445
- * @example
446
- * ```typescript
447
- * const boxValues = await appClient.getBoxValuesFromABIType(new ABIUintType(32))
448
- * ```
449
- */
450
- async getBoxValuesFromABIType(type, filter) {
451
- const names = (await this.getBoxNames()).filter(filter ?? ((_) => true));
452
- const values = await this._algorand.app.getBoxValuesFromABIType({
453
- appId: this.appId,
454
- boxNames: names.map((name) => name.nameRaw),
455
- type,
456
- });
457
- return names.map((name, i) => ({ name, value: values[i] }));
458
- }
459
- /**
460
- * Takes an error that may include a logic error from a call to the current app and re-exposes the
461
- * error to include source code information via the source map and ARC-56 spec.
462
- * @param e The error to parse
463
- * @param isClearStateProgram Whether or not the code was running the clear state program (defaults to approval program)
464
- * @returns The new error, or if there was no logic error or source map then the wrapped error with source details
465
- */
466
- async exposeLogicError(e, isClearStateProgram) {
467
- const pcOffsetMethod = this._appSpec.sourceInfo?.[isClearStateProgram ? 'clear' : 'approval']?.pcOffsetMethod;
468
- let program;
469
- if (pcOffsetMethod === 'cblocks') {
470
- // TODO: Cache this if we deploy the app and it's not updateable
471
- const appInfo = await this._algorand.app.getById(this.appId);
472
- program = isClearStateProgram ? appInfo.clearStateProgram : appInfo.approvalProgram;
473
- }
474
- return AppClient.exposeLogicError(e, this._appSpec, {
475
- isClearStateProgram,
476
- approvalSourceMap: this._approvalSourceMap,
477
- clearSourceMap: this._clearSourceMap,
478
- program,
479
- });
480
- }
481
- /**
482
- * Export the current source maps for the app.
483
- * @returns The source maps
484
- */
485
- exportSourceMaps() {
486
- if (!this._approvalSourceMap || !this._clearSourceMap) {
487
- throw new Error("Unable to export source maps; they haven't been loaded into this client - you need to call create, update, or deploy first");
488
- }
489
- return {
490
- approvalSourceMap: this._approvalSourceMap,
491
- clearSourceMap: this._clearSourceMap,
492
- };
493
- }
494
- /**
495
- * Import source maps for the app.
496
- * @param sourceMaps The source maps to import
497
- */
498
- importSourceMaps(sourceMaps) {
499
- this._approvalSourceMap = new SourceMap(sourceMaps.approvalSourceMap);
500
- this._clearSourceMap = new SourceMap(sourceMaps.clearSourceMap);
501
- }
502
- /**
503
- * Returns the ABI Method spec for the given method string for the app represented by this application client instance
504
- * @param methodNameOrSignature The method name or method signature to call if an ABI call is being emitted.
505
- * e.g. `my_method` or `my_method(unit64,string)bytes`
506
- * @returns A tuple with: [ARC-56 `Method`, algosdk `ABIMethod`]
507
- */
508
- getABIMethod(methodNameOrSignature) {
509
- return types_appArc56.getArc56Method(methodNameOrSignature, this._appSpec);
510
- }
511
- /**
512
- * Checks for decode errors on the SendAppTransactionResult and maps the return value to the specified type
513
- * on the ARC-56 method, replacing the `return` property with the decoded type.
514
- *
515
- * If the return type is an ARC-56 struct then the struct will be returned.
516
- *
517
- * @param result The SendAppTransactionResult to be mapped
518
- * @param method The method that was called
519
- * @returns The smart contract response with an updated return value
520
- */
521
- async processMethodCallReturn(result, method) {
522
- const resultValue = await result;
523
- return { ...resultValue, return: types_appArc56.getArc56ReturnValue(resultValue.return, method, this._appSpec.structs) };
524
- }
525
- /**
526
- * Compiles the approval and clear state programs (if TEAL templates provided),
527
- * performing any provided deploy-time parameter replacement and stores
528
- * the source maps.
529
- *
530
- * If no TEAL templates provided it will use any byte code provided in the app spec.
531
- *
532
- * Will store any generated source maps for later use in debugging.
533
- * @param compilation Any compilation parameters to use
534
- * @returns The compiled code and any compilation results (including source maps)
535
- */
536
- async compile(compilation) {
537
- const result = await AppClient.compile(this._appSpec, this._algorand.app, compilation);
538
- if (result.compiledApproval) {
539
- this._approvalSourceMap = result.compiledApproval.sourceMap;
540
- this._lastCompiled.approval = result.compiledApproval.compiledBase64ToBytes;
541
- }
542
- if (result.compiledClear) {
543
- this._clearSourceMap = result.compiledClear.sourceMap;
544
- this._lastCompiled.clear = result.compiledClear.compiledBase64ToBytes;
545
- }
546
- return result;
547
- }
548
- /**
549
- * Takes an error that may include a logic error from a call to the current app and re-exposes the
550
- * error to include source code information via the source map and ARC-56 spec.
551
- * @param e The error to parse
552
- * @param appSpec The app spec for the app
553
- * @param details Additional information to inform the error
554
- * @returns The new error, or if there was no logic error or source map then the wrapped error with source details
555
- */
556
- static exposeLogicError(e, appSpec, details) {
557
- const { isClearStateProgram, approvalSourceMap, clearSourceMap, program } = details;
558
- const sourceMap = isClearStateProgram ? clearSourceMap : approvalSourceMap;
559
- const errorDetails = types_logicError.LogicError.parseLogicError(e);
560
- // Return the error if we don't have a PC
561
- if (errorDetails === undefined || errorDetails?.pc === undefined)
562
- return e;
563
- /** The PC value to find in the ARC56 SourceInfo */
564
- let arc56Pc = errorDetails?.pc;
565
- const programSourceInfo = isClearStateProgram ? appSpec.sourceInfo?.clear : appSpec.sourceInfo?.approval;
566
- /** The offset to apply to the PC if using the cblocks pc offset method */
567
- let cblocksOffset = 0;
568
- // If the program uses cblocks offset, then we need to adjust the PC accordingly
569
- if (programSourceInfo?.pcOffsetMethod === 'cblocks') {
570
- if (program === undefined)
571
- throw new Error('Program bytes are required to calculate the ARC56 cblocks PC offset');
572
- cblocksOffset = getConstantBlockOffset(program);
573
- arc56Pc = errorDetails.pc - cblocksOffset;
574
- }
575
- // Find the source info for this PC and get the error message
576
- const sourceInfo = programSourceInfo?.sourceInfo.find((s) => s.pc.includes(arc56Pc));
577
- const errorMessage = sourceInfo?.errorMessage;
578
- // If we have the source we can display the TEAL in the error message
579
- if (appSpec.source) {
580
- let getLineForPc = (inputPc) => sourceMap?.getLocationForPc?.(inputPc)?.line;
581
- // If the SourceMap is not defined, we need to provide our own function for going from a PC to TEAL based on ARC56 SourceInfo[]
582
- if (sourceMap === undefined) {
583
- getLineForPc = (inputPc) => {
584
- const teal = programSourceInfo?.sourceInfo.find((s) => s.pc.includes(inputPc - cblocksOffset))?.teal;
585
- if (teal === undefined)
586
- return undefined;
587
- return teal - 1;
588
- };
589
- }
590
- e = new types_logicError.LogicError(errorDetails, buffer.Buffer.from(isClearStateProgram ? appSpec.source.clear : appSpec.source.approval, 'base64')
591
- .toString()
592
- .split('\n'), getLineForPc);
593
- }
594
- if (errorMessage) {
595
- const appId = util.asJson(e).match(/(?<=app=)\d+/)?.[0] || '';
596
- const txId = util.asJson(e).match(/(?<=transaction )\S+(?=:)/)?.[0];
597
- const error = new Error(`Runtime error when executing ${appSpec.name} (appId: ${appId}) in transaction ${txId}: ${errorMessage}`);
598
- error.cause = e;
599
- return error;
600
- }
601
- return e;
602
- }
603
- /**
604
- * Compiles the approval and clear state programs (if TEAL templates provided),
605
- * performing any provided deploy-time parameter replacement and returns
606
- * the compiled code and any compilation results (including source maps).
607
- *
608
- * If no TEAL templates provided it will use any byte code provided in the app spec.
609
- *
610
- * Will store any generated source maps for later use in debugging.
611
- * @param appSpec The app spec for the app
612
- * @param appManager The app manager to use for compilation
613
- * @param compilation Any compilation parameters to use
614
- * @returns The compiled code and any compilation results (including source maps)
615
- */
616
- static async compile(appSpec, appManager, compilation) {
617
- const { deployTimeParams, updatable, deletable } = compilation ?? {};
618
- if (!appSpec.source) {
619
- if (!appSpec.byteCode?.approval || !appSpec.byteCode?.clear) {
620
- throw new Error(`Attempt to compile app ${appSpec.name} without source or byteCode`);
621
- }
622
- return {
623
- approvalProgram: buffer.Buffer.from(appSpec.byteCode.approval, 'base64'),
624
- clearStateProgram: buffer.Buffer.from(appSpec.byteCode.clear, 'base64'),
625
- };
626
- }
627
- const approvalTemplate = buffer.Buffer.from(appSpec.source.approval, 'base64').toString('utf-8');
628
- const compiledApproval = await appManager.compileTealTemplate(approvalTemplate, deployTimeParams, {
629
- updatable,
630
- deletable,
631
- });
632
- const clearTemplate = buffer.Buffer.from(appSpec.source.clear, 'base64').toString('utf-8');
633
- const compiledClear = await appManager.compileTealTemplate(clearTemplate, deployTimeParams);
634
- if (config.Config.debug) {
635
- await config.Config.events.emitAsync(types_lifecycleEvents.EventType.AppCompiled, {
636
- sources: [
637
- { compiledTeal: compiledApproval, appName: appSpec.name, fileName: 'approval' },
638
- { compiledTeal: compiledClear, appName: appSpec.name, fileName: 'clear' },
639
- ],
640
- });
641
- }
642
- return {
643
- approvalProgram: compiledApproval.compiledBase64ToBytes,
644
- compiledApproval,
645
- clearStateProgram: compiledClear.compiledBase64ToBytes,
646
- compiledClear,
647
- };
648
- }
649
- /**
650
- * Returns ABI method arguments ready for a method call params object with default values populated
651
- * and structs replaced with tuples.
652
- *
653
- * It does this by replacing any `undefined` values with the equivalent default value from the given ARC-56 app spec.
654
- * @param methodNameOrSignature The method name or method signature to call if an ABI call is being emitted.
655
- * e.g. `my_method` or `my_method(unit64,string)bytes`
656
- * @param args The arguments to the method with `undefined` for any that should be populated with a default value
657
- */
658
- async getABIArgsWithDefaultValues(methodNameOrSignature, args, sender) {
659
- const m = types_appArc56.getArc56Method(methodNameOrSignature, this._appSpec);
660
- return await Promise.all(args?.map(async (a, i) => {
661
- const arg = m.args[i];
662
- if (!arg) {
663
- throw new Error(`Unexpected arg at position ${i}. ${m.name} only expects ${m.args.length} args`);
664
- }
665
- if (a !== undefined) {
666
- // If a struct then convert to tuple for the underlying call
667
- return arg.struct && typeof a === 'object' && !Array.isArray(a)
668
- ? types_appArc56.getABITupleFromABIStruct(a, this._appSpec.structs[arg.struct], this._appSpec.structs)
669
- : a;
670
- }
671
- const defaultValue = arg.defaultValue;
672
- if (defaultValue) {
673
- switch (defaultValue.source) {
674
- case 'literal':
675
- return types_appArc56.getABIDecodedValue(buffer.Buffer.from(defaultValue.data, 'base64'), m.method.args[i].defaultValue?.type ?? m.method.args[i].type, this._appSpec.structs);
676
- case 'method': {
677
- const method = this.getABIMethod(defaultValue.data);
678
- const result = await this.send.call({
679
- method: defaultValue.data,
680
- args: method.args.map(() => undefined),
681
- sender,
682
- });
683
- if (result.return === undefined) {
684
- throw new Error('Default value method call did not return a value');
685
- }
686
- if (typeof result.return === 'object' &&
687
- !(result.return instanceof Uint8Array) &&
688
- !Array.isArray(result.return) &&
689
- !(result.return instanceof algosdk.Address)) {
690
- return types_appArc56.getABITupleFromABIStruct(result.return, this._appSpec.structs[method.returns.struct], this._appSpec.structs);
691
- }
692
- return result.return;
693
- }
694
- case 'local':
695
- case 'global': {
696
- const state = defaultValue.source === 'global' ? await this.getGlobalState() : await this.getLocalState(sender);
697
- const value = Object.values(state).find((s) => s.keyBase64 === defaultValue.data);
698
- if (!value) {
699
- throw new Error(`Preparing default value for argument ${arg.name ?? `arg${i + 1}`} resulted in the failure: The key '${defaultValue.data}' could not be found in ${defaultValue.source} storage`);
700
- }
701
- return 'valueRaw' in value
702
- ? types_appArc56.getABIDecodedValue(value.valueRaw, m.method.args[i].defaultValue?.type ?? m.method.args[i].type, this._appSpec.structs)
703
- : value.value;
704
- }
705
- case 'box': {
706
- const value = await this.getBoxValue(buffer.Buffer.from(defaultValue.data, 'base64'));
707
- return types_appArc56.getABIDecodedValue(value, m.method.args[i].defaultValue?.type ?? m.method.args[i].type, this._appSpec.structs);
708
- }
709
- }
710
- }
711
- if (!algosdk.abiTypeIsTransaction(arg.type)) {
712
- throw new Error(`No value provided for required argument ${arg.name ?? `arg${i + 1}`} in call to method ${m.name}`);
713
- }
714
- }) ?? []);
715
- }
716
- getBareParamsMethods() {
717
- return {
718
- /** Return params for an update call, including deploy-time TEAL template replacements and compilation if provided */
719
- update: async (params) => {
720
- return this.getBareParams({
721
- ...params,
722
- ...(await this.compile(params)),
723
- }, OnApplicationComplete.UpdateApplicationOC);
724
- },
725
- /** Return params for an opt-in call */
726
- optIn: (params) => {
727
- return this.getBareParams(params, OnApplicationComplete.OptInOC);
728
- },
729
- /** Return params for a delete call */
730
- delete: (params) => {
731
- return this.getBareParams(params, OnApplicationComplete.DeleteApplicationOC);
732
- },
733
- /** Return params for a clear state call */
734
- clearState: (params) => {
735
- return this.getBareParams(params, OnApplicationComplete.ClearStateOC);
736
- },
737
- /** Return params for a close out call */
738
- closeOut: (params) => {
739
- return this.getBareParams(params, OnApplicationComplete.CloseOutOC);
740
- },
741
- /** Return params for a call (defaults to no-op) */
742
- call: (params) => {
743
- return this.getBareParams(params, params?.onComplete ?? OnApplicationComplete.NoOpOC);
744
- },
745
- };
746
- }
747
- getBareCreateTransactionMethods() {
748
- return {
749
- /** Returns a transaction for an update call, including deploy-time TEAL template replacements and compilation if provided */
750
- update: async (params) => {
751
- return this._algorand.createTransaction.appUpdate(await this.params.bare.update(params));
752
- },
753
- /** Returns a transaction for an opt-in call */
754
- optIn: (params) => {
755
- return this._algorand.createTransaction.appCall(this.params.bare.optIn(params));
756
- },
757
- /** Returns a transaction for a delete call */
758
- delete: (params) => {
759
- return this._algorand.createTransaction.appDelete(this.params.bare.delete(params));
760
- },
761
- /** Returns a transaction for a clear state call */
762
- clearState: (params) => {
763
- return this._algorand.createTransaction.appCall(this.params.bare.clearState(params));
764
- },
765
- /** Returns a transaction for a close out call */
766
- closeOut: (params) => {
767
- return this._algorand.createTransaction.appCall(this.params.bare.closeOut(params));
768
- },
769
- /** Returns a transaction for a call (defaults to no-op) */
770
- call: (params) => {
771
- return this._algorand.createTransaction.appCall(this.params.bare.call(params));
772
- },
773
- };
774
- }
775
- getBareSendMethods() {
776
- return {
777
- /** Signs and sends an update call, including deploy-time TEAL template replacements and compilation if provided */
778
- update: async (params) => {
779
- const compiled = await this.compile(params);
780
- return {
781
- ...(await this._algorand.send.appUpdate(await this.params.bare.update(params))),
782
- ...compiled,
783
- };
784
- },
785
- /** Signs and sends an opt-in call */
786
- optIn: (params) => {
787
- return this._algorand.send.appCall(this.params.bare.optIn(params));
788
- },
789
- /** Signs and sends a delete call */
790
- delete: (params) => {
791
- return this._algorand.send.appDelete(this.params.bare.delete(params));
792
- },
793
- /** Signs and sends a clear state call */
794
- clearState: (params) => {
795
- return this._algorand.send.appCall(this.params.bare.clearState(params));
796
- },
797
- /** Signs and sends a close out call */
798
- closeOut: (params) => {
799
- return this._algorand.send.appCall(this.params.bare.closeOut(params));
800
- },
801
- /** Signs and sends a call (defaults to no-op) */
802
- call: (params) => {
803
- return this._algorand.send.appCall(this.params.bare.call(params));
804
- },
805
- };
806
- }
807
- getMethodCallParamsMethods() {
808
- return {
809
- /**
810
- * Return params for a payment transaction to fund the app account
811
- * @param params The parameters for the fund app accont payment transaction
812
- * @returns The parameters which can be used to create a fund app account payment transaction
813
- */
814
- fundAppAccount: (params) => {
815
- return {
816
- ...params,
817
- sender: this.getSender(params.sender),
818
- signer: this.getSigner(params.sender, params.signer),
819
- receiver: this.appAddress,
820
- };
821
- },
822
- /**
823
- * Return params for an update ABI call, including deploy-time TEAL template replacements and compilation if provided
824
- * @param params The parameters for the update ABI method call
825
- * @returns The parameters which can be used to create an update ABI method call
826
- */
827
- update: async (params) => {
828
- return (await this.getABIParams({
829
- ...params,
830
- ...(await this.compile(params)),
831
- }, OnApplicationComplete.UpdateApplicationOC));
832
- },
833
- /**
834
- * Return params for an opt-in ABI call
835
- * @param params The parameters for the opt-in ABI method call
836
- * @returns The parameters which can be used to create an opt-in ABI method call
837
- */
838
- optIn: async (params) => {
839
- return (await this.getABIParams(params, OnApplicationComplete.OptInOC));
840
- },
841
- /**
842
- * Return params for an delete ABI call
843
- * @param params The parameters for the delete ABI method call
844
- * @returns The parameters which can be used to create a delete ABI method call
845
- */
846
- delete: async (params) => {
847
- return (await this.getABIParams(params, OnApplicationComplete.DeleteApplicationOC));
848
- },
849
- /** Return params for an close out ABI call
850
- * @param params The parameters for the close out ABI method call
851
- * @returns The parameters which can be used to create a close out ABI method call
852
- */
853
- closeOut: async (params) => {
854
- return (await this.getABIParams(params, OnApplicationComplete.CloseOutOC));
855
- },
856
- /** Return params for an ABI call
857
- * @param params The parameters for the ABI method call
858
- * @returns The parameters which can be used to create an ABI method call
859
- */
860
- call: async (params) => {
861
- return (await this.getABIParams(params, params.onComplete ?? OnApplicationComplete.NoOpOC));
862
- },
863
- };
864
- }
865
- getMethodCallSendMethods() {
866
- return {
867
- /** Sign and send transactions for a payment transaction to fund the app account
868
- * @param params The parameters for the fund app account payment transaction
869
- * @returns The result of send the fund app account payment transaction
870
- */
871
- fundAppAccount: (params) => {
872
- return this._algorand.send.payment(this.params.fundAppAccount(params));
873
- },
874
- /**
875
- * Sign and send transactions for an update ABI call, including deploy-time TEAL template replacements and compilation if provided
876
- * @param params The parameters for the update ABI method call
877
- * @returns The result of sending the update ABI method call
878
- */
879
- update: async (params) => {
880
- const compiled = await this.compile(params);
881
- return {
882
- ...(await this.processMethodCallReturn(this._algorand.send.appUpdateMethodCall(await this.params.update({ ...params })), types_appArc56.getArc56Method(params.method, this._appSpec))),
883
- ...compiled,
884
- };
885
- },
886
- /**
887
- * Sign and send transactions for an opt-in ABI call
888
- * @param params The parameters for the opt-in ABI method call
889
- * @returns The result of sending the opt-in ABI method call
890
- */
891
- optIn: async (params) => {
892
- return this.processMethodCallReturn(this._algorand.send.appCallMethodCall(await this.params.optIn(params)), types_appArc56.getArc56Method(params.method, this._appSpec));
893
- },
894
- /**
895
- * Sign and send transactions for a delete ABI call
896
- * @param params The parameters for the delete ABI method call
897
- * @returns The result of sending the delete ABI method call
898
- */
899
- delete: async (params) => {
900
- return this.processMethodCallReturn(this._algorand.send.appDeleteMethodCall(await this.params.delete(params)), types_appArc56.getArc56Method(params.method, this._appSpec));
901
- },
902
- /**
903
- * Sign and send transactions for a close out ABI call
904
- * @param params The parameters for the close out ABI method call
905
- * @returns The result of sending the close out ABI method call
906
- */
907
- closeOut: async (params) => {
908
- return this.processMethodCallReturn(this._algorand.send.appCallMethodCall(await this.params.closeOut(params)), types_appArc56.getArc56Method(params.method, this._appSpec));
909
- },
910
- /**
911
- * Sign and send transactions for a call (defaults to no-op)
912
- * @param params The parameters for the ABI method call
913
- * @returns The result of sending the ABI method call
914
- */
915
- call: async (params) => {
916
- // Read-only call - do it via simulate
917
- if ((params.onComplete === OnApplicationComplete.NoOpOC || !params.onComplete) &&
918
- types_appArc56.getArc56Method(params.method, this._appSpec).method.readonly) {
919
- const readonlyParams = {
920
- ...params,
921
- };
922
- // Read-only calls do not require fees to be paid, as they are only simulated on the network.
923
- // With maximum opcode budget provided, ensure_budget (and similar op-up utilities) won't need to create inner transactions,
924
- // so fee coverage for op-up inner transactions does not need to be accounted for in readonly calls.
925
- // 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,
926
- // even though ARC-22 specifies that readonly methods should not send inner transactions.
927
- if (params.coverAppCallInnerTransactionFees && params.maxFee) {
928
- readonlyParams.staticFee = params.maxFee;
929
- readonlyParams.extraFee = undefined;
930
- }
931
- try {
932
- const result = await this._algorand
933
- .newGroup()
934
- .addAppCallMethodCall(await this.params.call(readonlyParams))
935
- .simulate({
936
- allowUnnamedResources: params.populateAppCallResources ?? true,
937
- // Simulate calls for a readonly method shouldn't invoke signing
938
- skipSignatures: true,
939
- // Simulate calls for a readonly method can use the max opcode budget
940
- extraOpcodeBudget: MAX_SIMULATE_OPCODE_BUDGET,
941
- });
942
- return this.processMethodCallReturn({
943
- ...result,
944
- transaction: result.transactions.at(-1),
945
- confirmation: result.confirmations.at(-1),
946
- // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
947
- return: (result.returns?.length ?? 0 > 0) ? result.returns?.at(-1) : undefined,
948
- }, types_appArc56.getArc56Method(params.method, this._appSpec));
949
- }
950
- catch (e) {
951
- const error = e;
952
- // For read-only calls with max opcode budget, fee issues should be rare
953
- // but we can still provide helpful error message if they occur
954
- if (params.coverAppCallInnerTransactionFees && error && error.message && error.message.match(/fee too small/)) {
955
- throw Error(`Fees were too small. You may need to increase the transaction maxFee.`);
956
- }
957
- throw e;
958
- }
959
- }
960
- return this.processMethodCallReturn(this._algorand.send.appCallMethodCall(await this.params.call(params)), types_appArc56.getArc56Method(params.method, this._appSpec));
961
- },
962
- };
963
- }
964
- getMethodCallCreateTransactionMethods() {
965
- return {
966
- /** Return transaction for a payment transaction to fund the app account
967
- * @param params The parameters for the fund app account payment transaction
968
- * @returns A transaction which can be used to fund the app account
969
- */
970
- fundAppAccount: (params) => {
971
- return this._algorand.createTransaction.payment(this.params.fundAppAccount(params));
972
- },
973
- /**
974
- * Return transactions for an update ABI call, including deploy-time TEAL template replacements and compilation if provided
975
- * @param params The parameters for the update ABI method call
976
- * @returns The transactions which can be used to create an update ABI method call
977
- */
978
- update: async (params) => {
979
- return this._algorand.createTransaction.appUpdateMethodCall(await this.params.update(params));
980
- },
981
- /**
982
- * Return transactions for an opt-in ABI call
983
- * @param params The parameters for the opt-in ABI method call
984
- * @returns The transactions which can be used to create an opt-in ABI method call
985
- */
986
- optIn: async (params) => {
987
- return this._algorand.createTransaction.appCallMethodCall(await this.params.optIn(params));
988
- },
989
- /**
990
- * Return transactions for a delete ABI call
991
- * @param params The parameters for the delete ABI method call
992
- * @returns The transactions which can be used to create a delete ABI method call
993
- */
994
- delete: async (params) => {
995
- return this._algorand.createTransaction.appDeleteMethodCall(await this.params.delete(params));
996
- },
997
- /**
998
- * Return transactions for a close out ABI call
999
- * @param params The parameters for the close out ABI method call
1000
- * @returns The transactions which can be used to create a close out ABI method call
1001
- */
1002
- closeOut: async (params) => {
1003
- return this._algorand.createTransaction.appCallMethodCall(await this.params.closeOut(params));
1004
- },
1005
- /**
1006
- * Return transactions for an ABI call (defaults to no-op)
1007
- * @param params The parameters for the ABI method call
1008
- * @returns The transactions which can be used to create an ABI method call
1009
- */
1010
- call: async (params) => {
1011
- return this._algorand.createTransaction.appCallMethodCall(await this.params.call(params));
1012
- },
1013
- };
1014
- }
1015
- /** Returns the sender for a call, using the provided sender or using the `defaultSender`
1016
- * if none provided and throws an error if neither provided */
1017
- getSender(sender) {
1018
- if (!sender && !this._defaultSender) {
1019
- throw new Error(`No sender provided and no default sender present in app client for call to app ${this._appName}`);
1020
- }
1021
- return typeof sender === 'string' ? algosdk.Address.fromString(sender) : (sender ?? this._defaultSender);
1022
- }
1023
- /** Returns the signer for a call, using the provided signer or the `defaultSigner`
1024
- * if no signer was provided and the sender resolves to the default sender, the call will use default signer
1025
- * or `undefined` otherwise (so the signer is resolved from `AlgorandClient`) */
1026
- getSigner(sender, signer) {
1027
- return signer ?? (!sender || sender === this._defaultSender ? this._defaultSigner : undefined);
1028
- }
1029
- getBareParams(params, onComplete) {
1030
- return {
1031
- ...params,
1032
- appId: this._appId,
1033
- sender: this.getSender(params?.sender),
1034
- signer: this.getSigner(params?.sender, params?.signer),
1035
- onComplete,
1036
- };
1037
- }
1038
- async getABIParams(params, onComplete) {
1039
- const sender = this.getSender(params.sender);
1040
- const method = types_appArc56.getArc56Method(params.method, this._appSpec);
1041
- const args = await this.getABIArgsWithDefaultValues(params.method, params.args, sender);
1042
- return {
1043
- ...params,
1044
- appId: this._appId,
1045
- sender: sender,
1046
- signer: this.getSigner(params.sender, params.signer),
1047
- method,
1048
- onComplete,
1049
- args,
1050
- };
1051
- }
1052
- getBoxMethods() {
1053
- // eslint-disable-next-line @typescript-eslint/no-this-alias
1054
- const that = this;
1055
- const stateMethods = {
1056
- /**
1057
- * Returns all single-key state values in a record keyed by the key name and the value a decoded ABI value.
1058
- */
1059
- getAll: async () => {
1060
- return Object.fromEntries(await Promise.all(Object.keys(that._appSpec.state.keys.box).map(async (key) => [key, await stateMethods.getValue(key)])));
1061
- },
1062
- /**
1063
- * Returns a single state value for the current app with the value a decoded ABI value.
1064
- * @param name The name of the state value to retrieve the value for
1065
- * @returns
1066
- */
1067
- getValue: async (name) => {
1068
- const metadata = that._appSpec.state.keys.box[name];
1069
- const value = await that.getBoxValue(buffer.Buffer.from(metadata.key, 'base64'));
1070
- return types_appArc56.getABIDecodedValue(value, metadata.valueType, that._appSpec.structs);
1071
- },
1072
- /**
1073
- *
1074
- * @param mapName The name of the map to read from
1075
- * @param key The key within the map (without any map prefix) as either a Buffer with the bytes or a value
1076
- * that will be converted to bytes by encoding it using the specified ABI key type
1077
- * in the ARC-56 spec
1078
- */
1079
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1080
- getMapValue: async (mapName, key) => {
1081
- const metadata = that._appSpec.state.maps.box[mapName];
1082
- const prefix = buffer.Buffer.from(metadata.prefix ?? '', 'base64');
1083
- const encodedKey = buffer.Buffer.concat([prefix, types_appArc56.getABIEncodedValue(key, metadata.keyType, that._appSpec.structs)]);
1084
- const base64Key = buffer.Buffer.from(encodedKey).toString('base64');
1085
- const value = await that.getBoxValue(buffer.Buffer.from(base64Key, 'base64'));
1086
- return types_appArc56.getABIDecodedValue(value, metadata.valueType, that._appSpec.structs);
1087
- },
1088
- /**
1089
- *
1090
- * @param mapName The name of the map to read from
1091
- * @param key The key within the map as either a Buffer with the bytes or a value
1092
- * that will be converted to bytes by encoding it using the specified ABI key type
1093
- * in the ARC-56 spec
1094
- * @param appState
1095
- */
1096
- getMap: async (mapName) => {
1097
- const metadata = that._appSpec.state.maps.box[mapName];
1098
- const prefix = buffer.Buffer.from(metadata.prefix ?? '', 'base64');
1099
- const boxNames = await that.getBoxNames();
1100
- return new Map(await Promise.all(boxNames
1101
- .filter((b) => util.binaryStartsWith(b.nameRaw, prefix))
1102
- .map(async (b) => {
1103
- return [
1104
- types_appArc56.getABIDecodedValue(b.nameRaw.slice(prefix.length), metadata.keyType, that._appSpec.structs),
1105
- types_appArc56.getABIDecodedValue(await that.getBoxValue(b.nameRaw), metadata.valueType, that._appSpec.structs),
1106
- ];
1107
- })));
1108
- },
1109
- };
1110
- return stateMethods;
1111
- }
1112
- getStateMethods(stateGetter, keyGetter, mapGetter) {
1113
- // eslint-disable-next-line @typescript-eslint/no-this-alias
1114
- const that = this;
1115
- const stateMethods = {
1116
- /**
1117
- * Returns all single-key state values in a record keyed by the key name and the value a decoded ABI value.
1118
- */
1119
- getAll: async () => {
1120
- const appState = await stateGetter();
1121
- return Object.fromEntries(await Promise.all(Object.keys(keyGetter()).map(async (key) => [key, await stateMethods.getValue(key, appState)])));
1122
- },
1123
- /**
1124
- * Returns a single state value for the current app with the value a decoded ABI value.
1125
- * @param name The name of the state value to retrieve the value for
1126
- * @param appState Optional cached value of the current state
1127
- * @returns
1128
- */
1129
- getValue: async (name, appState) => {
1130
- const state = Object.values(appState ?? (await stateGetter()));
1131
- const metadata = keyGetter()[name];
1132
- if (metadata === undefined)
1133
- throw new Error(`Attempted to get state value ${name}, but it does not exist`);
1134
- const value = state.find((s) => s.keyBase64 === metadata.key);
1135
- if (value && 'valueRaw' in value) {
1136
- return types_appArc56.getABIDecodedValue(value.valueRaw, metadata.valueType, that._appSpec.structs);
1137
- }
1138
- return value?.value;
1139
- },
1140
- /**
1141
- * Returns a single value from the given map for the current app with the value a decoded ABI value.
1142
- * @param mapName The name of the map to read from
1143
- * @param key The key within the map (without any map prefix) as either a Buffer with the bytes or a value
1144
- * that will be converted to bytes by encoding it using the specified ABI key type
1145
- * in the ARC-56 spec
1146
- * @param appState Optional cached value of the current state
1147
- */
1148
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1149
- getMapValue: async (mapName, key, appState) => {
1150
- const state = Object.values(appState ?? (await stateGetter()));
1151
- const metadata = mapGetter()[mapName];
1152
- const prefix = buffer.Buffer.from(metadata.prefix ?? '', 'base64');
1153
- const encodedKey = buffer.Buffer.concat([prefix, types_appArc56.getABIEncodedValue(key, metadata.keyType, that._appSpec.structs)]);
1154
- const base64Key = buffer.Buffer.from(encodedKey).toString('base64');
1155
- const value = state.find((s) => s.keyBase64 === base64Key);
1156
- if (value && 'valueRaw' in value) {
1157
- return types_appArc56.getABIDecodedValue(value.valueRaw, metadata.valueType, that._appSpec.structs);
1158
- }
1159
- return value?.value;
1160
- },
1161
- /**
1162
- * Returns all map values for the given map.
1163
- * @param mapName The name of the map to read from
1164
- * @param appState Optional cached value of the current state
1165
- * @returns A map of all key-value pairs in the map as a `Record<string, ABIValue>`
1166
- */
1167
- getMap: async (mapName) => {
1168
- const state = Object.values(await stateGetter());
1169
- const metadata = mapGetter()[mapName];
1170
- const prefix = buffer.Buffer.from(metadata.prefix ?? '', 'base64');
1171
- return new Map(state
1172
- .filter((s) => util.binaryStartsWith(s.keyRaw, prefix))
1173
- .map((s) => {
1174
- const key = s.keyRaw.slice(prefix.length);
1175
- return [
1176
- types_appArc56.getABIDecodedValue(key, metadata.keyType, this._appSpec.structs),
1177
- types_appArc56.getABIDecodedValue('valueRaw' in s ? s.valueRaw : s.value, metadata.valueType, this._appSpec.structs),
1178
- ];
1179
- }));
1180
- },
1181
- };
1182
- return stateMethods;
1183
- }
1184
- }
80
+ * state for a specific deployed instance of an app (with a known app ID). */
81
+ var AppClient = class AppClient {
82
+ _appId;
83
+ _appAddress;
84
+ _appName;
85
+ _appSpec;
86
+ _algorand;
87
+ _defaultSender;
88
+ _defaultSigner;
89
+ _approvalSourceMap;
90
+ _clearSourceMap;
91
+ _localStateMethods;
92
+ _globalStateMethods;
93
+ _boxStateMethods;
94
+ _paramsMethods;
95
+ _createTransactionsMethods;
96
+ _sendMethods;
97
+ _lastCompiled;
98
+ /**
99
+ * Create a new app client.
100
+ * @param params The parameters to create the app client
101
+ * @returns The `AppClient` instance
102
+ * @example
103
+ * ```typescript
104
+ * const appClient = new AppClient({
105
+ * appId: 12345678n,
106
+ * appSpec: appSpec,
107
+ * algorand: AlgorandClient.mainNet(),
108
+ * })
109
+ */
110
+ constructor(params) {
111
+ this._appId = params.appId;
112
+ this._appAddress = algosdk.default.getApplicationAddress(this._appId);
113
+ this._appSpec = AppClient.normaliseAppSpec(params.appSpec);
114
+ this._appName = params.appName ?? this._appSpec.name;
115
+ this._algorand = params.algorand;
116
+ this._algorand.registerErrorTransformer(this.handleCallErrors);
117
+ this._defaultSender = typeof params.defaultSender === "string" ? algosdk.Address.fromString(params.defaultSender) : params.defaultSender;
118
+ this._defaultSigner = params.defaultSigner;
119
+ this._lastCompiled = {};
120
+ this._approvalSourceMap = params.approvalSourceMap;
121
+ this._clearSourceMap = params.clearSourceMap;
122
+ this._localStateMethods = (address) => this.getStateMethods(() => this.getLocalState(address), () => this._appSpec.state.keys.local, () => this._appSpec.state.maps.local);
123
+ this._globalStateMethods = this.getStateMethods(() => this.getGlobalState(), () => this._appSpec.state.keys.global, () => this._appSpec.state.maps.global);
124
+ this._boxStateMethods = this.getBoxMethods();
125
+ this._paramsMethods = {
126
+ ...this.getMethodCallParamsMethods(),
127
+ /** Get parameters to define bare (raw) transactions to the current app */
128
+ bare: this.getBareParamsMethods()
129
+ };
130
+ this._createTransactionsMethods = {
131
+ ...this.getMethodCallCreateTransactionMethods(),
132
+ /** Get transactions for bare (raw) calls to the current app */
133
+ bare: this.getBareCreateTransactionMethods()
134
+ };
135
+ this._sendMethods = {
136
+ ...this.getMethodCallSendMethods(),
137
+ /** Send bare (raw) transactions to the current app */
138
+ bare: this.getBareSendMethods()
139
+ };
140
+ }
141
+ /**
142
+ * Clone this app client with different params
143
+ *
144
+ * @param params The params to use for the the cloned app client. Omit a param to keep the original value. Set a param to override the original value. Setting to undefined will clear the original value.
145
+ * @returns A new app client with the altered params
146
+ * @example
147
+ * ```typescript
148
+ * const appClient2 = appClient.clone({ defaultSender: 'NEW_SENDER_ADDRESS' })
149
+ * ```
150
+ */
151
+ clone(params) {
152
+ return new AppClient({
153
+ appId: this._appId,
154
+ appSpec: this._appSpec,
155
+ algorand: this._algorand,
156
+ appName: this._appName,
157
+ defaultSender: this._defaultSender,
158
+ defaultSigner: this._defaultSigner,
159
+ approvalSourceMap: this._approvalSourceMap,
160
+ clearSourceMap: this._clearSourceMap,
161
+ ...params
162
+ });
163
+ }
164
+ /**
165
+ * Returns a new `AppClient` client, resolving the app by creator address and name
166
+ * using AlgoKit app deployment semantics (i.e. looking for the app creation transaction note).
167
+ * @param params The parameters to create the app client
168
+ * @returns The `AppClient` instance
169
+ * @example
170
+ * ```typescript
171
+ * const appClient = await AppClient.fromCreatorAndName({
172
+ * creatorAddress: 'CREATOR_ADDRESS',
173
+ * name: 'APP_NAME',
174
+ * appSpec: appSpec,
175
+ * algorand: AlgorandClient.mainNet(),
176
+ * })
177
+ */
178
+ static async fromCreatorAndName(params) {
179
+ const appSpec = AppClient.normaliseAppSpec(params.appSpec);
180
+ const appMetadata = (params.appLookupCache ?? await params.algorand.appDeployer.getCreatorAppsByName(params.creatorAddress, params.ignoreCache)).apps[params.appName ?? appSpec.name];
181
+ if (!appMetadata) throw new Error(`App not found for creator ${params.creatorAddress} and name ${params.appName ?? appSpec.name}`);
182
+ return new AppClient({
183
+ ...params,
184
+ algorand: params.algorand,
185
+ appId: appMetadata.appId
186
+ });
187
+ }
188
+ /**
189
+ * Returns an `AppClient` instance for the current network based on
190
+ * pre-determined network-specific app IDs specified in the ARC-56 app spec.
191
+ *
192
+ * If no IDs are in the app spec or the network isn't recognised, an error is thrown.
193
+ * @param params The parameters to create the app client
194
+ * @returns The `AppClient` instance
195
+ * @example
196
+ * ```typescript
197
+ * const appClient = await AppClient.fromNetwork({
198
+ * appSpec: appSpec,
199
+ * algorand: AlgorandClient.mainNet(),
200
+ * })
201
+ */
202
+ static async fromNetwork(params) {
203
+ const network = await params.algorand.client.network();
204
+ const appSpec = AppClient.normaliseAppSpec(params.appSpec);
205
+ const networkNames = [network.genesisHash];
206
+ if (network.isLocalNet) networkNames.push("localnet");
207
+ if (network.isTestNet) networkNames.push("testnet");
208
+ if (network.isMainNet) networkNames.push("mainnet");
209
+ const networkIndex = Object.keys(appSpec.networks ?? {}).findIndex((n) => networkNames.includes(n));
210
+ if (networkIndex === -1) throw new Error(`No app ID found for network ${require_util.asJson(networkNames)} in the app spec`);
211
+ const appId = BigInt(appSpec.networks[networkIndex].appID);
212
+ return new AppClient({
213
+ ...params,
214
+ appId,
215
+ appSpec
216
+ });
217
+ }
218
+ /**
219
+ * Takes a string or parsed JSON object that could be ARC-32 or ARC-56 format and
220
+ * normalises it into a parsed ARC-56 contract object.
221
+ * @param spec The spec to normalise
222
+ * @returns The normalised ARC-56 contract object
223
+ * @example
224
+ * ```typescript
225
+ * const arc56AppSpec = AppClient.normaliseAppSpec(appSpec)
226
+ * ```
227
+ */
228
+ static normaliseAppSpec(spec) {
229
+ const parsedSpec = typeof spec === "string" ? JSON.parse(spec) : spec;
230
+ return "hints" in parsedSpec ? require_app_spec.arc32ToArc56(parsedSpec) : parsedSpec;
231
+ }
232
+ /** The ID of the app instance this client is linked to. */
233
+ get appId() {
234
+ return this._appId;
235
+ }
236
+ /** The app address of the app instance this client is linked to. */
237
+ get appAddress() {
238
+ return this._appAddress;
239
+ }
240
+ /** The name of the app (from the ARC-32 / ARC-56 app spec or override). */
241
+ get appName() {
242
+ return this._appName;
243
+ }
244
+ /** The ARC-56 app spec being used */
245
+ get appSpec() {
246
+ return this._appSpec;
247
+ }
248
+ /** A reference to the underlying `AlgorandClient` this app client is using. */
249
+ get algorand() {
250
+ return this._algorand;
251
+ }
252
+ /** Get parameters to create transactions for the current app.
253
+ *
254
+ * A good mental model for this is that these parameters represent a deferred transaction creation.
255
+ * @example Create a transaction in the future using Algorand Client
256
+ * ```typescript
257
+ * const myMethodCall = appClient.params.call({method: 'my_method', args: [123, 'hello']})
258
+ * // ...
259
+ * await algorand.send.AppMethodCall(myMethodCall)
260
+ * ```
261
+ * @example Define a nested transaction as an ABI argument
262
+ * ```typescript
263
+ * const myMethodCall = appClient.params.call({method: 'my_method', args: [123, 'hello']})
264
+ * await appClient.send.call({method: 'my_method2', args: [myMethodCall]})
265
+ * ```
266
+ */
267
+ get params() {
268
+ return this._paramsMethods;
269
+ }
270
+ /** Create transactions for the current app */
271
+ get createTransaction() {
272
+ return this._createTransactionsMethods;
273
+ }
274
+ /** Send transactions to the current app */
275
+ get send() {
276
+ return this._sendMethods;
277
+ }
278
+ /** Get state (local, global, box) from the current app */
279
+ get state() {
280
+ return {
281
+ /**
282
+ * Methods to access local state for the current app
283
+ * @param address The address of the account to get the local state for
284
+ */
285
+ local: this._localStateMethods,
286
+ /**
287
+ * Methods to access global state for the current app
288
+ */
289
+ global: this._globalStateMethods,
290
+ /**
291
+ * Methods to access box storage for the current app
292
+ */
293
+ box: this._boxStateMethods
294
+ };
295
+ }
296
+ /**
297
+ * Funds Algo into the app account for this app.
298
+ *
299
+ * An alias for `appClient.send.fundAppAccount(params)`.
300
+ * @param params The parameters for the funding transaction
301
+ * @returns The result of the funding
302
+ * @example
303
+ * ```typescript
304
+ * await appClient.fundAppAccount({ amount: algo(1) })
305
+ * ```
306
+ */
307
+ async fundAppAccount(params) {
308
+ return this.send.fundAppAccount(params);
309
+ }
310
+ /**
311
+ * Returns raw global state for the current app.
312
+ * @returns The global state
313
+ * @example
314
+ * ```typescript
315
+ * const globalState = await appClient.getGlobalState()
316
+ * ```
317
+ */
318
+ async getGlobalState() {
319
+ return await this._algorand.app.getGlobalState(this.appId);
320
+ }
321
+ /**
322
+ * Returns raw local state for the given account address.
323
+ * @param address The address of the account to get the local state for
324
+ * @returns The local state
325
+ * @example
326
+ * ```typescript
327
+ * const localState = await appClient.getLocalState('ACCOUNT_ADDRESS')
328
+ * ```
329
+ */
330
+ async getLocalState(address) {
331
+ return await this._algorand.app.getLocalState(this.appId, address);
332
+ }
333
+ /**
334
+ * Returns the names of all current boxes for the current app.
335
+ * @returns The names of the boxes
336
+ * @example
337
+ * ```typescript
338
+ * const boxNames = await appClient.getBoxNames()
339
+ * ```
340
+ */
341
+ async getBoxNames() {
342
+ return await this._algorand.app.getBoxNames(this.appId);
343
+ }
344
+ /**
345
+ * Returns the value of the given box for the current app.
346
+ * @param name The identifier of the box to return
347
+ * @returns The current box value as a byte array
348
+ * @example
349
+ * ```typescript
350
+ * const boxValue = await appClient.getBoxValue('boxName')
351
+ * ```
352
+ */
353
+ async getBoxValue(name) {
354
+ return await this._algorand.app.getBoxValue(this.appId, name);
355
+ }
356
+ /**
357
+ * Returns the value of the given box for the current app.
358
+ * @param name The identifier of the box to return
359
+ * @param type
360
+ * @returns The current box value as a byte array
361
+ * @example
362
+ * ```typescript
363
+ * const boxValue = await appClient.getBoxValueFromABIType('boxName', new ABIUintType(32))
364
+ * ```
365
+ */
366
+ async getBoxValueFromABIType(name, type) {
367
+ return await this._algorand.app.getBoxValueFromABIType({
368
+ appId: this.appId,
369
+ boxName: name,
370
+ type
371
+ });
372
+ }
373
+ /**
374
+ * Returns the values of all current boxes for the current app.
375
+ * Note: This will issue multiple HTTP requests (one per box) and it's not an atomic operation so values may be out of sync.
376
+ * @param filter Optional filter to filter which boxes' values are returned
377
+ * @returns The (name, value) pair of the boxes with values as raw byte arrays
378
+ * @example
379
+ * ```typescript
380
+ * const boxValues = await appClient.getBoxValues()
381
+ * ```
382
+ */
383
+ async getBoxValues(filter) {
384
+ const names = (await this.getBoxNames()).filter(filter ?? ((_) => true));
385
+ const values = await this._algorand.app.getBoxValues(this.appId, names.map((name) => name.nameRaw));
386
+ return names.map((name, i) => ({
387
+ name,
388
+ value: values[i]
389
+ }));
390
+ }
391
+ /**
392
+ * Returns the values of all current boxes for the current app decoded using an ABI Type.
393
+ * Note: This will issue multiple HTTP requests (one per box) and it's not an atomic operation so values may be out of sync.
394
+ * @param type The ABI type to decode the values with
395
+ * @param filter Optional filter to filter which boxes' values are returned
396
+ * @returns The (name, value) pair of the boxes with values as the ABI Value
397
+ * @example
398
+ * ```typescript
399
+ * const boxValues = await appClient.getBoxValuesFromABIType(new ABIUintType(32))
400
+ * ```
401
+ */
402
+ async getBoxValuesFromABIType(type, filter) {
403
+ const names = (await this.getBoxNames()).filter(filter ?? ((_) => true));
404
+ const values = await this._algorand.app.getBoxValuesFromABIType({
405
+ appId: this.appId,
406
+ boxNames: names.map((name) => name.nameRaw),
407
+ type
408
+ });
409
+ return names.map((name, i) => ({
410
+ name,
411
+ value: values[i]
412
+ }));
413
+ }
414
+ /**
415
+ * Takes an error that may include a logic error from a call to the current app and re-exposes the
416
+ * error to include source code information via the source map and ARC-56 spec.
417
+ * @param e The error to parse
418
+ * @param isClearStateProgram Whether or not the code was running the clear state program (defaults to approval program)
419
+ * @returns The new error, or if there was no logic error or source map then the wrapped error with source details
420
+ */
421
+ async exposeLogicError(e, isClearStateProgram) {
422
+ const pcOffsetMethod = this._appSpec.sourceInfo?.[isClearStateProgram ? "clear" : "approval"]?.pcOffsetMethod;
423
+ let program;
424
+ if (pcOffsetMethod === "cblocks") {
425
+ const appInfo = await this._algorand.app.getById(this.appId);
426
+ program = isClearStateProgram ? appInfo.clearStateProgram : appInfo.approvalProgram;
427
+ }
428
+ return AppClient.exposeLogicError(e, this._appSpec, {
429
+ isClearStateProgram,
430
+ approvalSourceMap: this._approvalSourceMap,
431
+ clearSourceMap: this._clearSourceMap,
432
+ program
433
+ });
434
+ }
435
+ /**
436
+ * Export the current source maps for the app.
437
+ * @returns The source maps
438
+ */
439
+ exportSourceMaps() {
440
+ if (!this._approvalSourceMap || !this._clearSourceMap) throw new Error("Unable to export source maps; they haven't been loaded into this client - you need to call create, update, or deploy first");
441
+ return {
442
+ approvalSourceMap: this._approvalSourceMap,
443
+ clearSourceMap: this._clearSourceMap
444
+ };
445
+ }
446
+ /**
447
+ * Import source maps for the app.
448
+ * @param sourceMaps The source maps to import
449
+ */
450
+ importSourceMaps(sourceMaps) {
451
+ this._approvalSourceMap = new SourceMap(sourceMaps.approvalSourceMap);
452
+ this._clearSourceMap = new SourceMap(sourceMaps.clearSourceMap);
453
+ }
454
+ /**
455
+ * Returns the ABI Method spec for the given method string for the app represented by this application client instance
456
+ * @param methodNameOrSignature The method name or method signature to call if an ABI call is being emitted.
457
+ * e.g. `my_method` or `my_method(unit64,string)bytes`
458
+ * @returns A tuple with: [ARC-56 `Method`, algosdk `ABIMethod`]
459
+ */
460
+ getABIMethod(methodNameOrSignature) {
461
+ return require_app_arc56.getArc56Method(methodNameOrSignature, this._appSpec);
462
+ }
463
+ /**
464
+ * Checks for decode errors on the SendAppTransactionResult and maps the return value to the specified type
465
+ * on the ARC-56 method, replacing the `return` property with the decoded type.
466
+ *
467
+ * If the return type is an ARC-56 struct then the struct will be returned.
468
+ *
469
+ * @param result The SendAppTransactionResult to be mapped
470
+ * @param method The method that was called
471
+ * @returns The smart contract response with an updated return value
472
+ */
473
+ async processMethodCallReturn(result, method) {
474
+ const resultValue = await result;
475
+ return {
476
+ ...resultValue,
477
+ return: require_app_arc56.getArc56ReturnValue(resultValue.return, method, this._appSpec.structs)
478
+ };
479
+ }
480
+ /**
481
+ * Compiles the approval and clear state programs (if TEAL templates provided),
482
+ * performing any provided deploy-time parameter replacement and stores
483
+ * the source maps.
484
+ *
485
+ * If no TEAL templates provided it will use any byte code provided in the app spec.
486
+ *
487
+ * Will store any generated source maps for later use in debugging.
488
+ * @param compilation Any compilation parameters to use
489
+ * @returns The compiled code and any compilation results (including source maps)
490
+ */
491
+ async compile(compilation) {
492
+ const result = await AppClient.compile(this._appSpec, this._algorand.app, compilation);
493
+ if (result.compiledApproval) {
494
+ this._approvalSourceMap = result.compiledApproval.sourceMap;
495
+ this._lastCompiled.approval = result.compiledApproval.compiledBase64ToBytes;
496
+ }
497
+ if (result.compiledClear) {
498
+ this._clearSourceMap = result.compiledClear.sourceMap;
499
+ this._lastCompiled.clear = result.compiledClear.compiledBase64ToBytes;
500
+ }
501
+ return result;
502
+ }
503
+ /**
504
+ * Takes an error that may include a logic error from a call to the current app and re-exposes the
505
+ * error to include source code information via the source map and ARC-56 spec.
506
+ * @param e The error to parse
507
+ * @param appSpec The app spec for the app
508
+ * @param details Additional information to inform the error
509
+ * @returns The new error, or if there was no logic error or source map then the wrapped error with source details
510
+ */
511
+ static exposeLogicError(e, appSpec, details) {
512
+ const { isClearStateProgram, approvalSourceMap, clearSourceMap, program } = details;
513
+ const sourceMap = isClearStateProgram ? clearSourceMap : approvalSourceMap;
514
+ const errorDetails = require_logic_error.LogicError.parseLogicError(e);
515
+ if (errorDetails === void 0 || errorDetails?.pc === void 0) return e;
516
+ /** The PC value to find in the ARC56 SourceInfo */
517
+ let arc56Pc = errorDetails?.pc;
518
+ const programSourceInfo = isClearStateProgram ? appSpec.sourceInfo?.clear : appSpec.sourceInfo?.approval;
519
+ /** The offset to apply to the PC if using the cblocks pc offset method */
520
+ let cblocksOffset = 0;
521
+ if (programSourceInfo?.pcOffsetMethod === "cblocks") {
522
+ if (program === void 0) throw new Error("Program bytes are required to calculate the ARC56 cblocks PC offset");
523
+ cblocksOffset = getConstantBlockOffset(program);
524
+ arc56Pc = errorDetails.pc - cblocksOffset;
525
+ }
526
+ const errorMessage = (programSourceInfo?.sourceInfo.find((s) => s.pc.includes(arc56Pc)))?.errorMessage;
527
+ if (appSpec.source) {
528
+ let getLineForPc = (inputPc) => sourceMap?.getLocationForPc?.(inputPc)?.line;
529
+ if (sourceMap === void 0) getLineForPc = (inputPc) => {
530
+ const teal = programSourceInfo?.sourceInfo.find((s) => s.pc.includes(inputPc - cblocksOffset))?.teal;
531
+ if (teal === void 0) return void 0;
532
+ return teal - 1;
533
+ };
534
+ e = new require_logic_error.LogicError(errorDetails, buffer.Buffer.from(isClearStateProgram ? appSpec.source.clear : appSpec.source.approval, "base64").toString().split("\n"), getLineForPc);
535
+ }
536
+ if (errorMessage) {
537
+ const appId = require_util.asJson(e).match(/(?<=app=)\d+/)?.[0] || "";
538
+ const txId = require_util.asJson(e).match(/(?<=transaction )\S+(?=:)/)?.[0];
539
+ const error = /* @__PURE__ */ new Error(`Runtime error when executing ${appSpec.name} (appId: ${appId}) in transaction ${txId}: ${errorMessage}`);
540
+ error.cause = e;
541
+ return error;
542
+ }
543
+ return e;
544
+ }
545
+ /**
546
+ * Compiles the approval and clear state programs (if TEAL templates provided),
547
+ * performing any provided deploy-time parameter replacement and returns
548
+ * the compiled code and any compilation results (including source maps).
549
+ *
550
+ * If no TEAL templates provided it will use any byte code provided in the app spec.
551
+ *
552
+ * Will store any generated source maps for later use in debugging.
553
+ * @param appSpec The app spec for the app
554
+ * @param appManager The app manager to use for compilation
555
+ * @param compilation Any compilation parameters to use
556
+ * @returns The compiled code and any compilation results (including source maps)
557
+ */
558
+ static async compile(appSpec, appManager, compilation) {
559
+ const { deployTimeParams, updatable, deletable } = compilation ?? {};
560
+ if (!appSpec.source) {
561
+ if (!appSpec.byteCode?.approval || !appSpec.byteCode?.clear) throw new Error(`Attempt to compile app ${appSpec.name} without source or byteCode`);
562
+ return {
563
+ approvalProgram: buffer.Buffer.from(appSpec.byteCode.approval, "base64"),
564
+ clearStateProgram: buffer.Buffer.from(appSpec.byteCode.clear, "base64")
565
+ };
566
+ }
567
+ const approvalTemplate = buffer.Buffer.from(appSpec.source.approval, "base64").toString("utf-8");
568
+ const compiledApproval = await appManager.compileTealTemplate(approvalTemplate, deployTimeParams, {
569
+ updatable,
570
+ deletable
571
+ });
572
+ const clearTemplate = buffer.Buffer.from(appSpec.source.clear, "base64").toString("utf-8");
573
+ const compiledClear = await appManager.compileTealTemplate(clearTemplate, deployTimeParams);
574
+ if (require_config.Config.debug) await require_config.Config.events.emitAsync("AppCompiled", { sources: [{
575
+ compiledTeal: compiledApproval,
576
+ appName: appSpec.name,
577
+ fileName: "approval"
578
+ }, {
579
+ compiledTeal: compiledClear,
580
+ appName: appSpec.name,
581
+ fileName: "clear"
582
+ }] });
583
+ return {
584
+ approvalProgram: compiledApproval.compiledBase64ToBytes,
585
+ compiledApproval,
586
+ clearStateProgram: compiledClear.compiledBase64ToBytes,
587
+ compiledClear
588
+ };
589
+ }
590
+ /**
591
+ * Returns ABI method arguments ready for a method call params object with default values populated
592
+ * and structs replaced with tuples.
593
+ *
594
+ * It does this by replacing any `undefined` values with the equivalent default value from the given ARC-56 app spec.
595
+ * @param methodNameOrSignature The method name or method signature to call if an ABI call is being emitted.
596
+ * e.g. `my_method` or `my_method(unit64,string)bytes`
597
+ * @param args The arguments to the method with `undefined` for any that should be populated with a default value
598
+ */
599
+ async getABIArgsWithDefaultValues(methodNameOrSignature, args, sender) {
600
+ const m = require_app_arc56.getArc56Method(methodNameOrSignature, this._appSpec);
601
+ return await Promise.all(args?.map(async (a, i) => {
602
+ const arg = m.args[i];
603
+ if (!arg) throw new Error(`Unexpected arg at position ${i}. ${m.name} only expects ${m.args.length} args`);
604
+ if (a !== void 0) return arg.struct && typeof a === "object" && !Array.isArray(a) ? require_app_arc56.getABITupleFromABIStruct(a, this._appSpec.structs[arg.struct], this._appSpec.structs) : a;
605
+ const defaultValue = arg.defaultValue;
606
+ if (defaultValue) switch (defaultValue.source) {
607
+ case "literal": return require_app_arc56.getABIDecodedValue(buffer.Buffer.from(defaultValue.data, "base64"), m.method.args[i].defaultValue?.type ?? m.method.args[i].type, this._appSpec.structs);
608
+ case "method": {
609
+ const method = this.getABIMethod(defaultValue.data);
610
+ const result = await this.send.call({
611
+ method: defaultValue.data,
612
+ args: method.args.map(() => void 0),
613
+ sender
614
+ });
615
+ if (result.return === void 0) throw new Error("Default value method call did not return a value");
616
+ if (typeof result.return === "object" && !(result.return instanceof Uint8Array) && !Array.isArray(result.return) && !(result.return instanceof algosdk.Address)) return require_app_arc56.getABITupleFromABIStruct(result.return, this._appSpec.structs[method.returns.struct], this._appSpec.structs);
617
+ return result.return;
618
+ }
619
+ case "local":
620
+ case "global": {
621
+ const state = defaultValue.source === "global" ? await this.getGlobalState() : await this.getLocalState(sender);
622
+ const value = Object.values(state).find((s) => s.keyBase64 === defaultValue.data);
623
+ if (!value) throw new Error(`Preparing default value for argument ${arg.name ?? `arg${i + 1}`} resulted in the failure: The key '${defaultValue.data}' could not be found in ${defaultValue.source} storage`);
624
+ return "valueRaw" in value ? require_app_arc56.getABIDecodedValue(value.valueRaw, m.method.args[i].defaultValue?.type ?? m.method.args[i].type, this._appSpec.structs) : value.value;
625
+ }
626
+ case "box": return require_app_arc56.getABIDecodedValue(await this.getBoxValue(buffer.Buffer.from(defaultValue.data, "base64")), m.method.args[i].defaultValue?.type ?? m.method.args[i].type, this._appSpec.structs);
627
+ }
628
+ if (!algosdk.default.abiTypeIsTransaction(arg.type)) throw new Error(`No value provided for required argument ${arg.name ?? `arg${i + 1}`} in call to method ${m.name}`);
629
+ }) ?? []);
630
+ }
631
+ getBareParamsMethods() {
632
+ return {
633
+ /** Return params for an update call, including deploy-time TEAL template replacements and compilation if provided */
634
+ update: async (params) => {
635
+ return this.getBareParams({
636
+ ...params,
637
+ ...await this.compile(params)
638
+ }, OnApplicationComplete.UpdateApplicationOC);
639
+ },
640
+ /** Return params for an opt-in call */
641
+ optIn: (params) => {
642
+ return this.getBareParams(params, OnApplicationComplete.OptInOC);
643
+ },
644
+ /** Return params for a delete call */
645
+ delete: (params) => {
646
+ return this.getBareParams(params, OnApplicationComplete.DeleteApplicationOC);
647
+ },
648
+ /** Return params for a clear state call */
649
+ clearState: (params) => {
650
+ return this.getBareParams(params, OnApplicationComplete.ClearStateOC);
651
+ },
652
+ /** Return params for a close out call */
653
+ closeOut: (params) => {
654
+ return this.getBareParams(params, OnApplicationComplete.CloseOutOC);
655
+ },
656
+ /** Return params for a call (defaults to no-op) */
657
+ call: (params) => {
658
+ return this.getBareParams(params, params?.onComplete ?? OnApplicationComplete.NoOpOC);
659
+ }
660
+ };
661
+ }
662
+ getBareCreateTransactionMethods() {
663
+ return {
664
+ /** Returns a transaction for an update call, including deploy-time TEAL template replacements and compilation if provided */
665
+ update: async (params) => {
666
+ return this._algorand.createTransaction.appUpdate(await this.params.bare.update(params));
667
+ },
668
+ /** Returns a transaction for an opt-in call */
669
+ optIn: (params) => {
670
+ return this._algorand.createTransaction.appCall(this.params.bare.optIn(params));
671
+ },
672
+ /** Returns a transaction for a delete call */
673
+ delete: (params) => {
674
+ return this._algorand.createTransaction.appDelete(this.params.bare.delete(params));
675
+ },
676
+ /** Returns a transaction for a clear state call */
677
+ clearState: (params) => {
678
+ return this._algorand.createTransaction.appCall(this.params.bare.clearState(params));
679
+ },
680
+ /** Returns a transaction for a close out call */
681
+ closeOut: (params) => {
682
+ return this._algorand.createTransaction.appCall(this.params.bare.closeOut(params));
683
+ },
684
+ /** Returns a transaction for a call (defaults to no-op) */
685
+ call: (params) => {
686
+ return this._algorand.createTransaction.appCall(this.params.bare.call(params));
687
+ }
688
+ };
689
+ }
690
+ getBareSendMethods() {
691
+ return {
692
+ /** Signs and sends an update call, including deploy-time TEAL template replacements and compilation if provided */
693
+ update: async (params) => {
694
+ const compiled = await this.compile(params);
695
+ return {
696
+ ...await this._algorand.send.appUpdate(await this.params.bare.update(params)),
697
+ ...compiled
698
+ };
699
+ },
700
+ /** Signs and sends an opt-in call */
701
+ optIn: (params) => {
702
+ return this._algorand.send.appCall(this.params.bare.optIn(params));
703
+ },
704
+ /** Signs and sends a delete call */
705
+ delete: (params) => {
706
+ return this._algorand.send.appDelete(this.params.bare.delete(params));
707
+ },
708
+ /** Signs and sends a clear state call */
709
+ clearState: (params) => {
710
+ return this._algorand.send.appCall(this.params.bare.clearState(params));
711
+ },
712
+ /** Signs and sends a close out call */
713
+ closeOut: (params) => {
714
+ return this._algorand.send.appCall(this.params.bare.closeOut(params));
715
+ },
716
+ /** Signs and sends a call (defaults to no-op) */
717
+ call: (params) => {
718
+ return this._algorand.send.appCall(this.params.bare.call(params));
719
+ }
720
+ };
721
+ }
722
+ getMethodCallParamsMethods() {
723
+ return {
724
+ /**
725
+ * Return params for a payment transaction to fund the app account
726
+ * @param params The parameters for the fund app accont payment transaction
727
+ * @returns The parameters which can be used to create a fund app account payment transaction
728
+ */
729
+ fundAppAccount: (params) => {
730
+ return {
731
+ ...params,
732
+ sender: this.getSender(params.sender),
733
+ signer: this.getSigner(params.sender, params.signer),
734
+ receiver: this.appAddress
735
+ };
736
+ },
737
+ /**
738
+ * Return params for an update ABI call, including deploy-time TEAL template replacements and compilation if provided
739
+ * @param params The parameters for the update ABI method call
740
+ * @returns The parameters which can be used to create an update ABI method call
741
+ */
742
+ update: async (params) => {
743
+ return await this.getABIParams({
744
+ ...params,
745
+ ...await this.compile(params)
746
+ }, OnApplicationComplete.UpdateApplicationOC);
747
+ },
748
+ /**
749
+ * Return params for an opt-in ABI call
750
+ * @param params The parameters for the opt-in ABI method call
751
+ * @returns The parameters which can be used to create an opt-in ABI method call
752
+ */
753
+ optIn: async (params) => {
754
+ return await this.getABIParams(params, OnApplicationComplete.OptInOC);
755
+ },
756
+ /**
757
+ * Return params for an delete ABI call
758
+ * @param params The parameters for the delete ABI method call
759
+ * @returns The parameters which can be used to create a delete ABI method call
760
+ */
761
+ delete: async (params) => {
762
+ return await this.getABIParams(params, OnApplicationComplete.DeleteApplicationOC);
763
+ },
764
+ /** Return params for an close out ABI call
765
+ * @param params The parameters for the close out ABI method call
766
+ * @returns The parameters which can be used to create a close out ABI method call
767
+ */
768
+ closeOut: async (params) => {
769
+ return await this.getABIParams(params, OnApplicationComplete.CloseOutOC);
770
+ },
771
+ /** Return params for an ABI call
772
+ * @param params The parameters for the ABI method call
773
+ * @returns The parameters which can be used to create an ABI method call
774
+ */
775
+ call: async (params) => {
776
+ return await this.getABIParams(params, params.onComplete ?? OnApplicationComplete.NoOpOC);
777
+ }
778
+ };
779
+ }
780
+ getMethodCallSendMethods() {
781
+ return {
782
+ /** Sign and send transactions for a payment transaction to fund the app account
783
+ * @param params The parameters for the fund app account payment transaction
784
+ * @returns The result of send the fund app account payment transaction
785
+ */
786
+ fundAppAccount: (params) => {
787
+ return this._algorand.send.payment(this.params.fundAppAccount(params));
788
+ },
789
+ /**
790
+ * Sign and send transactions for an update ABI call, including deploy-time TEAL template replacements and compilation if provided
791
+ * @param params The parameters for the update ABI method call
792
+ * @returns The result of sending the update ABI method call
793
+ */
794
+ update: async (params) => {
795
+ const compiled = await this.compile(params);
796
+ return {
797
+ ...await this.processMethodCallReturn(this._algorand.send.appUpdateMethodCall(await this.params.update({ ...params })), require_app_arc56.getArc56Method(params.method, this._appSpec)),
798
+ ...compiled
799
+ };
800
+ },
801
+ /**
802
+ * Sign and send transactions for an opt-in ABI call
803
+ * @param params The parameters for the opt-in ABI method call
804
+ * @returns The result of sending the opt-in ABI method call
805
+ */
806
+ optIn: async (params) => {
807
+ return this.processMethodCallReturn(this._algorand.send.appCallMethodCall(await this.params.optIn(params)), require_app_arc56.getArc56Method(params.method, this._appSpec));
808
+ },
809
+ /**
810
+ * Sign and send transactions for a delete ABI call
811
+ * @param params The parameters for the delete ABI method call
812
+ * @returns The result of sending the delete ABI method call
813
+ */
814
+ delete: async (params) => {
815
+ return this.processMethodCallReturn(this._algorand.send.appDeleteMethodCall(await this.params.delete(params)), require_app_arc56.getArc56Method(params.method, this._appSpec));
816
+ },
817
+ /**
818
+ * Sign and send transactions for a close out ABI call
819
+ * @param params The parameters for the close out ABI method call
820
+ * @returns The result of sending the close out ABI method call
821
+ */
822
+ closeOut: async (params) => {
823
+ return this.processMethodCallReturn(this._algorand.send.appCallMethodCall(await this.params.closeOut(params)), require_app_arc56.getArc56Method(params.method, this._appSpec));
824
+ },
825
+ /**
826
+ * Sign and send transactions for a call (defaults to no-op)
827
+ * @param params The parameters for the ABI method call
828
+ * @returns The result of sending the ABI method call
829
+ */
830
+ call: async (params) => {
831
+ if ((params.onComplete === OnApplicationComplete.NoOpOC || !params.onComplete) && require_app_arc56.getArc56Method(params.method, this._appSpec).method.readonly) {
832
+ const readonlyParams = { ...params };
833
+ if (params.coverAppCallInnerTransactionFees && params.maxFee) {
834
+ readonlyParams.staticFee = params.maxFee;
835
+ readonlyParams.extraFee = void 0;
836
+ }
837
+ try {
838
+ const result = await this._algorand.newGroup().addAppCallMethodCall(await this.params.call(readonlyParams)).simulate({
839
+ allowUnnamedResources: params.populateAppCallResources ?? true,
840
+ skipSignatures: true,
841
+ extraOpcodeBudget: MAX_SIMULATE_OPCODE_BUDGET
842
+ });
843
+ return this.processMethodCallReturn({
844
+ ...result,
845
+ transaction: result.transactions.at(-1),
846
+ confirmation: result.confirmations.at(-1),
847
+ return: result.returns?.length ?? false ? result.returns?.at(-1) : void 0
848
+ }, require_app_arc56.getArc56Method(params.method, this._appSpec));
849
+ } catch (e) {
850
+ const error = e;
851
+ if (params.coverAppCallInnerTransactionFees && error && error.message && error.message.match(/fee ([\w.]+\s+)?too small/)) throw Error(`Fees were too small. You may need to increase the transaction maxFee.`);
852
+ throw e;
853
+ }
854
+ }
855
+ return this.processMethodCallReturn(this._algorand.send.appCallMethodCall(await this.params.call(params)), require_app_arc56.getArc56Method(params.method, this._appSpec));
856
+ }
857
+ };
858
+ }
859
+ getMethodCallCreateTransactionMethods() {
860
+ return {
861
+ /** Return transaction for a payment transaction to fund the app account
862
+ * @param params The parameters for the fund app account payment transaction
863
+ * @returns A transaction which can be used to fund the app account
864
+ */
865
+ fundAppAccount: (params) => {
866
+ return this._algorand.createTransaction.payment(this.params.fundAppAccount(params));
867
+ },
868
+ /**
869
+ * Return transactions for an update ABI call, including deploy-time TEAL template replacements and compilation if provided
870
+ * @param params The parameters for the update ABI method call
871
+ * @returns The transactions which can be used to create an update ABI method call
872
+ */
873
+ update: async (params) => {
874
+ return this._algorand.createTransaction.appUpdateMethodCall(await this.params.update(params));
875
+ },
876
+ /**
877
+ * Return transactions for an opt-in ABI call
878
+ * @param params The parameters for the opt-in ABI method call
879
+ * @returns The transactions which can be used to create an opt-in ABI method call
880
+ */
881
+ optIn: async (params) => {
882
+ return this._algorand.createTransaction.appCallMethodCall(await this.params.optIn(params));
883
+ },
884
+ /**
885
+ * Return transactions for a delete ABI call
886
+ * @param params The parameters for the delete ABI method call
887
+ * @returns The transactions which can be used to create a delete ABI method call
888
+ */
889
+ delete: async (params) => {
890
+ return this._algorand.createTransaction.appDeleteMethodCall(await this.params.delete(params));
891
+ },
892
+ /**
893
+ * Return transactions for a close out ABI call
894
+ * @param params The parameters for the close out ABI method call
895
+ * @returns The transactions which can be used to create a close out ABI method call
896
+ */
897
+ closeOut: async (params) => {
898
+ return this._algorand.createTransaction.appCallMethodCall(await this.params.closeOut(params));
899
+ },
900
+ /**
901
+ * Return transactions for an ABI call (defaults to no-op)
902
+ * @param params The parameters for the ABI method call
903
+ * @returns The transactions which can be used to create an ABI method call
904
+ */
905
+ call: async (params) => {
906
+ return this._algorand.createTransaction.appCallMethodCall(await this.params.call(params));
907
+ }
908
+ };
909
+ }
910
+ /** Returns the sender for a call, using the provided sender or using the `defaultSender`
911
+ * if none provided and throws an error if neither provided */
912
+ getSender(sender) {
913
+ if (!sender && !this._defaultSender) throw new Error(`No sender provided and no default sender present in app client for call to app ${this._appName}`);
914
+ return typeof sender === "string" ? algosdk.Address.fromString(sender) : sender ?? this._defaultSender;
915
+ }
916
+ /** Returns the signer for a call, using the provided signer or the `defaultSigner`
917
+ * if no signer was provided and the sender resolves to the default sender, the call will use default signer
918
+ * or `undefined` otherwise (so the signer is resolved from `AlgorandClient`) */
919
+ getSigner(sender, signer) {
920
+ return signer ?? (!sender || sender === this._defaultSender ? this._defaultSigner : void 0);
921
+ }
922
+ getBareParams(params, onComplete) {
923
+ return {
924
+ ...params,
925
+ appId: this._appId,
926
+ sender: this.getSender(params?.sender),
927
+ signer: this.getSigner(params?.sender, params?.signer),
928
+ onComplete
929
+ };
930
+ }
931
+ async getABIParams(params, onComplete) {
932
+ const sender = this.getSender(params.sender);
933
+ const method = require_app_arc56.getArc56Method(params.method, this._appSpec);
934
+ const args = await this.getABIArgsWithDefaultValues(params.method, params.args, sender);
935
+ return {
936
+ ...params,
937
+ appId: this._appId,
938
+ sender,
939
+ signer: this.getSigner(params.sender, params.signer),
940
+ method,
941
+ onComplete,
942
+ args
943
+ };
944
+ }
945
+ /** Make the given call and catch any errors, augmenting with debugging information before re-throwing. */
946
+ handleCallErrors = async (e) => {
947
+ if (this.appId === 0n) {
948
+ if (e.sentTransactions === void 0) return e;
949
+ const txn = e.sentTransactions.find((t) => e.message.includes(t.txID()));
950
+ const programsDefinedAndEqual = (a, b) => {
951
+ if (a === void 0 || b === void 0) return false;
952
+ if (a.length !== b.length) return false;
953
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
954
+ return true;
955
+ };
956
+ if (!programsDefinedAndEqual(txn?.applicationCall?.clearProgram, this._lastCompiled.clear) || !programsDefinedAndEqual(txn?.applicationCall?.approvalProgram, this._lastCompiled?.approval)) return e;
957
+ } else {
958
+ const appIdString = `app=${this._appId.toString()}`;
959
+ if (!e.message.includes(appIdString)) return e;
960
+ }
961
+ const logicError = await this.exposeLogicError(e);
962
+ if (logicError instanceof require_logic_error.LogicError) {
963
+ let currentLine = logicError.teal_line - logicError.lines - 1;
964
+ const stackWithLines = logicError.stack?.split("\n").map((line) => `${currentLine += 1}: ${line}`).join("\n");
965
+ require_config.Config.logger.error(`${logicError.message}\n\n${stackWithLines}`);
966
+ }
967
+ return logicError;
968
+ };
969
+ getBoxMethods() {
970
+ const that = this;
971
+ const stateMethods = {
972
+ /**
973
+ * Returns all single-key state values in a record keyed by the key name and the value a decoded ABI value.
974
+ */
975
+ getAll: async () => {
976
+ return Object.fromEntries(await Promise.all(Object.keys(that._appSpec.state.keys.box).map(async (key) => [key, await stateMethods.getValue(key)])));
977
+ },
978
+ /**
979
+ * Returns a single state value for the current app with the value a decoded ABI value.
980
+ * @param name The name of the state value to retrieve the value for
981
+ * @returns
982
+ */
983
+ getValue: async (name) => {
984
+ const metadata = that._appSpec.state.keys.box[name];
985
+ return require_app_arc56.getABIDecodedValue(await that.getBoxValue(buffer.Buffer.from(metadata.key, "base64")), metadata.valueType, that._appSpec.structs);
986
+ },
987
+ /**
988
+ *
989
+ * @param mapName The name of the map to read from
990
+ * @param key The key within the map (without any map prefix) as either a Buffer with the bytes or a value
991
+ * that will be converted to bytes by encoding it using the specified ABI key type
992
+ * in the ARC-56 spec
993
+ */
994
+ getMapValue: async (mapName, key) => {
995
+ const metadata = that._appSpec.state.maps.box[mapName];
996
+ const prefix = buffer.Buffer.from(metadata.prefix ?? "", "base64");
997
+ const encodedKey = buffer.Buffer.concat([prefix, require_app_arc56.getABIEncodedValue(key, metadata.keyType, that._appSpec.structs)]);
998
+ const base64Key = buffer.Buffer.from(encodedKey).toString("base64");
999
+ return require_app_arc56.getABIDecodedValue(await that.getBoxValue(buffer.Buffer.from(base64Key, "base64")), metadata.valueType, that._appSpec.structs);
1000
+ },
1001
+ /**
1002
+ *
1003
+ * @param mapName The name of the map to read from
1004
+ * @param key The key within the map as either a Buffer with the bytes or a value
1005
+ * that will be converted to bytes by encoding it using the specified ABI key type
1006
+ * in the ARC-56 spec
1007
+ * @param appState
1008
+ */
1009
+ getMap: async (mapName) => {
1010
+ const metadata = that._appSpec.state.maps.box[mapName];
1011
+ const prefix = buffer.Buffer.from(metadata.prefix ?? "", "base64");
1012
+ const boxNames = await that.getBoxNames();
1013
+ return new Map(await Promise.all(boxNames.filter((b) => require_util.binaryStartsWith(b.nameRaw, prefix)).map(async (b) => {
1014
+ return [require_app_arc56.getABIDecodedValue(b.nameRaw.slice(prefix.length), metadata.keyType, that._appSpec.structs), require_app_arc56.getABIDecodedValue(await that.getBoxValue(b.nameRaw), metadata.valueType, that._appSpec.structs)];
1015
+ })));
1016
+ }
1017
+ };
1018
+ return stateMethods;
1019
+ }
1020
+ getStateMethods(stateGetter, keyGetter, mapGetter) {
1021
+ const that = this;
1022
+ const stateMethods = {
1023
+ /**
1024
+ * Returns all single-key state values in a record keyed by the key name and the value a decoded ABI value.
1025
+ */
1026
+ getAll: async () => {
1027
+ const appState = await stateGetter();
1028
+ return Object.fromEntries(await Promise.all(Object.keys(keyGetter()).map(async (key) => [key, await stateMethods.getValue(key, appState)])));
1029
+ },
1030
+ /**
1031
+ * Returns a single state value for the current app with the value a decoded ABI value.
1032
+ * @param name The name of the state value to retrieve the value for
1033
+ * @param appState Optional cached value of the current state
1034
+ * @returns
1035
+ */
1036
+ getValue: async (name, appState) => {
1037
+ const state = Object.values(appState ?? await stateGetter());
1038
+ const metadata = keyGetter()[name];
1039
+ if (metadata === void 0) throw new Error(`Attempted to get state value ${name}, but it does not exist`);
1040
+ const value = state.find((s) => s.keyBase64 === metadata.key);
1041
+ if (value && "valueRaw" in value) return require_app_arc56.getABIDecodedValue(value.valueRaw, metadata.valueType, that._appSpec.structs);
1042
+ return value?.value;
1043
+ },
1044
+ /**
1045
+ * Returns a single value from the given map for the current app with the value a decoded ABI value.
1046
+ * @param mapName The name of the map to read from
1047
+ * @param key The key within the map (without any map prefix) as either a Buffer with the bytes or a value
1048
+ * that will be converted to bytes by encoding it using the specified ABI key type
1049
+ * in the ARC-56 spec
1050
+ * @param appState Optional cached value of the current state
1051
+ */
1052
+ getMapValue: async (mapName, key, appState) => {
1053
+ const state = Object.values(appState ?? await stateGetter());
1054
+ const metadata = mapGetter()[mapName];
1055
+ const prefix = buffer.Buffer.from(metadata.prefix ?? "", "base64");
1056
+ const encodedKey = buffer.Buffer.concat([prefix, require_app_arc56.getABIEncodedValue(key, metadata.keyType, that._appSpec.structs)]);
1057
+ const base64Key = buffer.Buffer.from(encodedKey).toString("base64");
1058
+ const value = state.find((s) => s.keyBase64 === base64Key);
1059
+ if (value && "valueRaw" in value) return require_app_arc56.getABIDecodedValue(value.valueRaw, metadata.valueType, that._appSpec.structs);
1060
+ return value?.value;
1061
+ },
1062
+ /**
1063
+ * Returns all map values for the given map.
1064
+ * @param mapName The name of the map to read from
1065
+ * @param appState Optional cached value of the current state
1066
+ * @returns A map of all key-value pairs in the map as a `Record<string, ABIValue>`
1067
+ */
1068
+ getMap: async (mapName) => {
1069
+ const state = Object.values(await stateGetter());
1070
+ const metadata = mapGetter()[mapName];
1071
+ const prefix = buffer.Buffer.from(metadata.prefix ?? "", "base64");
1072
+ return new Map(state.filter((s) => require_util.binaryStartsWith(s.keyRaw, prefix)).map((s) => {
1073
+ return [require_app_arc56.getABIDecodedValue(s.keyRaw.slice(prefix.length), metadata.keyType, this._appSpec.structs), require_app_arc56.getABIDecodedValue("valueRaw" in s ? s.valueRaw : s.value, metadata.valueType, this._appSpec.structs)];
1074
+ }));
1075
+ }
1076
+ };
1077
+ return stateMethods;
1078
+ }
1079
+ };
1185
1080
  /**
1186
- * @deprecated Use `AppClient` instead e.g. via `algorand.client.getAppClientById` or
1187
- * `algorand.client.getAppClientByCreatorAndName`.
1188
- * If you want to `create` or `deploy` then use `AppFactory` e.g. via `algorand.client.getAppFactory`,
1189
- * which will in turn give you an `AppClient` instance against the created/deployed app to make other calls.
1190
- *
1191
- * Application client - a class that wraps an ARC-0032 app spec and provides high productivity methods to deploy and call the app */
1192
- class ApplicationClient {
1193
- /**
1194
- * @deprecated Use `AppClient` instead e.g. via `algorand.client.getAppClientById` or
1195
- * `algorand.client.getAppClientByCreatorAndName`.
1196
- * If you want to `create` or `deploy` then use `AppFactory` e.g. via `algorand.client.getAppFactory`,
1197
- * which will in turn give you an `AppClient` instance against the created/deployed app to make other calls.
1198
- *
1199
- * Create a new ApplicationClient instance
1200
- * @param appDetails The details of the app
1201
- * @param algod An algod instance
1202
- */
1203
- constructor(appDetails, algod) {
1204
- const { app, sender, params, deployTimeParams, ...appIdentifier } = appDetails;
1205
- this.algod = algod;
1206
- this.appSpec = typeof app == 'string' ? JSON.parse(app) : app;
1207
- this._appName = appIdentifier.name ?? this.appSpec.contract.name;
1208
- this.deployTimeParams = deployTimeParams;
1209
- if (appIdentifier.resolveBy === 'id') {
1210
- if (appIdentifier.id < 0) {
1211
- throw new Error(`Attempt to create application client with invalid app id of ${appIdentifier.id}`);
1212
- }
1213
- this._appId = appIdentifier.id;
1214
- }
1215
- else {
1216
- this._appId = 0;
1217
- this._creator = appIdentifier.creatorAddress?.toString();
1218
- if (appIdentifier.findExistingUsing instanceof Indexer) {
1219
- this.indexer = appIdentifier.findExistingUsing;
1220
- }
1221
- else {
1222
- if (appIdentifier.findExistingUsing.creator !== this._creator) {
1223
- throw new Error(`Attempt to create application client with invalid existingDeployments against a different creator (${appIdentifier.findExistingUsing.creator}) instead of expected creator ${this._creator}`);
1224
- }
1225
- this.existingDeployments = appIdentifier.findExistingUsing;
1226
- }
1227
- }
1228
- this._appAddress = algosdk.getApplicationAddress(this._appId).toString();
1229
- this.sender = sender;
1230
- this.params = params;
1231
- }
1232
- /**
1233
- * @deprecated Use `AppClient.compile()` instead.
1234
- *
1235
- * Compiles the approval and clear state programs and sets up the source map.
1236
- * @param compilation The deploy-time parameters for the compilation
1237
- * @returns The compiled approval and clear state programs
1238
- */
1239
- async compile(compilation) {
1240
- const { deployTimeParams, updatable, deletable } = compilation ?? {};
1241
- const approvalTemplate = buffer.Buffer.from(this.appSpec.source.approval, 'base64').toString('utf-8');
1242
- const approval = appDeploy.replaceDeployTimeControlParams(appDeploy.performTemplateSubstitution(approvalTemplate, deployTimeParams ?? this.deployTimeParams), {
1243
- updatable,
1244
- deletable,
1245
- });
1246
- const approvalCompiled = await app.compileTeal(approval, this.algod);
1247
- this._approvalSourceMap = approvalCompiled?.sourceMap;
1248
- const clearTemplate = buffer.Buffer.from(this.appSpec.source.clear, 'base64').toString('utf-8');
1249
- const clear = appDeploy.performTemplateSubstitution(clearTemplate, deployTimeParams ?? this.deployTimeParams);
1250
- const clearCompiled = await app.compileTeal(clear, this.algod);
1251
- this._clearSourceMap = clearCompiled?.sourceMap;
1252
- if (config.Config.debug) {
1253
- await config.Config.events.emitAsync(types_lifecycleEvents.EventType.AppCompiled, {
1254
- sources: [
1255
- { compiledTeal: approvalCompiled, appName: this._appName, fileName: 'approval' },
1256
- { compiledTeal: clearCompiled, appName: this._appName, fileName: 'clear' },
1257
- ],
1258
- });
1259
- }
1260
- return { approvalCompiled, clearCompiled };
1261
- }
1262
- /**
1263
- * Export the current source maps for the app.
1264
- * @returns The source maps
1265
- */
1266
- exportSourceMaps() {
1267
- if (!this._approvalSourceMap || !this._clearSourceMap) {
1268
- throw new Error("Unable to export source maps; they haven't been loaded into this client - you need to call create, update, or deploy first");
1269
- }
1270
- return {
1271
- approvalSourceMap: this._approvalSourceMap,
1272
- clearSourceMap: this._clearSourceMap,
1273
- };
1274
- }
1275
- /**
1276
- * Import source maps for the app.
1277
- * @param sourceMaps The source maps to import
1278
- */
1279
- importSourceMaps(sourceMaps) {
1280
- this._approvalSourceMap = new SourceMap(sourceMaps.approvalSourceMap);
1281
- this._clearSourceMap = new SourceMap(sourceMaps.clearSourceMap);
1282
- }
1283
- /**
1284
- * @deprecated Use `deploy` from an `AppFactory` instance instead.
1285
- *
1286
- * Idempotently deploy (create, update/delete if changed) an app against the given name via the given creator account, including deploy-time template placeholder substitutions.
1287
- *
1288
- * To understand the architecture decisions behind this functionality please see https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md
1289
- *
1290
- * **Note:** if there is a breaking state schema change to an existing app (and `onSchemaBreak` is set to `'replace'`) the existing app will be deleted and re-created.
1291
- *
1292
- * **Note:** if there is an update (different TEAL code) to an existing app (and `onUpdate` is set to `'replace'`) the existing app will be deleted and re-created.
1293
- * @param deploy Deployment details
1294
- * @returns The metadata and transaction result(s) of the deployment, or just the metadata if it didn't need to issue transactions
1295
- */
1296
- async deploy(deploy) {
1297
- const { schema, sender: deploySender, version, allowUpdate, allowDelete, sendParams, createArgs, createOnCompleteAction, updateArgs, deleteArgs, ...deployArgs } = deploy ?? {};
1298
- if (this._appId !== 0) {
1299
- throw new Error(`Attempt to deploy app which already has an app id of ${this._appId}`);
1300
- }
1301
- const sender = deploySender ?? this.sender;
1302
- if (!sender) {
1303
- throw new Error('No sender provided, unable to deploy app');
1304
- }
1305
- const from = sender ?? this.sender;
1306
- if (!this._creator) {
1307
- throw new Error("Attempt to `deploy` a contract without specifying `resolveBy: 'creatorAndName'` in the constructor");
1308
- }
1309
- if (this._creator !== transaction.getSenderAddress(from)) {
1310
- throw new Error(`Attempt to deploy contract with a sender address (${transaction.getSenderAddress(from)}) that differs from the given creator address for this application client: ${this._creator}`);
1311
- }
1312
- const approval = buffer.Buffer.from(this.appSpec.source.approval, 'base64').toString('utf-8');
1313
- const compilation = {
1314
- deployTimeParams: deployArgs.deployTimeParams,
1315
- updatable: allowUpdate !== undefined
1316
- ? allowUpdate
1317
- : getDeployTimeControl(approval, this.appSpec, types_app.UPDATABLE_TEMPLATE_NAME, 'update_application'),
1318
- deletable: allowDelete !== undefined
1319
- ? allowDelete
1320
- : getDeployTimeControl(approval, this.appSpec, types_app.DELETABLE_TEMPLATE_NAME, 'delete_application'),
1321
- };
1322
- const { approvalCompiled, clearCompiled } = await this.compile(compilation);
1323
- try {
1324
- await this.getAppReference();
1325
- const result = await appDeploy.deployApp({
1326
- from: sender,
1327
- approvalProgram: approvalCompiled.compiledBase64ToBytes,
1328
- clearStateProgram: clearCompiled.compiledBase64ToBytes,
1329
- metadata: {
1330
- name: this._appName,
1331
- version: version ?? '1.0',
1332
- updatable: compilation.updatable,
1333
- deletable: compilation.deletable,
1334
- },
1335
- schema: {
1336
- globalByteSlices: this.appSpec.state.global.num_byte_slices,
1337
- globalInts: this.appSpec.state.global.num_uints,
1338
- localByteSlices: this.appSpec.state.local.num_byte_slices,
1339
- localInts: this.appSpec.state.local.num_uints,
1340
- ...schema,
1341
- },
1342
- transactionParams: this.params,
1343
- ...(sendParams ?? {}),
1344
- existingDeployments: this.existingDeployments,
1345
- createArgs: await this.getCallArgs(createArgs, sender),
1346
- createOnCompleteAction: createOnCompleteAction,
1347
- updateArgs: await this.getCallArgs(updateArgs, sender),
1348
- deleteArgs: await this.getCallArgs(deleteArgs, sender),
1349
- ...deployArgs,
1350
- }, this.algod, this.indexer);
1351
- // Nothing needed to happen
1352
- if (result.operationPerformed === 'nothing') {
1353
- return result;
1354
- }
1355
- if (!this.existingDeployments) {
1356
- throw new Error('Expected existingDeployments to be present');
1357
- }
1358
- const { transaction, confirmation, operationPerformed, ...appMetadata } = result;
1359
- this.existingDeployments = {
1360
- creator: this.existingDeployments.creator,
1361
- apps: { ...this.existingDeployments.apps, [this._appName]: appMetadata },
1362
- };
1363
- return { ...result, ...{ compiledApproval: approvalCompiled, compiledClear: clearCompiled } };
1364
- }
1365
- catch (e) {
1366
- throw this.exposeLogicError(e);
1367
- }
1368
- }
1369
- /**
1370
- * @deprecated Use `create` from an `AppFactory` instance instead.
1371
- *
1372
- * Creates a smart contract app, returns the details of the created app.
1373
- * @param create The parameters to create the app with
1374
- * @returns The details of the created app, or the transaction to create it if `skipSending` and the compilation result
1375
- */
1376
- async create(create) {
1377
- const { sender: createSender, note, sendParams, deployTimeParams, updatable, deletable, onCompleteAction, schema, ...args } = create ?? {};
1378
- if (this._appId !== 0) {
1379
- throw new Error(`Attempt to create app which already has an app id of ${this._appId}`);
1380
- }
1381
- const sender = createSender ?? this.sender;
1382
- if (!sender) {
1383
- throw new Error('No sender provided, unable to create app');
1384
- }
1385
- const { approvalCompiled, clearCompiled } = await this.compile(create);
1386
- try {
1387
- const result = await app.createApp({
1388
- from: sender,
1389
- approvalProgram: approvalCompiled.compiledBase64ToBytes,
1390
- clearStateProgram: clearCompiled.compiledBase64ToBytes,
1391
- schema: {
1392
- globalByteSlices: this.appSpec.state.global.num_byte_slices,
1393
- globalInts: this.appSpec.state.global.num_uints,
1394
- localByteSlices: this.appSpec.state.local.num_byte_slices,
1395
- localInts: this.appSpec.state.local.num_uints,
1396
- ...schema,
1397
- },
1398
- onCompleteAction,
1399
- args: await this.getCallArgs(args, sender),
1400
- note: note,
1401
- transactionParams: this.params,
1402
- ...(sendParams ?? {}),
1403
- }, this.algod);
1404
- if (result.confirmation) {
1405
- this._appId = result.confirmation.applicationIndex;
1406
- this._appAddress = getApplicationAddress(this._appId).toString();
1407
- }
1408
- return { ...result, ...{ compiledApproval: approvalCompiled, compiledClear: clearCompiled } };
1409
- }
1410
- catch (e) {
1411
- throw await this.exposeLogicError(e);
1412
- }
1413
- }
1414
- /**
1415
- * @deprecated Use `appClient.send.update` or `appClient.createTransaction.update` from an `AppClient` instance instead.
1416
- *
1417
- * Updates the smart contract app.
1418
- * @param update The parameters to update the app with
1419
- * @returns The transaction send result and the compilation result
1420
- */
1421
- async update(update) {
1422
- const { sender: updateSender, note, sendParams, deployTimeParams, updatable, deletable, ...args } = update ?? {};
1423
- if (this._appId === 0) {
1424
- throw new Error(`Attempt to update app which doesn't have an app id defined`);
1425
- }
1426
- const sender = updateSender ?? this.sender;
1427
- if (!sender) {
1428
- throw new Error('No sender provided, unable to create app');
1429
- }
1430
- const { approvalCompiled, clearCompiled } = await this.compile(update);
1431
- try {
1432
- const result = await app.updateApp({
1433
- appId: this._appId,
1434
- from: sender,
1435
- approvalProgram: approvalCompiled.compiledBase64ToBytes,
1436
- clearStateProgram: clearCompiled.compiledBase64ToBytes,
1437
- args: await this.getCallArgs(args, sender),
1438
- note: note,
1439
- transactionParams: this.params,
1440
- ...(sendParams ?? {}),
1441
- }, this.algod);
1442
- return { ...result, ...{ compiledApproval: approvalCompiled, compiledClear: clearCompiled } };
1443
- }
1444
- catch (e) {
1445
- throw await this.exposeLogicError(e);
1446
- }
1447
- }
1448
- /**
1449
- * @deprecated Use `appClient.send.call` or `appClient.createTransaction.call` from an `AppClient` instance instead.
1450
- *
1451
- * Issues a no_op (normal) call to the app.
1452
- * @param call The call details.
1453
- * @returns The result of the call
1454
- */
1455
- async call(call) {
1456
- if (
1457
- // ABI call
1458
- call?.method &&
1459
- // We aren't skipping the send
1460
- !call.sendParams?.skipSending &&
1461
- // There isn't an ATC passed in
1462
- !call.sendParams?.atc &&
1463
- // The method is readonly
1464
- this.appSpec.hints[this.getABIMethodSignature(this.getABIMethod(call.method))].read_only) {
1465
- const atc = new AtomicTransactionComposer();
1466
- await this.callOfType({ ...call, sendParams: { ...call.sendParams, atc } }, 'no_op');
1467
- const result = await atc.simulate(this.algod);
1468
- if (result.simulateResponse.txnGroups.some((group) => group.failureMessage)) {
1469
- throw new Error(result.simulateResponse.txnGroups.find((x) => x.failureMessage)?.failureMessage);
1470
- }
1471
- const txns = atc.buildGroup();
1472
- return {
1473
- transaction: txns[txns.length - 1].txn,
1474
- confirmation: result.simulateResponse.txnGroups[0].txnResults.at(-1)?.txnResult,
1475
- confirmations: result.simulateResponse.txnGroups[0].txnResults.map((t) => t.txnResult),
1476
- transactions: txns.map((t) => t.txn),
1477
- return: (result.methodResults?.length ?? 0 > 0) ? result.methodResults[result.methodResults.length - 1] : undefined,
1478
- };
1479
- }
1480
- return await this.callOfType(call, 'no_op');
1481
- }
1482
- /**
1483
- * @deprecated Use `appClient.send.optIn` or `appClient.createTransaction.optIn` from an `AppClient` instance instead.
1484
- *
1485
- * Issues a opt_in call to the app.
1486
- * @param call The call details.
1487
- * @returns The result of the call
1488
- */
1489
- async optIn(call) {
1490
- return await this.callOfType(call, 'opt_in');
1491
- }
1492
- /**
1493
- * @deprecated Use `appClient.send.closeOut` or `appClient.createTransaction.closeOut` from an `AppClient` instance instead.
1494
- *
1495
- * Issues a close_out call to the app.
1496
- * @param call The call details.
1497
- * @returns The result of the call
1498
- */
1499
- async closeOut(call) {
1500
- return await this.callOfType(call, 'close_out');
1501
- }
1502
- /**
1503
- * @deprecated Use `appClient.send.clearState` or `appClient.createTransaction.clearState` from an `AppClient` instance instead.
1504
- *
1505
- * Issues a clear_state call to the app.
1506
- * @param call The call details.
1507
- * @returns The result of the call
1508
- */
1509
- async clearState(call) {
1510
- return await this.callOfType(call, 'clear_state');
1511
- }
1512
- /**
1513
- * @deprecated Use `appClient.send.delete` or `appClient.createTransaction.delete` from an `AppClient` instance instead.
1514
- *
1515
- * Issues a delete_application call to the app.
1516
- * @param call The call details.
1517
- * @returns The result of the call
1518
- */
1519
- async delete(call) {
1520
- return await this.callOfType(call, 'delete_application');
1521
- }
1522
- /**
1523
- * @deprecated Use `appClient.send.call` or `appClient.createTransaction.call` from an `AppClient` instance instead.
1524
- *
1525
- * Issues a call to the app with the given call type.
1526
- * @param call The call details.
1527
- * @param callType The call type
1528
- * @returns The result of the call
1529
- */
1530
- async callOfType(call = {}, callType) {
1531
- const { sender: callSender, note, sendParams, ...args } = call;
1532
- const sender = callSender ?? this.sender;
1533
- if (!sender) {
1534
- throw new Error('No sender provided, unable to call app');
1535
- }
1536
- const appMetadata = await this.getAppReference();
1537
- if (appMetadata.appId === 0) {
1538
- throw new Error(`Attempt to call an app that can't be found '${this._appName}' for creator '${this._creator}'.`);
1539
- }
1540
- try {
1541
- return await app.callApp({
1542
- appId: appMetadata.appId,
1543
- callType: callType,
1544
- from: sender,
1545
- args: await this.getCallArgs(args, sender),
1546
- note: note,
1547
- transactionParams: this.params,
1548
- ...(sendParams ?? {}),
1549
- }, this.algod);
1550
- }
1551
- catch (e) {
1552
- throw this.exposeLogicError(e);
1553
- }
1554
- }
1555
- /**
1556
- * Funds Algo into the app account for this app.
1557
- * @param fund The parameters for the funding or the funding amount
1558
- * @returns The result of the funding
1559
- */
1560
- async fundAppAccount(fund) {
1561
- const { amount, sender, note, sendParams } = 'microAlgos' in fund ? { amount: fund } : fund;
1562
- if (!sender && !this.sender) {
1563
- throw new Error('No sender provided, unable to call app');
1564
- }
1565
- const ref = await this.getAppReference();
1566
- return legacyBridge.legacySendTransactionBridge(this.algod, sender ?? this.sender, sendParams ?? {}, {
1567
- receiver: ref.appAddress,
1568
- sender: transaction.getSenderAddress(sender ?? this.sender),
1569
- amount: amount,
1570
- note: transaction.encodeTransactionNote(note),
1571
- }, (c) => c.payment, (c) => c.payment, this.params);
1572
- }
1573
- /**
1574
- * Returns global state for the current app.
1575
- * @returns The global state
1576
- */
1577
- async getGlobalState() {
1578
- const appRef = await this.getAppReference();
1579
- if (appRef.appId === 0) {
1580
- throw new Error('No app has been created yet, unable to get global state');
1581
- }
1582
- return app.getAppGlobalState(appRef.appId, this.algod);
1583
- }
1584
- /**
1585
- * Returns local state for the given account / account address.
1586
- * @returns The global state
1587
- */
1588
- async getLocalState(account) {
1589
- const appRef = await this.getAppReference();
1590
- if (appRef.appId === 0) {
1591
- throw new Error('No app has been created yet, unable to get global state');
1592
- }
1593
- return app.getAppLocalState(appRef.appId, account, this.algod);
1594
- }
1595
- /**
1596
- * Returns the names of all current boxes for the current app.
1597
- * @returns The names of the boxes
1598
- */
1599
- async getBoxNames() {
1600
- const appRef = await this.getAppReference();
1601
- if (appRef.appId === 0) {
1602
- throw new Error('No app has been created yet, unable to get global state');
1603
- }
1604
- return await app.getAppBoxNames(appRef.appId, this.algod);
1605
- }
1606
- /**
1607
- * Returns the value of the given box for the current app.
1608
- * @param name The name of the box to return either as a string, binary array or `BoxName`
1609
- * @returns The current box value as a byte array
1610
- */
1611
- async getBoxValue(name) {
1612
- const appRef = await this.getAppReference();
1613
- if (appRef.appId === 0) {
1614
- throw new Error('No app has been created yet, unable to get global state');
1615
- }
1616
- return await app.getAppBoxValue(appRef.appId, name, this.algod);
1617
- }
1618
- /**
1619
- * Returns the value of the given box for the current app.
1620
- * @param name The name of the box to return either as a string, binary array or `BoxName`
1621
- * @param type
1622
- * @returns The current box value as a byte array
1623
- */
1624
- async getBoxValueFromABIType(name, type) {
1625
- const appRef = await this.getAppReference();
1626
- if (appRef.appId === 0) {
1627
- throw new Error('No app has been created yet, unable to get global state');
1628
- }
1629
- return await app.getAppBoxValueFromABIType({ appId: appRef.appId, boxName: name, type }, this.algod);
1630
- }
1631
- /**
1632
- * Returns the values of all current boxes for the current app.
1633
- * Note: This will issue multiple HTTP requests (one per box) and it's not an atomic operation so values may be out of sync.
1634
- * @param filter Optional filter to filter which boxes' values are returned
1635
- * @returns The (name, value) pair of the boxes with values as raw byte arrays
1636
- */
1637
- async getBoxValues(filter) {
1638
- const appRef = await this.getAppReference();
1639
- if (appRef.appId === 0) {
1640
- throw new Error('No app has been created yet, unable to get global state');
1641
- }
1642
- const names = await this.getBoxNames();
1643
- return await Promise.all(names
1644
- .filter(filter ?? ((_) => true))
1645
- .map(async (boxName) => ({ name: boxName, value: await app.getAppBoxValue(appRef.appId, boxName, this.algod) })));
1646
- }
1647
- /**
1648
- * Returns the values of all current boxes for the current app decoded using an ABI Type.
1649
- * Note: This will issue multiple HTTP requests (one per box) and it's not an atomic operation so values may be out of sync.
1650
- * @param type The ABI type to decode the values with
1651
- * @param filter Optional filter to filter which boxes' values are returned
1652
- * @returns The (name, value) pair of the boxes with values as the ABI Value
1653
- */
1654
- async getBoxValuesFromABIType(type, filter) {
1655
- const appRef = await this.getAppReference();
1656
- if (appRef.appId === 0) {
1657
- throw new Error('No app has been created yet, unable to get global state');
1658
- }
1659
- const names = await this.getBoxNames();
1660
- return await Promise.all(names.filter(filter ?? ((_) => true)).map(async (boxName) => ({
1661
- name: boxName,
1662
- value: await app.getAppBoxValueFromABIType({ appId: appRef.appId, boxName, type }, this.algod),
1663
- })));
1664
- }
1665
- /**
1666
- * @deprecated Use `appClient.params.*` from an `AppClient` instance instead.
1667
- *
1668
- * Returns the arguments for an app call for the given ABI method or raw method specification.
1669
- * @param args The call args specific to this application client
1670
- * @param sender The sender of this call. Will be used to fetch any default argument values if applicable
1671
- * @returns The call args ready to pass into an app call
1672
- */
1673
- async getCallArgs(args, sender) {
1674
- if (!args) {
1675
- return undefined;
1676
- }
1677
- if (args.method) {
1678
- const abiMethod = this.getABIMethodParams(args.method);
1679
- if (!abiMethod) {
1680
- throw new Error(`Attempt to call ABI method ${args.method}, but it wasn't found`);
1681
- }
1682
- const methodSignature = this.getABIMethodSignature(abiMethod);
1683
- return {
1684
- ...args,
1685
- method: abiMethod,
1686
- methodArgs: await Promise.all(args.methodArgs.map(async (arg, index) => {
1687
- if (arg !== undefined)
1688
- return arg;
1689
- const argName = abiMethod.args[index].name;
1690
- const defaultValueStrategy = argName && this.appSpec.hints?.[methodSignature]?.default_arguments?.[argName];
1691
- if (!defaultValueStrategy)
1692
- throw new Error(`Argument at position ${index} with the name ${argName} is undefined and does not have a default value strategy`);
1693
- switch (defaultValueStrategy.source) {
1694
- case 'constant':
1695
- return defaultValueStrategy.data;
1696
- case 'abi-method': {
1697
- const method = defaultValueStrategy.data;
1698
- const result = await this.callOfType({
1699
- method: this.getABIMethodSignature(method),
1700
- methodArgs: method.args.map(() => undefined),
1701
- sender,
1702
- }, 'no_op');
1703
- return result.return?.returnValue;
1704
- }
1705
- case 'local-state':
1706
- case 'global-state': {
1707
- const state = defaultValueStrategy.source === 'global-state' ? await this.getGlobalState() : await this.getLocalState(sender);
1708
- const key = defaultValueStrategy.data;
1709
- if (key in state) {
1710
- return state[key].value;
1711
- }
1712
- else {
1713
- throw new Error(`Preparing default value for argument at position ${index} with the name ${argName} resulted in the failure: The key '${key}' could not be found in ${defaultValueStrategy.source}`);
1714
- }
1715
- }
1716
- }
1717
- })),
1718
- };
1719
- }
1720
- else {
1721
- return args;
1722
- }
1723
- }
1724
- /**
1725
- * @deprecated Use `appClient.getABIMethod` instead.
1726
- *
1727
- * Returns the ABI Method parameters for the given method name string for the app represented by this application client instance
1728
- * @param method Either the name of the method or the ABI method spec definition string
1729
- * @returns The ABI method params for the given method
1730
- */
1731
- getABIMethodParams(method) {
1732
- if (!method.includes('(')) {
1733
- const methods = this.appSpec.contract.methods.filter((m) => m.name === method);
1734
- if (methods.length > 1) {
1735
- throw new Error(`Received a call to method ${method} in contract ${this._appName}, but this resolved to multiple methods; please pass in an ABI signature instead: ${methods
1736
- .map(this.getABIMethodSignature)
1737
- .join(', ')}`);
1738
- }
1739
- return methods[0];
1740
- }
1741
- return this.appSpec.contract.methods.find((m) => this.getABIMethodSignature(m) === method);
1742
- }
1743
- /**
1744
- * Returns the ABI Method for the given method name string for the app represented by this application client instance
1745
- * @param method Either the name of the method or the ABI method spec definition string
1746
- * @returns The ABI method for the given method
1747
- */
1748
- getABIMethod(method) {
1749
- const methodParams = this.getABIMethodParams(method);
1750
- return methodParams ? new ABIMethod(methodParams) : undefined;
1751
- }
1752
- /**
1753
- * @deprecated Use `appClient.appId` and `appClient.appAddress` from an `AppClient` instance instead.
1754
- *
1755
- * Gets the reference information for the current application instance.
1756
- * `appId` will be 0 if it can't find an app.
1757
- * @returns The app reference, or if deployed using the `deploy` method, the app metadata too
1758
- */
1759
- async getAppReference() {
1760
- if (!this.existingDeployments && this._creator) {
1761
- this.existingDeployments = await appDeploy.getCreatorAppsByName(this._creator, this.indexer);
1762
- }
1763
- if (this.existingDeployments && this._appId === 0) {
1764
- const app = this.existingDeployments.apps[this._appName];
1765
- if (!app) {
1766
- return {
1767
- appId: 0,
1768
- appAddress: getApplicationAddress(0).toString(),
1769
- };
1770
- }
1771
- return app;
1772
- }
1773
- return {
1774
- appId: this._appId,
1775
- appAddress: this._appAddress,
1776
- };
1777
- }
1778
- /**
1779
- * Takes an error that may include a logic error from a smart contract call and re-exposes the error to include source code information via the source map.
1780
- * This is automatically used within `ApplicationClient` but if you pass `skipSending: true` e.g. if doing a group transaction
1781
- * then you can use this in a try/catch block to get better debugging information.
1782
- * @param e The error to parse
1783
- * @param isClear Whether or not the code was running the clear state program
1784
- * @returns The new error, or if there was no logic error or source map then the wrapped error with source details
1785
- */
1786
- exposeLogicError(e, isClear) {
1787
- if ((!isClear && this._approvalSourceMap == undefined) || (isClear && this._clearSourceMap == undefined))
1788
- return e;
1789
- const errorDetails = types_logicError.LogicError.parseLogicError(e);
1790
- if (errorDetails !== undefined)
1791
- return new types_logicError.LogicError(errorDetails, buffer.Buffer.from(isClear ? this.appSpec.source.clear : this.appSpec.source.approval, 'base64')
1792
- .toString()
1793
- .split('\n'), (pc) => (isClear ? this._clearSourceMap : this._approvalSourceMap)?.getLocationForPc(pc)?.line);
1794
- else
1795
- return e;
1796
- }
1797
- getABIMethodSignature(method) {
1798
- return 'getSignature' in method ? method.getSignature() : new ABIMethod(method).getSignature();
1799
- }
1800
- }
1801
-
1081
+ * @deprecated Use `AppClient` instead e.g. via `algorand.client.getAppClientById` or
1082
+ * `algorand.client.getAppClientByCreatorAndName`.
1083
+ * If you want to `create` or `deploy` then use `AppFactory` e.g. via `algorand.client.getAppFactory`,
1084
+ * which will in turn give you an `AppClient` instance against the created/deployed app to make other calls.
1085
+ *
1086
+ * Application client - a class that wraps an ARC-0032 app spec and provides high productivity methods to deploy and call the app */
1087
+ var ApplicationClient = class {
1088
+ algod;
1089
+ indexer;
1090
+ appSpec;
1091
+ sender;
1092
+ params;
1093
+ existingDeployments;
1094
+ deployTimeParams;
1095
+ _appId;
1096
+ _appAddress;
1097
+ _creator;
1098
+ _appName;
1099
+ _approvalSourceMap;
1100
+ _clearSourceMap;
1101
+ /**
1102
+ * @deprecated Use `AppClient` instead e.g. via `algorand.client.getAppClientById` or
1103
+ * `algorand.client.getAppClientByCreatorAndName`.
1104
+ * If you want to `create` or `deploy` then use `AppFactory` e.g. via `algorand.client.getAppFactory`,
1105
+ * which will in turn give you an `AppClient` instance against the created/deployed app to make other calls.
1106
+ *
1107
+ * Create a new ApplicationClient instance
1108
+ * @param appDetails The details of the app
1109
+ * @param algod An algod instance
1110
+ */
1111
+ constructor(appDetails, algod) {
1112
+ const { app, sender, params, deployTimeParams, ...appIdentifier } = appDetails;
1113
+ this.algod = algod;
1114
+ this.appSpec = typeof app == "string" ? JSON.parse(app) : app;
1115
+ this._appName = appIdentifier.name ?? this.appSpec.contract.name;
1116
+ this.deployTimeParams = deployTimeParams;
1117
+ if (appIdentifier.resolveBy === "id") {
1118
+ if (appIdentifier.id < 0) throw new Error(`Attempt to create application client with invalid app id of ${appIdentifier.id}`);
1119
+ this._appId = appIdentifier.id;
1120
+ } else {
1121
+ this._appId = 0;
1122
+ this._creator = appIdentifier.creatorAddress?.toString();
1123
+ if (appIdentifier.findExistingUsing instanceof Indexer) this.indexer = appIdentifier.findExistingUsing;
1124
+ else {
1125
+ if (appIdentifier.findExistingUsing.creator !== this._creator) throw new Error(`Attempt to create application client with invalid existingDeployments against a different creator (${appIdentifier.findExistingUsing.creator}) instead of expected creator ${this._creator}`);
1126
+ this.existingDeployments = appIdentifier.findExistingUsing;
1127
+ }
1128
+ }
1129
+ this._appAddress = algosdk.default.getApplicationAddress(this._appId).toString();
1130
+ this.sender = sender;
1131
+ this.params = params;
1132
+ }
1133
+ /**
1134
+ * @deprecated Use `AppClient.compile()` instead.
1135
+ *
1136
+ * Compiles the approval and clear state programs and sets up the source map.
1137
+ * @param compilation The deploy-time parameters for the compilation
1138
+ * @returns The compiled approval and clear state programs
1139
+ */
1140
+ async compile(compilation) {
1141
+ const { deployTimeParams, updatable, deletable } = compilation ?? {};
1142
+ const approvalCompiled = await require_app$1.compileTeal(require_app_deploy.replaceDeployTimeControlParams(require_app_deploy.performTemplateSubstitution(buffer.Buffer.from(this.appSpec.source.approval, "base64").toString("utf-8"), deployTimeParams ?? this.deployTimeParams), {
1143
+ updatable,
1144
+ deletable
1145
+ }), this.algod);
1146
+ this._approvalSourceMap = approvalCompiled?.sourceMap;
1147
+ const clearCompiled = await require_app$1.compileTeal(require_app_deploy.performTemplateSubstitution(buffer.Buffer.from(this.appSpec.source.clear, "base64").toString("utf-8"), deployTimeParams ?? this.deployTimeParams), this.algod);
1148
+ this._clearSourceMap = clearCompiled?.sourceMap;
1149
+ if (require_config.Config.debug) await require_config.Config.events.emitAsync("AppCompiled", { sources: [{
1150
+ compiledTeal: approvalCompiled,
1151
+ appName: this._appName,
1152
+ fileName: "approval"
1153
+ }, {
1154
+ compiledTeal: clearCompiled,
1155
+ appName: this._appName,
1156
+ fileName: "clear"
1157
+ }] });
1158
+ return {
1159
+ approvalCompiled,
1160
+ clearCompiled
1161
+ };
1162
+ }
1163
+ /**
1164
+ * Export the current source maps for the app.
1165
+ * @returns The source maps
1166
+ */
1167
+ exportSourceMaps() {
1168
+ if (!this._approvalSourceMap || !this._clearSourceMap) throw new Error("Unable to export source maps; they haven't been loaded into this client - you need to call create, update, or deploy first");
1169
+ return {
1170
+ approvalSourceMap: this._approvalSourceMap,
1171
+ clearSourceMap: this._clearSourceMap
1172
+ };
1173
+ }
1174
+ /**
1175
+ * Import source maps for the app.
1176
+ * @param sourceMaps The source maps to import
1177
+ */
1178
+ importSourceMaps(sourceMaps) {
1179
+ this._approvalSourceMap = new SourceMap(sourceMaps.approvalSourceMap);
1180
+ this._clearSourceMap = new SourceMap(sourceMaps.clearSourceMap);
1181
+ }
1182
+ /**
1183
+ * @deprecated Use `deploy` from an `AppFactory` instance instead.
1184
+ *
1185
+ * Idempotently deploy (create, update/delete if changed) an app against the given name via the given creator account, including deploy-time template placeholder substitutions.
1186
+ *
1187
+ * To understand the architecture decisions behind this functionality please see https://github.com/algorandfoundation/algokit-cli/blob/main/docs/src/content/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md
1188
+ *
1189
+ * **Note:** if there is a breaking state schema change to an existing app (and `onSchemaBreak` is set to `'replace'`) the existing app will be deleted and re-created.
1190
+ *
1191
+ * **Note:** if there is an update (different TEAL code) to an existing app (and `onUpdate` is set to `'replace'`) the existing app will be deleted and re-created.
1192
+ * @param deploy Deployment details
1193
+ * @returns The metadata and transaction result(s) of the deployment, or just the metadata if it didn't need to issue transactions
1194
+ */
1195
+ async deploy(deploy) {
1196
+ const { schema, sender: deploySender, version, allowUpdate, allowDelete, sendParams, createArgs, createOnCompleteAction, updateArgs, deleteArgs, ...deployArgs } = deploy ?? {};
1197
+ if (this._appId !== 0) throw new Error(`Attempt to deploy app which already has an app id of ${this._appId}`);
1198
+ const sender = deploySender ?? this.sender;
1199
+ if (!sender) throw new Error("No sender provided, unable to deploy app");
1200
+ const from = sender ?? this.sender;
1201
+ if (!this._creator) throw new Error("Attempt to `deploy` a contract without specifying `resolveBy: 'creatorAndName'` in the constructor");
1202
+ if (this._creator !== require_transaction.getSenderAddress(from)) throw new Error(`Attempt to deploy contract with a sender address (${require_transaction.getSenderAddress(from)}) that differs from the given creator address for this application client: ${this._creator}`);
1203
+ const approval = buffer.Buffer.from(this.appSpec.source.approval, "base64").toString("utf-8");
1204
+ const compilation = {
1205
+ deployTimeParams: deployArgs.deployTimeParams,
1206
+ updatable: allowUpdate !== void 0 ? allowUpdate : getDeployTimeControl(approval, this.appSpec, require_app.UPDATABLE_TEMPLATE_NAME, "update_application"),
1207
+ deletable: allowDelete !== void 0 ? allowDelete : getDeployTimeControl(approval, this.appSpec, require_app.DELETABLE_TEMPLATE_NAME, "delete_application")
1208
+ };
1209
+ const { approvalCompiled, clearCompiled } = await this.compile(compilation);
1210
+ try {
1211
+ await this.getAppReference();
1212
+ const result = await require_app_deploy.deployApp({
1213
+ from: sender,
1214
+ approvalProgram: approvalCompiled.compiledBase64ToBytes,
1215
+ clearStateProgram: clearCompiled.compiledBase64ToBytes,
1216
+ metadata: {
1217
+ name: this._appName,
1218
+ version: version ?? "1.0",
1219
+ updatable: compilation.updatable,
1220
+ deletable: compilation.deletable
1221
+ },
1222
+ schema: {
1223
+ globalByteSlices: this.appSpec.state.global.num_byte_slices,
1224
+ globalInts: this.appSpec.state.global.num_uints,
1225
+ localByteSlices: this.appSpec.state.local.num_byte_slices,
1226
+ localInts: this.appSpec.state.local.num_uints,
1227
+ ...schema
1228
+ },
1229
+ transactionParams: this.params,
1230
+ ...sendParams ?? {},
1231
+ existingDeployments: this.existingDeployments,
1232
+ createArgs: await this.getCallArgs(createArgs, sender),
1233
+ createOnCompleteAction,
1234
+ updateArgs: await this.getCallArgs(updateArgs, sender),
1235
+ deleteArgs: await this.getCallArgs(deleteArgs, sender),
1236
+ ...deployArgs
1237
+ }, this.algod, this.indexer);
1238
+ if (result.operationPerformed === "nothing") return result;
1239
+ if (!this.existingDeployments) throw new Error("Expected existingDeployments to be present");
1240
+ const { transaction, confirmation, operationPerformed, ...appMetadata } = result;
1241
+ this.existingDeployments = {
1242
+ creator: this.existingDeployments.creator,
1243
+ apps: {
1244
+ ...this.existingDeployments.apps,
1245
+ [this._appName]: appMetadata
1246
+ }
1247
+ };
1248
+ return {
1249
+ ...result,
1250
+ compiledApproval: approvalCompiled,
1251
+ compiledClear: clearCompiled
1252
+ };
1253
+ } catch (e) {
1254
+ throw this.exposeLogicError(e);
1255
+ }
1256
+ }
1257
+ /**
1258
+ * @deprecated Use `create` from an `AppFactory` instance instead.
1259
+ *
1260
+ * Creates a smart contract app, returns the details of the created app.
1261
+ * @param create The parameters to create the app with
1262
+ * @returns The details of the created app, or the transaction to create it if `skipSending` and the compilation result
1263
+ */
1264
+ async create(create) {
1265
+ const { sender: createSender, note, sendParams, deployTimeParams, updatable, deletable, onCompleteAction, schema, ...args } = create ?? {};
1266
+ if (this._appId !== 0) throw new Error(`Attempt to create app which already has an app id of ${this._appId}`);
1267
+ const sender = createSender ?? this.sender;
1268
+ if (!sender) throw new Error("No sender provided, unable to create app");
1269
+ const { approvalCompiled, clearCompiled } = await this.compile(create);
1270
+ try {
1271
+ const result = await require_app$1.createApp({
1272
+ from: sender,
1273
+ approvalProgram: approvalCompiled.compiledBase64ToBytes,
1274
+ clearStateProgram: clearCompiled.compiledBase64ToBytes,
1275
+ schema: {
1276
+ globalByteSlices: this.appSpec.state.global.num_byte_slices,
1277
+ globalInts: this.appSpec.state.global.num_uints,
1278
+ localByteSlices: this.appSpec.state.local.num_byte_slices,
1279
+ localInts: this.appSpec.state.local.num_uints,
1280
+ ...schema
1281
+ },
1282
+ onCompleteAction,
1283
+ args: await this.getCallArgs(args, sender),
1284
+ note,
1285
+ transactionParams: this.params,
1286
+ ...sendParams ?? {}
1287
+ }, this.algod);
1288
+ if (result.confirmation) {
1289
+ this._appId = result.confirmation.applicationIndex;
1290
+ this._appAddress = getApplicationAddress(this._appId).toString();
1291
+ }
1292
+ return {
1293
+ ...result,
1294
+ compiledApproval: approvalCompiled,
1295
+ compiledClear: clearCompiled
1296
+ };
1297
+ } catch (e) {
1298
+ throw await this.exposeLogicError(e);
1299
+ }
1300
+ }
1301
+ /**
1302
+ * @deprecated Use `appClient.send.update` or `appClient.createTransaction.update` from an `AppClient` instance instead.
1303
+ *
1304
+ * Updates the smart contract app.
1305
+ * @param update The parameters to update the app with
1306
+ * @returns The transaction send result and the compilation result
1307
+ */
1308
+ async update(update) {
1309
+ const { sender: updateSender, note, sendParams, deployTimeParams, updatable, deletable, ...args } = update ?? {};
1310
+ if (this._appId === 0) throw new Error(`Attempt to update app which doesn't have an app id defined`);
1311
+ const sender = updateSender ?? this.sender;
1312
+ if (!sender) throw new Error("No sender provided, unable to create app");
1313
+ const { approvalCompiled, clearCompiled } = await this.compile(update);
1314
+ try {
1315
+ return {
1316
+ ...await require_app$1.updateApp({
1317
+ appId: this._appId,
1318
+ from: sender,
1319
+ approvalProgram: approvalCompiled.compiledBase64ToBytes,
1320
+ clearStateProgram: clearCompiled.compiledBase64ToBytes,
1321
+ args: await this.getCallArgs(args, sender),
1322
+ note,
1323
+ transactionParams: this.params,
1324
+ ...sendParams ?? {}
1325
+ }, this.algod),
1326
+ compiledApproval: approvalCompiled,
1327
+ compiledClear: clearCompiled
1328
+ };
1329
+ } catch (e) {
1330
+ throw await this.exposeLogicError(e);
1331
+ }
1332
+ }
1333
+ /**
1334
+ * @deprecated Use `appClient.send.call` or `appClient.createTransaction.call` from an `AppClient` instance instead.
1335
+ *
1336
+ * Issues a no_op (normal) call to the app.
1337
+ * @param call The call details.
1338
+ * @returns The result of the call
1339
+ */
1340
+ async call(call) {
1341
+ if (call?.method && !call.sendParams?.skipSending && !call.sendParams?.atc && this.appSpec.hints[this.getABIMethodSignature(this.getABIMethod(call.method))].read_only) {
1342
+ const atc = new AtomicTransactionComposer();
1343
+ await this.callOfType({
1344
+ ...call,
1345
+ sendParams: {
1346
+ ...call.sendParams,
1347
+ atc
1348
+ }
1349
+ }, "no_op");
1350
+ const result = await atc.simulate(this.algod);
1351
+ if (result.simulateResponse.txnGroups.some((group) => group.failureMessage)) throw new Error(result.simulateResponse.txnGroups.find((x) => x.failureMessage)?.failureMessage);
1352
+ const txns = atc.buildGroup();
1353
+ return {
1354
+ transaction: txns[txns.length - 1].txn,
1355
+ confirmation: result.simulateResponse.txnGroups[0].txnResults.at(-1)?.txnResult,
1356
+ confirmations: result.simulateResponse.txnGroups[0].txnResults.map((t) => t.txnResult),
1357
+ transactions: txns.map((t) => t.txn),
1358
+ return: result.methodResults?.length ?? false ? result.methodResults[result.methodResults.length - 1] : void 0
1359
+ };
1360
+ }
1361
+ return await this.callOfType(call, "no_op");
1362
+ }
1363
+ /**
1364
+ * @deprecated Use `appClient.send.optIn` or `appClient.createTransaction.optIn` from an `AppClient` instance instead.
1365
+ *
1366
+ * Issues a opt_in call to the app.
1367
+ * @param call The call details.
1368
+ * @returns The result of the call
1369
+ */
1370
+ async optIn(call) {
1371
+ return await this.callOfType(call, "opt_in");
1372
+ }
1373
+ /**
1374
+ * @deprecated Use `appClient.send.closeOut` or `appClient.createTransaction.closeOut` from an `AppClient` instance instead.
1375
+ *
1376
+ * Issues a close_out call to the app.
1377
+ * @param call The call details.
1378
+ * @returns The result of the call
1379
+ */
1380
+ async closeOut(call) {
1381
+ return await this.callOfType(call, "close_out");
1382
+ }
1383
+ /**
1384
+ * @deprecated Use `appClient.send.clearState` or `appClient.createTransaction.clearState` from an `AppClient` instance instead.
1385
+ *
1386
+ * Issues a clear_state call to the app.
1387
+ * @param call The call details.
1388
+ * @returns The result of the call
1389
+ */
1390
+ async clearState(call) {
1391
+ return await this.callOfType(call, "clear_state");
1392
+ }
1393
+ /**
1394
+ * @deprecated Use `appClient.send.delete` or `appClient.createTransaction.delete` from an `AppClient` instance instead.
1395
+ *
1396
+ * Issues a delete_application call to the app.
1397
+ * @param call The call details.
1398
+ * @returns The result of the call
1399
+ */
1400
+ async delete(call) {
1401
+ return await this.callOfType(call, "delete_application");
1402
+ }
1403
+ /**
1404
+ * @deprecated Use `appClient.send.call` or `appClient.createTransaction.call` from an `AppClient` instance instead.
1405
+ *
1406
+ * Issues a call to the app with the given call type.
1407
+ * @param call The call details.
1408
+ * @param callType The call type
1409
+ * @returns The result of the call
1410
+ */
1411
+ async callOfType(call = {}, callType) {
1412
+ const { sender: callSender, note, sendParams, ...args } = call;
1413
+ const sender = callSender ?? this.sender;
1414
+ if (!sender) throw new Error("No sender provided, unable to call app");
1415
+ const appMetadata = await this.getAppReference();
1416
+ if (appMetadata.appId === 0) throw new Error(`Attempt to call an app that can't be found '${this._appName}' for creator '${this._creator}'.`);
1417
+ try {
1418
+ return await require_app$1.callApp({
1419
+ appId: appMetadata.appId,
1420
+ callType,
1421
+ from: sender,
1422
+ args: await this.getCallArgs(args, sender),
1423
+ note,
1424
+ transactionParams: this.params,
1425
+ ...sendParams ?? {}
1426
+ }, this.algod);
1427
+ } catch (e) {
1428
+ throw this.exposeLogicError(e);
1429
+ }
1430
+ }
1431
+ /**
1432
+ * Funds Algo into the app account for this app.
1433
+ * @param fund The parameters for the funding or the funding amount
1434
+ * @returns The result of the funding
1435
+ */
1436
+ async fundAppAccount(fund) {
1437
+ const { amount, sender, note, sendParams } = "microAlgos" in fund ? { amount: fund } : fund;
1438
+ if (!sender && !this.sender) throw new Error("No sender provided, unable to call app");
1439
+ const ref = await this.getAppReference();
1440
+ return require_legacy_bridge.legacySendTransactionBridge(this.algod, sender ?? this.sender, sendParams ?? {}, {
1441
+ receiver: ref.appAddress,
1442
+ sender: require_transaction.getSenderAddress(sender ?? this.sender),
1443
+ amount,
1444
+ note: require_transaction.encodeTransactionNote(note)
1445
+ }, (c) => c.payment, (c) => c.payment, this.params);
1446
+ }
1447
+ /**
1448
+ * Returns global state for the current app.
1449
+ * @returns The global state
1450
+ */
1451
+ async getGlobalState() {
1452
+ const appRef = await this.getAppReference();
1453
+ if (appRef.appId === 0) throw new Error("No app has been created yet, unable to get global state");
1454
+ return require_app$1.getAppGlobalState(appRef.appId, this.algod);
1455
+ }
1456
+ /**
1457
+ * Returns local state for the given account / account address.
1458
+ * @returns The global state
1459
+ */
1460
+ async getLocalState(account) {
1461
+ const appRef = await this.getAppReference();
1462
+ if (appRef.appId === 0) throw new Error("No app has been created yet, unable to get global state");
1463
+ return require_app$1.getAppLocalState(appRef.appId, account, this.algod);
1464
+ }
1465
+ /**
1466
+ * Returns the names of all current boxes for the current app.
1467
+ * @returns The names of the boxes
1468
+ */
1469
+ async getBoxNames() {
1470
+ const appRef = await this.getAppReference();
1471
+ if (appRef.appId === 0) throw new Error("No app has been created yet, unable to get global state");
1472
+ return await require_app$1.getAppBoxNames(appRef.appId, this.algod);
1473
+ }
1474
+ /**
1475
+ * Returns the value of the given box for the current app.
1476
+ * @param name The name of the box to return either as a string, binary array or `BoxName`
1477
+ * @returns The current box value as a byte array
1478
+ */
1479
+ async getBoxValue(name) {
1480
+ const appRef = await this.getAppReference();
1481
+ if (appRef.appId === 0) throw new Error("No app has been created yet, unable to get global state");
1482
+ return await require_app$1.getAppBoxValue(appRef.appId, name, this.algod);
1483
+ }
1484
+ /**
1485
+ * Returns the value of the given box for the current app.
1486
+ * @param name The name of the box to return either as a string, binary array or `BoxName`
1487
+ * @param type
1488
+ * @returns The current box value as a byte array
1489
+ */
1490
+ async getBoxValueFromABIType(name, type) {
1491
+ const appRef = await this.getAppReference();
1492
+ if (appRef.appId === 0) throw new Error("No app has been created yet, unable to get global state");
1493
+ return await require_app$1.getAppBoxValueFromABIType({
1494
+ appId: appRef.appId,
1495
+ boxName: name,
1496
+ type
1497
+ }, this.algod);
1498
+ }
1499
+ /**
1500
+ * Returns the values of all current boxes for the current app.
1501
+ * Note: This will issue multiple HTTP requests (one per box) and it's not an atomic operation so values may be out of sync.
1502
+ * @param filter Optional filter to filter which boxes' values are returned
1503
+ * @returns The (name, value) pair of the boxes with values as raw byte arrays
1504
+ */
1505
+ async getBoxValues(filter) {
1506
+ const appRef = await this.getAppReference();
1507
+ if (appRef.appId === 0) throw new Error("No app has been created yet, unable to get global state");
1508
+ const names = await this.getBoxNames();
1509
+ return await Promise.all(names.filter(filter ?? ((_) => true)).map(async (boxName) => ({
1510
+ name: boxName,
1511
+ value: await require_app$1.getAppBoxValue(appRef.appId, boxName, this.algod)
1512
+ })));
1513
+ }
1514
+ /**
1515
+ * Returns the values of all current boxes for the current app decoded using an ABI Type.
1516
+ * Note: This will issue multiple HTTP requests (one per box) and it's not an atomic operation so values may be out of sync.
1517
+ * @param type The ABI type to decode the values with
1518
+ * @param filter Optional filter to filter which boxes' values are returned
1519
+ * @returns The (name, value) pair of the boxes with values as the ABI Value
1520
+ */
1521
+ async getBoxValuesFromABIType(type, filter) {
1522
+ const appRef = await this.getAppReference();
1523
+ if (appRef.appId === 0) throw new Error("No app has been created yet, unable to get global state");
1524
+ const names = await this.getBoxNames();
1525
+ return await Promise.all(names.filter(filter ?? ((_) => true)).map(async (boxName) => ({
1526
+ name: boxName,
1527
+ value: await require_app$1.getAppBoxValueFromABIType({
1528
+ appId: appRef.appId,
1529
+ boxName,
1530
+ type
1531
+ }, this.algod)
1532
+ })));
1533
+ }
1534
+ /**
1535
+ * @deprecated Use `appClient.params.*` from an `AppClient` instance instead.
1536
+ *
1537
+ * Returns the arguments for an app call for the given ABI method or raw method specification.
1538
+ * @param args The call args specific to this application client
1539
+ * @param sender The sender of this call. Will be used to fetch any default argument values if applicable
1540
+ * @returns The call args ready to pass into an app call
1541
+ */
1542
+ async getCallArgs(args, sender) {
1543
+ if (!args) return;
1544
+ if (args.method) {
1545
+ const abiMethod = this.getABIMethodParams(args.method);
1546
+ if (!abiMethod) throw new Error(`Attempt to call ABI method ${args.method}, but it wasn't found`);
1547
+ const methodSignature = this.getABIMethodSignature(abiMethod);
1548
+ return {
1549
+ ...args,
1550
+ method: abiMethod,
1551
+ methodArgs: await Promise.all(args.methodArgs.map(async (arg, index) => {
1552
+ if (arg !== void 0) return arg;
1553
+ const argName = abiMethod.args[index].name;
1554
+ const defaultValueStrategy = argName && this.appSpec.hints?.[methodSignature]?.default_arguments?.[argName];
1555
+ if (!defaultValueStrategy) throw new Error(`Argument at position ${index} with the name ${argName} is undefined and does not have a default value strategy`);
1556
+ switch (defaultValueStrategy.source) {
1557
+ case "constant": return defaultValueStrategy.data;
1558
+ case "abi-method": {
1559
+ const method = defaultValueStrategy.data;
1560
+ return (await this.callOfType({
1561
+ method: this.getABIMethodSignature(method),
1562
+ methodArgs: method.args.map(() => void 0),
1563
+ sender
1564
+ }, "no_op")).return?.returnValue;
1565
+ }
1566
+ case "local-state":
1567
+ case "global-state": {
1568
+ const state = defaultValueStrategy.source === "global-state" ? await this.getGlobalState() : await this.getLocalState(sender);
1569
+ const key = defaultValueStrategy.data;
1570
+ if (key in state) return state[key].value;
1571
+ else throw new Error(`Preparing default value for argument at position ${index} with the name ${argName} resulted in the failure: The key '${key}' could not be found in ${defaultValueStrategy.source}`);
1572
+ }
1573
+ }
1574
+ }))
1575
+ };
1576
+ } else return args;
1577
+ }
1578
+ /**
1579
+ * @deprecated Use `appClient.getABIMethod` instead.
1580
+ *
1581
+ * Returns the ABI Method parameters for the given method name string for the app represented by this application client instance
1582
+ * @param method Either the name of the method or the ABI method spec definition string
1583
+ * @returns The ABI method params for the given method
1584
+ */
1585
+ getABIMethodParams(method) {
1586
+ if (!method.includes("(")) {
1587
+ const methods = this.appSpec.contract.methods.filter((m) => m.name === method);
1588
+ if (methods.length > 1) throw new Error(`Received a call to method ${method} in contract ${this._appName}, but this resolved to multiple methods; please pass in an ABI signature instead: ${methods.map(this.getABIMethodSignature).join(", ")}`);
1589
+ return methods[0];
1590
+ }
1591
+ return this.appSpec.contract.methods.find((m) => this.getABIMethodSignature(m) === method);
1592
+ }
1593
+ /**
1594
+ * Returns the ABI Method for the given method name string for the app represented by this application client instance
1595
+ * @param method Either the name of the method or the ABI method spec definition string
1596
+ * @returns The ABI method for the given method
1597
+ */
1598
+ getABIMethod(method) {
1599
+ const methodParams = this.getABIMethodParams(method);
1600
+ return methodParams ? new ABIMethod(methodParams) : void 0;
1601
+ }
1602
+ /**
1603
+ * @deprecated Use `appClient.appId` and `appClient.appAddress` from an `AppClient` instance instead.
1604
+ *
1605
+ * Gets the reference information for the current application instance.
1606
+ * `appId` will be 0 if it can't find an app.
1607
+ * @returns The app reference, or if deployed using the `deploy` method, the app metadata too
1608
+ */
1609
+ async getAppReference() {
1610
+ if (!this.existingDeployments && this._creator) this.existingDeployments = await require_app_deploy.getCreatorAppsByName(this._creator, this.indexer);
1611
+ if (this.existingDeployments && this._appId === 0) {
1612
+ const app = this.existingDeployments.apps[this._appName];
1613
+ if (!app) return {
1614
+ appId: 0,
1615
+ appAddress: getApplicationAddress(0).toString()
1616
+ };
1617
+ return app;
1618
+ }
1619
+ return {
1620
+ appId: this._appId,
1621
+ appAddress: this._appAddress
1622
+ };
1623
+ }
1624
+ /**
1625
+ * Takes an error that may include a logic error from a smart contract call and re-exposes the error to include source code information via the source map.
1626
+ * This is automatically used within `ApplicationClient` but if you pass `skipSending: true` e.g. if doing a group transaction
1627
+ * then you can use this in a try/catch block to get better debugging information.
1628
+ * @param e The error to parse
1629
+ * @param isClear Whether or not the code was running the clear state program
1630
+ * @returns The new error, or if there was no logic error or source map then the wrapped error with source details
1631
+ */
1632
+ exposeLogicError(e, isClear) {
1633
+ if (!isClear && this._approvalSourceMap == void 0 || isClear && this._clearSourceMap == void 0) return e;
1634
+ const errorDetails = require_logic_error.LogicError.parseLogicError(e);
1635
+ if (errorDetails !== void 0) return new require_logic_error.LogicError(errorDetails, buffer.Buffer.from(isClear ? this.appSpec.source.clear : this.appSpec.source.approval, "base64").toString().split("\n"), (pc) => (isClear ? this._clearSourceMap : this._approvalSourceMap)?.getLocationForPc(pc)?.line);
1636
+ else return e;
1637
+ }
1638
+ getABIMethodSignature(method) {
1639
+ return "getSignature" in method ? method.getSignature() : new ABIMethod(method).getSignature();
1640
+ }
1641
+ };
1642
+ //#endregion
1802
1643
  exports.AppClient = AppClient;
1803
1644
  exports.ApplicationClient = ApplicationClient;
1804
- //# sourceMappingURL=app-client.js.map
1645
+
1646
+ //# sourceMappingURL=app-client.js.map