algokit-utils 5.0.0a3__py3-none-any.whl

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 (337) hide show
  1. algokit_abi/__init__.py +9 -0
  2. algokit_abi/_arc32_to_arc56.py +242 -0
  3. algokit_abi/_arc56_serde.py +161 -0
  4. algokit_abi/abi.py +667 -0
  5. algokit_abi/arc32.py +210 -0
  6. algokit_abi/arc56.py +821 -0
  7. algokit_abi/py.typed +0 -0
  8. algokit_algo25/__init__.py +38 -0
  9. algokit_algo25/_encoding.py +46 -0
  10. algokit_algo25/_wordlist.py +2065 -0
  11. algokit_algo25/exceptions.py +29 -0
  12. algokit_algo25/mnemonic.py +128 -0
  13. algokit_algo25/py.typed +0 -0
  14. algokit_algod_client/__init__.py +10 -0
  15. algokit_algod_client/client.py +1585 -0
  16. algokit_algod_client/config.py +36 -0
  17. algokit_algod_client/exceptions.py +59 -0
  18. algokit_algod_client/models/__init__.py +229 -0
  19. algokit_algod_client/models/_account.py +150 -0
  20. algokit_algod_client/models/_account_application_response.py +25 -0
  21. algokit_algod_client/models/_account_asset_response.py +25 -0
  22. algokit_algod_client/models/_account_participation.py +53 -0
  23. algokit_algod_client/models/_account_state_delta.py +30 -0
  24. algokit_algod_client/models/_allocations_for_genesis_file.py +23 -0
  25. algokit_algod_client/models/_allocations_for_genesis_file_state_model.py +42 -0
  26. algokit_algod_client/models/_application.py +23 -0
  27. algokit_algod_client/models/_application_initial_states.py +37 -0
  28. algokit_algod_client/models/_application_kvstorage.py +29 -0
  29. algokit_algod_client/models/_application_local_state.py +33 -0
  30. algokit_algod_client/models/_application_params.py +63 -0
  31. algokit_algod_client/models/_application_state_operation.py +41 -0
  32. algokit_algod_client/models/_application_state_schema.py +22 -0
  33. algokit_algod_client/models/_asset.py +23 -0
  34. algokit_algod_client/models/_asset_holding.py +29 -0
  35. algokit_algod_client/models/_asset_params.py +102 -0
  36. algokit_algod_client/models/_avm_key_value.py +28 -0
  37. algokit_algod_client/models/_avm_value.py +32 -0
  38. algokit_algod_client/models/_block.py +363 -0
  39. algokit_algod_client/models/_block_hash_response.py +14 -0
  40. algokit_algod_client/models/_block_txids_response.py +14 -0
  41. algokit_algod_client/models/_box.py +36 -0
  42. algokit_algod_client/models/_box_descriptor.py +24 -0
  43. algokit_algod_client/models/_boxes_response.py +21 -0
  44. algokit_algod_client/models/_build_version_contains_the_current_algod_build_version_information.py +34 -0
  45. algokit_algod_client/models/_compile_response.py +24 -0
  46. algokit_algod_client/models/_disassemble_response.py +14 -0
  47. algokit_algod_client/models/_error_response.py +22 -0
  48. algokit_algod_client/models/_eval_delta.py +32 -0
  49. algokit_algod_client/models/_eval_delta_key_value.py +28 -0
  50. algokit_algod_client/models/_genesis_file_in_json.py +53 -0
  51. algokit_algod_client/models/_get_block_time_stamp_offset_response.py +14 -0
  52. algokit_algod_client/models/_get_sync_round_response.py +14 -0
  53. algokit_algod_client/models/_ledger_state_delta.py +389 -0
  54. algokit_algod_client/models/_light_block_header_proof.py +32 -0
  55. algokit_algod_client/models/_node_status_response.py +118 -0
  56. algokit_algod_client/models/_pending_transaction_response.py +91 -0
  57. algokit_algod_client/models/_pending_transactions_response.py +29 -0
  58. algokit_algod_client/models/_post_transactions_response.py +14 -0
  59. algokit_algod_client/models/_scratch_change.py +23 -0
  60. algokit_algod_client/models/_serde_helpers.py +241 -0
  61. algokit_algod_client/models/_simulate_initial_states.py +25 -0
  62. algokit_algod_client/models/_simulate_request.py +54 -0
  63. algokit_algod_client/models/_simulate_request_transaction_group.py +25 -0
  64. algokit_algod_client/models/_simulate_response.py +44 -0
  65. algokit_algod_client/models/_simulate_trace_config.py +30 -0
  66. algokit_algod_client/models/_simulate_transaction_group_result.py +46 -0
  67. algokit_algod_client/models/_simulate_transaction_result.py +41 -0
  68. algokit_algod_client/models/_simulate_unnamed_resources_accessed.py +64 -0
  69. algokit_algod_client/models/_simulation_eval_overrides.py +40 -0
  70. algokit_algod_client/models/_simulation_opcode_trace_unit.py +55 -0
  71. algokit_algod_client/models/_simulation_transaction_exec_trace.py +82 -0
  72. algokit_algod_client/models/_source_map.py +30 -0
  73. algokit_algod_client/models/_state_delta.py +6 -0
  74. algokit_algod_client/models/_state_proof.py +28 -0
  75. algokit_algod_client/models/_state_proof_message.py +44 -0
  76. algokit_algod_client/models/_supply_response.py +26 -0
  77. algokit_algod_client/models/_teal_key_value.py +28 -0
  78. algokit_algod_client/models/_teal_key_value_store.py +6 -0
  79. algokit_algod_client/models/_teal_value.py +32 -0
  80. algokit_algod_client/models/_transaction_group_ledger_state_deltas_for_round_response.py +21 -0
  81. algokit_algod_client/models/_transaction_parameters_response.py +45 -0
  82. algokit_algod_client/models/_transaction_proof.py +44 -0
  83. algokit_algod_client/models/_version_contains_the_current_algod_version.py +38 -0
  84. algokit_algod_client/models/suggested_params.py +42 -0
  85. algokit_algod_client/py.typed +1 -0
  86. algokit_algod_client/types.py +7 -0
  87. algokit_algosdk/__init__.py +38 -0
  88. algokit_algosdk/account.py +32 -0
  89. algokit_algosdk/app_access.py +228 -0
  90. algokit_algosdk/box_reference.py +100 -0
  91. algokit_algosdk/constants.py +147 -0
  92. algokit_algosdk/encoding.py +89 -0
  93. algokit_algosdk/error.py +180 -0
  94. algokit_algosdk/logic.py +61 -0
  95. algokit_algosdk/logicsig.py +218 -0
  96. algokit_algosdk/mnemonic.py +216 -0
  97. algokit_algosdk/multisig.py +161 -0
  98. algokit_algosdk/py.typed +0 -0
  99. algokit_algosdk/transaction.py +596 -0
  100. algokit_algosdk/wordlist.py +2054 -0
  101. algokit_common/__init__.py +50 -0
  102. algokit_common/address.py +34 -0
  103. algokit_common/constants.py +47 -0
  104. algokit_common/hashing.py +25 -0
  105. algokit_common/py.typed +0 -0
  106. algokit_common/serde/__init__.py +40 -0
  107. algokit_common/serde/_core.py +610 -0
  108. algokit_common/serde/_primitives.py +135 -0
  109. algokit_common/source_map.py +158 -0
  110. algokit_indexer_client/__init__.py +10 -0
  111. algokit_indexer_client/client.py +1456 -0
  112. algokit_indexer_client/config.py +36 -0
  113. algokit_indexer_client/exceptions.py +59 -0
  114. algokit_indexer_client/models/__init__.py +148 -0
  115. algokit_indexer_client/models/_account.py +161 -0
  116. algokit_indexer_client/models/_account_participation.py +53 -0
  117. algokit_indexer_client/models/_account_response.py +19 -0
  118. algokit_indexer_client/models/_account_state_delta.py +29 -0
  119. algokit_indexer_client/models/_accounts_response.py +29 -0
  120. algokit_indexer_client/models/_application.py +35 -0
  121. algokit_indexer_client/models/_application_local_state.py +45 -0
  122. algokit_indexer_client/models/_application_local_states_response.py +29 -0
  123. algokit_indexer_client/models/_application_log_data.py +28 -0
  124. algokit_indexer_client/models/_application_logs_response.py +33 -0
  125. algokit_indexer_client/models/_application_params.py +62 -0
  126. algokit_indexer_client/models/_application_response.py +20 -0
  127. algokit_indexer_client/models/_application_state_schema.py +22 -0
  128. algokit_indexer_client/models/_applications_response.py +29 -0
  129. algokit_indexer_client/models/_asset.py +35 -0
  130. algokit_indexer_client/models/_asset_balances_response.py +29 -0
  131. algokit_indexer_client/models/_asset_holding.py +41 -0
  132. algokit_indexer_client/models/_asset_holdings_response.py +29 -0
  133. algokit_indexer_client/models/_asset_params.py +102 -0
  134. algokit_indexer_client/models/_asset_response.py +19 -0
  135. algokit_indexer_client/models/_assets_response.py +29 -0
  136. algokit_indexer_client/models/_block.py +150 -0
  137. algokit_indexer_client/models/_block_headers_response.py +29 -0
  138. algokit_indexer_client/models/_block_rewards.py +38 -0
  139. algokit_indexer_client/models/_block_upgrade_state.py +34 -0
  140. algokit_indexer_client/models/_block_upgrade_vote.py +26 -0
  141. algokit_indexer_client/models/_box.py +36 -0
  142. algokit_indexer_client/models/_box_descriptor.py +24 -0
  143. algokit_indexer_client/models/_box_reference.py +28 -0
  144. algokit_indexer_client/models/_boxes_response.py +29 -0
  145. algokit_indexer_client/models/_error_response.py +18 -0
  146. algokit_indexer_client/models/_eval_delta.py +32 -0
  147. algokit_indexer_client/models/_eval_delta_key_value.py +28 -0
  148. algokit_indexer_client/models/_hash_factory.py +14 -0
  149. algokit_indexer_client/models/_hb_proof_fields.py +57 -0
  150. algokit_indexer_client/models/_health_check.py +42 -0
  151. algokit_indexer_client/models/_holding_ref.py +23 -0
  152. algokit_indexer_client/models/_indexer_state_proof_message.py +40 -0
  153. algokit_indexer_client/models/_locals_ref.py +23 -0
  154. algokit_indexer_client/models/_merkle_array_proof.py +29 -0
  155. algokit_indexer_client/models/_mini_asset_holding.py +38 -0
  156. algokit_indexer_client/models/_on_completion.py +25 -0
  157. algokit_indexer_client/models/_participation_updates.py +22 -0
  158. algokit_indexer_client/models/_resource_ref.py +42 -0
  159. algokit_indexer_client/models/_serde_helpers.py +241 -0
  160. algokit_indexer_client/models/_state_delta.py +6 -0
  161. algokit_indexer_client/models/_state_proof_fields.py +57 -0
  162. algokit_indexer_client/models/_state_proof_participant.py +20 -0
  163. algokit_indexer_client/models/_state_proof_reveal.py +25 -0
  164. algokit_indexer_client/models/_state_proof_sig_slot.py +20 -0
  165. algokit_indexer_client/models/_state_proof_signature.py +37 -0
  166. algokit_indexer_client/models/_state_proof_tracking.py +32 -0
  167. algokit_indexer_client/models/_state_proof_verifier.py +24 -0
  168. algokit_indexer_client/models/_state_schema.py +25 -0
  169. algokit_indexer_client/models/_teal_key_value.py +28 -0
  170. algokit_indexer_client/models/_teal_key_value_store.py +6 -0
  171. algokit_indexer_client/models/_teal_value.py +32 -0
  172. algokit_indexer_client/models/_transaction.py +213 -0
  173. algokit_indexer_client/models/_transaction_application.py +105 -0
  174. algokit_indexer_client/models/_transaction_asset_config.py +31 -0
  175. algokit_indexer_client/models/_transaction_asset_freeze.py +29 -0
  176. algokit_indexer_client/models/_transaction_asset_transfer.py +41 -0
  177. algokit_indexer_client/models/_transaction_heartbeat.py +52 -0
  178. algokit_indexer_client/models/_transaction_keyreg.py +59 -0
  179. algokit_indexer_client/models/_transaction_payment.py +33 -0
  180. algokit_indexer_client/models/_transaction_response.py +19 -0
  181. algokit_indexer_client/models/_transaction_signature.py +35 -0
  182. algokit_indexer_client/models/_transaction_signature_logicsig.py +59 -0
  183. algokit_indexer_client/models/_transaction_signature_multisig.py +36 -0
  184. algokit_indexer_client/models/_transaction_signature_multisig_subsignature.py +28 -0
  185. algokit_indexer_client/models/_transaction_state_proof.py +32 -0
  186. algokit_indexer_client/models/_transactions_response.py +29 -0
  187. algokit_indexer_client/py.typed +1 -0
  188. algokit_indexer_client/types.py +7 -0
  189. algokit_kmd_client/__init__.py +10 -0
  190. algokit_kmd_client/client.py +1240 -0
  191. algokit_kmd_client/config.py +36 -0
  192. algokit_kmd_client/exceptions.py +59 -0
  193. algokit_kmd_client/models/__init__.py +112 -0
  194. algokit_kmd_client/models/_classical_signatures.py +4 -0
  195. algokit_kmd_client/models/_create_wallet_request.py +30 -0
  196. algokit_kmd_client/models/_create_wallet_response.py +19 -0
  197. algokit_kmd_client/models/_delete_key_request.py +27 -0
  198. algokit_kmd_client/models/_delete_multisig_request.py +27 -0
  199. algokit_kmd_client/models/_digest_represents_a32_byte_value_holding_the256_bit_hash_digest.py +4 -0
  200. algokit_kmd_client/models/_ed25519_public_key.py +4 -0
  201. algokit_kmd_client/models/_export_key_request.py +27 -0
  202. algokit_kmd_client/models/_export_key_response.py +24 -0
  203. algokit_kmd_client/models/_export_master_key_request.py +22 -0
  204. algokit_kmd_client/models/_export_master_key_response.py +18 -0
  205. algokit_kmd_client/models/_export_multisig_request.py +23 -0
  206. algokit_kmd_client/models/_export_multisig_response.py +26 -0
  207. algokit_kmd_client/models/_generate_key_request.py +18 -0
  208. algokit_kmd_client/models/_generate_key_response.py +19 -0
  209. algokit_kmd_client/models/_import_key_request.py +28 -0
  210. algokit_kmd_client/models/_import_key_response.py +19 -0
  211. algokit_kmd_client/models/_import_multisig_request.py +30 -0
  212. algokit_kmd_client/models/_import_multisig_response.py +19 -0
  213. algokit_kmd_client/models/_init_wallet_handle_token_request.py +22 -0
  214. algokit_kmd_client/models/_init_wallet_handle_token_response.py +18 -0
  215. algokit_kmd_client/models/_list_keys_request.py +18 -0
  216. algokit_kmd_client/models/_list_keys_response.py +18 -0
  217. algokit_kmd_client/models/_list_multisig_request.py +18 -0
  218. algokit_kmd_client/models/_list_multisig_response.py +18 -0
  219. algokit_kmd_client/models/_list_wallets_request.py +11 -0
  220. algokit_kmd_client/models/_list_wallets_response.py +25 -0
  221. algokit_kmd_client/models/_master_derivation_key.py +4 -0
  222. algokit_kmd_client/models/_multisig_sig.py +33 -0
  223. algokit_kmd_client/models/_multisig_subsig.py +23 -0
  224. algokit_kmd_client/models/_public_key.py +4 -0
  225. algokit_kmd_client/models/_release_wallet_handle_token_request.py +18 -0
  226. algokit_kmd_client/models/_rename_wallet_request.py +26 -0
  227. algokit_kmd_client/models/_rename_wallet_response.py +19 -0
  228. algokit_kmd_client/models/_renew_wallet_handle_token_request.py +18 -0
  229. algokit_kmd_client/models/_renew_wallet_handle_token_response.py +19 -0
  230. algokit_kmd_client/models/_serde_helpers.py +241 -0
  231. algokit_kmd_client/models/_sign_multisig_response.py +24 -0
  232. algokit_kmd_client/models/_sign_multisig_txn_request.py +45 -0
  233. algokit_kmd_client/models/_sign_program_multisig_request.py +50 -0
  234. algokit_kmd_client/models/_sign_program_multisig_response.py +24 -0
  235. algokit_kmd_client/models/_sign_program_request.py +37 -0
  236. algokit_kmd_client/models/_sign_program_response.py +24 -0
  237. algokit_kmd_client/models/_sign_transaction_response.py +24 -0
  238. algokit_kmd_client/models/_sign_txn_request.py +36 -0
  239. algokit_kmd_client/models/_signature.py +4 -0
  240. algokit_kmd_client/models/_tx_type.py +4 -0
  241. algokit_kmd_client/models/_versions_request.py +11 -0
  242. algokit_kmd_client/models/_versions_response.py +19 -0
  243. algokit_kmd_client/models/_wallet.py +38 -0
  244. algokit_kmd_client/models/_wallet_handle.py +24 -0
  245. algokit_kmd_client/models/_wallet_info_request.py +18 -0
  246. algokit_kmd_client/models/_wallet_info_response.py +19 -0
  247. algokit_kmd_client/py.typed +1 -0
  248. algokit_kmd_client/types.py +7 -0
  249. algokit_transact/__init__.py +190 -0
  250. algokit_transact/codec/__init__.py +0 -0
  251. algokit_transact/codec/msgpack.py +11 -0
  252. algokit_transact/codec/serde.py +7 -0
  253. algokit_transact/codec/signed.py +57 -0
  254. algokit_transact/codec/transaction.py +65 -0
  255. algokit_transact/exceptions.py +17 -0
  256. algokit_transact/logicsig.py +220 -0
  257. algokit_transact/models/__init__.py +0 -0
  258. algokit_transact/models/app_call.py +447 -0
  259. algokit_transact/models/asset_config.py +19 -0
  260. algokit_transact/models/asset_freeze.py +11 -0
  261. algokit_transact/models/asset_transfer.py +13 -0
  262. algokit_transact/models/common.py +17 -0
  263. algokit_transact/models/heartbeat.py +21 -0
  264. algokit_transact/models/key_registration.py +14 -0
  265. algokit_transact/models/payment.py +14 -0
  266. algokit_transact/models/signed_transaction.py +21 -0
  267. algokit_transact/models/state_proof.py +150 -0
  268. algokit_transact/models/transaction.py +88 -0
  269. algokit_transact/multisig.py +93 -0
  270. algokit_transact/ops/__init__.py +0 -0
  271. algokit_transact/ops/fees.py +47 -0
  272. algokit_transact/ops/group.py +28 -0
  273. algokit_transact/ops/ids.py +14 -0
  274. algokit_transact/ops/validate.py +503 -0
  275. algokit_transact/py.typed +0 -0
  276. algokit_transact/signer.py +195 -0
  277. algokit_transact/signing/__init__.py +0 -0
  278. algokit_transact/signing/logic_signature.py +19 -0
  279. algokit_transact/signing/multisig.py +84 -0
  280. algokit_transact/signing/types.py +39 -0
  281. algokit_transact/signing/validation.py +63 -0
  282. algokit_utils/__init__.py +23 -0
  283. algokit_utils/_debugging.py +304 -0
  284. algokit_utils/accounts/__init__.py +2 -0
  285. algokit_utils/accounts/account_manager.py +1051 -0
  286. algokit_utils/accounts/kmd_account_manager.py +206 -0
  287. algokit_utils/algo25.py +46 -0
  288. algokit_utils/algorand.py +383 -0
  289. algokit_utils/applications/__init__.py +7 -0
  290. algokit_utils/applications/abi.py +280 -0
  291. algokit_utils/applications/app_client.py +2193 -0
  292. algokit_utils/applications/app_deployer.py +788 -0
  293. algokit_utils/applications/app_factory.py +1140 -0
  294. algokit_utils/applications/app_manager.py +575 -0
  295. algokit_utils/applications/app_spec/__init__.py +6 -0
  296. algokit_utils/applications/enums.py +40 -0
  297. algokit_utils/assets/__init__.py +1 -0
  298. algokit_utils/assets/asset_manager.py +344 -0
  299. algokit_utils/clients/__init__.py +41 -0
  300. algokit_utils/clients/client_manager.py +756 -0
  301. algokit_utils/clients/dispenser_api_client.py +212 -0
  302. algokit_utils/common.py +40 -0
  303. algokit_utils/config.py +159 -0
  304. algokit_utils/errors/__init__.py +1 -0
  305. algokit_utils/errors/logic_error.py +160 -0
  306. algokit_utils/models/__init__.py +7 -0
  307. algokit_utils/models/account.py +12 -0
  308. algokit_utils/models/amount.py +198 -0
  309. algokit_utils/models/application.py +90 -0
  310. algokit_utils/models/network.py +29 -0
  311. algokit_utils/models/simulate.py +7 -0
  312. algokit_utils/models/state.py +53 -0
  313. algokit_utils/models/transaction.py +49 -0
  314. algokit_utils/protocols/__init__.py +3 -0
  315. algokit_utils/protocols/account.py +11 -0
  316. algokit_utils/protocols/signer.py +17 -0
  317. algokit_utils/protocols/typed_clients.py +110 -0
  318. algokit_utils/py.typed +0 -0
  319. algokit_utils/transact.py +195 -0
  320. algokit_utils/transactions/__init__.py +3 -0
  321. algokit_utils/transactions/builders/__init__.py +67 -0
  322. algokit_utils/transactions/builders/app.py +248 -0
  323. algokit_utils/transactions/builders/asset.py +256 -0
  324. algokit_utils/transactions/builders/common.py +263 -0
  325. algokit_utils/transactions/builders/keyreg.py +103 -0
  326. algokit_utils/transactions/builders/method_call.py +380 -0
  327. algokit_utils/transactions/builders/payment.py +43 -0
  328. algokit_utils/transactions/composer_resources.py +409 -0
  329. algokit_utils/transactions/fee_coverage.py +79 -0
  330. algokit_utils/transactions/helpers.py +9 -0
  331. algokit_utils/transactions/transaction_composer.py +1574 -0
  332. algokit_utils/transactions/transaction_creator.py +699 -0
  333. algokit_utils/transactions/transaction_sender.py +1240 -0
  334. algokit_utils/transactions/types.py +262 -0
  335. algokit_utils-5.0.0a3.dist-info/METADATA +105 -0
  336. algokit_utils-5.0.0a3.dist-info/RECORD +337 -0
  337. algokit_utils-5.0.0a3.dist-info/WHEEL +4 -0
@@ -0,0 +1,212 @@
1
+ import contextlib
2
+ import enum
3
+ import os
4
+ from dataclasses import dataclass
5
+
6
+ import httpx
7
+
8
+ from algokit_utils.config import config
9
+
10
+ __all__ = [
11
+ "DISPENSER_ACCESS_TOKEN_KEY",
12
+ "DISPENSER_ASSETS",
13
+ "DISPENSER_REQUEST_TIMEOUT",
14
+ "DispenserApiConfig",
15
+ "DispenserAsset",
16
+ "DispenserAssetName",
17
+ "DispenserFundResponse",
18
+ "DispenserLimitResponse",
19
+ "TestNetDispenserApiClient",
20
+ ]
21
+
22
+
23
+ class DispenserApiConfig:
24
+ BASE_URL = "https://api.dispenser.algorandfoundation.tools"
25
+
26
+
27
+ class DispenserAssetName(enum.IntEnum):
28
+ ALGO = 0
29
+
30
+
31
+ @dataclass
32
+ class DispenserAsset:
33
+ asset_id: int
34
+ """The ID of the asset"""
35
+ decimals: int
36
+ """The amount of decimal places the asset was created with"""
37
+ description: str
38
+ """The description of the asset"""
39
+
40
+
41
+ @dataclass
42
+ class DispenserFundResponse:
43
+ tx_id: str
44
+ """The transaction ID of the funded transaction"""
45
+ amount: int
46
+ """The amount of Algos funded"""
47
+
48
+
49
+ @dataclass
50
+ class DispenserLimitResponse:
51
+ amount: int
52
+ """The amount of Algos that can be funded"""
53
+
54
+
55
+ DISPENSER_ASSETS = {
56
+ DispenserAssetName.ALGO: DispenserAsset(
57
+ asset_id=0,
58
+ decimals=6,
59
+ description="Algo",
60
+ ),
61
+ }
62
+ DISPENSER_REQUEST_TIMEOUT = 15
63
+ DISPENSER_ACCESS_TOKEN_KEY = "ALGOKIT_DISPENSER_ACCESS_TOKEN"
64
+
65
+
66
+ class TestNetDispenserApiClient:
67
+ """
68
+ Client for interacting with the [AlgoKit TestNet Dispenser API](https://github.com/algorandfoundation/algokit/blob/main/docs/testnet_api.md).
69
+ To get started create a new access token via `algokit dispenser login --ci`
70
+ and pass it to the client constructor as `auth_token`.
71
+ Alternatively set the access token as environment variable `ALGOKIT_DISPENSER_ACCESS_TOKEN`,
72
+ and it will be auto loaded. If both are set, the constructor argument takes precedence.
73
+
74
+ Default request timeout is 15 seconds. Modify by passing `request_timeout` to the constructor.
75
+ """
76
+
77
+ # NOTE: ensures pytest does not think this is a test
78
+ # https://docs.pytest.org/en/stable/example/pythoncollection.html#customizing-test-collection
79
+ __test__ = False
80
+ auth_token: str
81
+ request_timeout = DISPENSER_REQUEST_TIMEOUT
82
+
83
+ def __init__(self, auth_token: str | None = None, request_timeout: int = DISPENSER_REQUEST_TIMEOUT):
84
+ auth_token_from_env = os.getenv(DISPENSER_ACCESS_TOKEN_KEY)
85
+
86
+ if auth_token:
87
+ self.auth_token = auth_token
88
+ elif auth_token_from_env:
89
+ self.auth_token = auth_token_from_env
90
+ else:
91
+ raise Exception(
92
+ f"Can't init AlgoKit TestNet Dispenser API client "
93
+ f"because neither environment variable {DISPENSER_ACCESS_TOKEN_KEY} or "
94
+ "the auth_token were provided."
95
+ )
96
+
97
+ self.request_timeout = request_timeout
98
+
99
+ def _process_dispenser_request(
100
+ self, *, auth_token: str, url_suffix: str, data: dict | None = None, method: str = "POST"
101
+ ) -> httpx.Response:
102
+ """
103
+ Generalized method to process http requests to dispenser API
104
+ """
105
+
106
+ headers = {"Authorization": f"Bearer {(auth_token)}"}
107
+
108
+ # Set request arguments
109
+ request_args = {
110
+ "url": f"{DispenserApiConfig.BASE_URL}/{url_suffix}",
111
+ "headers": headers,
112
+ "timeout": self.request_timeout,
113
+ }
114
+
115
+ if method.upper() != "GET" and data is not None:
116
+ request_args["json"] = data
117
+
118
+ try:
119
+ response: httpx.Response = getattr(httpx, method.lower())(**request_args)
120
+ response.raise_for_status()
121
+ return response
122
+
123
+ except httpx.HTTPStatusError as err:
124
+ error_message = f"Error processing dispenser API request: {err.response.status_code}"
125
+ error_response = None
126
+ with contextlib.suppress(Exception):
127
+ error_response = err.response.json()
128
+
129
+ if error_response and error_response.get("code"):
130
+ error_message = error_response.get("code")
131
+
132
+ elif err.response.status_code == httpx.codes.BAD_REQUEST:
133
+ error_message = err.response.json()["message"]
134
+
135
+ raise Exception(error_message) from err
136
+
137
+ except Exception as err:
138
+ error_message = "Error processing dispenser API request"
139
+ config.logger.debug(f"{error_message}: {err}", exc_info=True)
140
+ raise err
141
+
142
+ def fund(self, address: str, amount: int, asset_id: int | None = None) -> DispenserFundResponse: # noqa: ARG002
143
+ """
144
+ Fund an account with Algos from the dispenser API
145
+
146
+ :param address: The address to fund
147
+ :param amount: The amount of Algos to fund
148
+ :param asset_id: The asset ID to fund (deprecated)
149
+ :return: The transaction ID of the funded transaction
150
+ :raises Exception: If the dispenser API request fails
151
+
152
+ :example:
153
+ >>> dispenser_client = TestNetDispenserApiClient()
154
+ >>> dispenser_client.fund(address="SENDER_ADDRESS", amount=1000000)
155
+ """
156
+
157
+ try:
158
+ response = self._process_dispenser_request(
159
+ auth_token=self.auth_token,
160
+ url_suffix=f"fund/{DISPENSER_ASSETS[DispenserAssetName.ALGO].asset_id}",
161
+ data={
162
+ "receiver": address,
163
+ "amount": amount,
164
+ "assetID": DISPENSER_ASSETS[DispenserAssetName.ALGO].asset_id,
165
+ },
166
+ method="POST",
167
+ )
168
+
169
+ content = response.json()
170
+ return DispenserFundResponse(tx_id=content["txID"], amount=content["amount"])
171
+
172
+ except Exception as err:
173
+ config.logger.exception(f"Error funding account {address}: {err}")
174
+ raise err
175
+
176
+ def refund(self, refund_txn_id: str) -> None:
177
+ """
178
+ Register a refund for a transaction with the dispenser API
179
+ """
180
+
181
+ try:
182
+ self._process_dispenser_request(
183
+ auth_token=self.auth_token,
184
+ url_suffix="refund",
185
+ data={"refundTransactionID": refund_txn_id},
186
+ method="POST",
187
+ )
188
+
189
+ except Exception as err:
190
+ config.logger.exception(f"Error issuing refund for txn_id {refund_txn_id}: {err}")
191
+ raise err
192
+
193
+ def get_limit(
194
+ self,
195
+ address: str,
196
+ ) -> DispenserLimitResponse:
197
+ """
198
+ Get current limit for an account with Algos from the dispenser API
199
+ """
200
+
201
+ try:
202
+ response = self._process_dispenser_request(
203
+ auth_token=self.auth_token,
204
+ url_suffix=f"fund/{DISPENSER_ASSETS[DispenserAssetName.ALGO].asset_id}/limit",
205
+ method="GET",
206
+ )
207
+ content = response.json()
208
+
209
+ return DispenserLimitResponse(amount=content["amount"])
210
+ except Exception as err:
211
+ config.logger.exception(f"Error setting limit for account {address}: {err}")
212
+ raise err
@@ -0,0 +1,40 @@
1
+ """Common utilities - user-facing facade for algokit_common.
2
+
3
+ Users should import from this module instead of algokit_common directly.
4
+ """
5
+
6
+ from algokit_common import (
7
+ ADDRESS_LENGTH,
8
+ CHECKSUM_BYTE_LENGTH,
9
+ HASH_BYTES_LENGTH,
10
+ MAX_TRANSACTION_GROUP_SIZE,
11
+ MICROALGOS_TO_ALGOS_RATIO,
12
+ MIN_TXN_FEE,
13
+ PUBLIC_KEY_BYTE_LENGTH,
14
+ SIGNATURE_BYTE_LENGTH,
15
+ TRANSACTION_ID_LENGTH,
16
+ ZERO_ADDRESS,
17
+ ProgramSourceMap,
18
+ address_from_public_key,
19
+ get_application_address,
20
+ public_key_from_address,
21
+ sha512_256,
22
+ )
23
+
24
+ __all__ = [
25
+ "ADDRESS_LENGTH",
26
+ "CHECKSUM_BYTE_LENGTH",
27
+ "HASH_BYTES_LENGTH",
28
+ "MAX_TRANSACTION_GROUP_SIZE",
29
+ "MICROALGOS_TO_ALGOS_RATIO",
30
+ "MIN_TXN_FEE",
31
+ "PUBLIC_KEY_BYTE_LENGTH",
32
+ "SIGNATURE_BYTE_LENGTH",
33
+ "TRANSACTION_ID_LENGTH",
34
+ "ZERO_ADDRESS",
35
+ "ProgramSourceMap",
36
+ "address_from_public_key",
37
+ "get_application_address",
38
+ "public_key_from_address",
39
+ "sha512_256",
40
+ ]
@@ -0,0 +1,159 @@
1
+ import logging
2
+ import os
3
+ from collections.abc import Callable
4
+ from pathlib import Path
5
+
6
+ # Environment variable to override the project root
7
+ ALGOKIT_PROJECT_ROOT = os.getenv("ALGOKIT_PROJECT_ROOT")
8
+ ALGOKIT_CONFIG_FILENAME = ".algokit.toml"
9
+
10
+
11
+ class AlgoKitLogger(logging.Logger):
12
+ def __init__(self, name: str = "algokit-utils-py", level: int = logging.NOTSET):
13
+ super().__init__(name, level)
14
+
15
+ def _log(self, level: int, msg: object, args, exc_info=None, extra=None, stack_info=False, stacklevel=1) -> None: # type: ignore[no-untyped-def] # noqa: FBT002, ANN001
16
+ """
17
+ Overrides the base _log method to allow suppressing individual log calls.
18
+ When a caller passes suppress_log=True in the extra keyword, the log call is ignored.
19
+ """
20
+
21
+ # Check if the 'suppress_log' flag is provided in the extra dictionary.
22
+ if extra and extra.get("suppress_log", False):
23
+ return
24
+ # Call the parent _log
25
+ super()._log(level, msg, args, exc_info, extra, stack_info, stacklevel)
26
+
27
+ @classmethod
28
+ def get_null_logger(cls) -> logging.Logger:
29
+ """Return a logger that does nothing (a null logger)."""
30
+ null_logger = logging.getLogger("null")
31
+ null_logger.handlers.clear()
32
+ null_logger.addHandler(logging.NullHandler())
33
+ null_logger.propagate = False
34
+ return null_logger
35
+
36
+
37
+ # Set our custom logger class as the default.
38
+ logging.setLoggerClass(AlgoKitLogger)
39
+
40
+
41
+ class UpdatableConfig:
42
+ """
43
+ Class to manage and update configuration settings for the AlgoKit project.
44
+
45
+ Attributes:
46
+ debug (bool): Indicates whether debug mode is enabled.
47
+ project_root (Path | None): The path to the project root directory.
48
+ trace_all (bool): Indicates whether to trace all operations.
49
+ trace_buffer_size_mb (int | float): The size of the trace buffer in megabytes.
50
+ max_search_depth (int): The maximum depth to search for a specific file.
51
+ populate_app_call_resources (bool): Whether to populate app call resources.
52
+ logger (logging.Logger): The logger instance to use. Defaults to an AlgoKitLogger instance.
53
+ """
54
+
55
+ def __init__(self) -> None:
56
+ self._logger: logging.Logger = AlgoKitLogger()
57
+ self._debug: bool = False
58
+ self._project_root: Path | None = None
59
+ self._trace_all: bool = False
60
+ self._trace_buffer_size_mb: int | float = 256 # megabytes
61
+ self._max_search_depth: int = 10
62
+ self._populate_app_call_resources: bool = True
63
+ self._configure_project_root()
64
+
65
+ def _configure_project_root(self) -> None:
66
+ """
67
+ Configures the project root by searching for a specific file within a depth limit.
68
+ """
69
+ current_path = Path(__file__).resolve()
70
+ for _ in range(self._max_search_depth):
71
+ self._logger.debug(f"Searching in: {current_path}")
72
+ if (current_path / ALGOKIT_CONFIG_FILENAME).exists():
73
+ self._project_root = current_path
74
+ break
75
+ current_path = current_path.parent
76
+
77
+ @property
78
+ def logger(self) -> logging.Logger:
79
+ """Returns the logger instance."""
80
+ return self._logger
81
+
82
+ @property
83
+ def debug(self) -> bool:
84
+ """Returns the debug status."""
85
+ return self._debug
86
+
87
+ @property
88
+ def project_root(self) -> Path | None:
89
+ """Returns the project root path."""
90
+ return self._project_root
91
+
92
+ @property
93
+ def trace_all(self) -> bool:
94
+ """Indicates whether simulation traces for all operations should be stored."""
95
+ return self._trace_all
96
+
97
+ @property
98
+ def trace_buffer_size_mb(self) -> int | float:
99
+ """Returns the size of the trace buffer in megabytes."""
100
+ return self._trace_buffer_size_mb
101
+
102
+ @property
103
+ def populate_app_call_resource(self) -> bool:
104
+ """Indicates whether or not to populate app call resources."""
105
+ return self._populate_app_call_resources
106
+
107
+ def with_debug(self, func: Callable[[], str | None]) -> None:
108
+ """
109
+ Executes a function with debug mode temporarily enabled.
110
+ """
111
+ original_debug = self._debug
112
+ try:
113
+ self._debug = True
114
+ func()
115
+ finally:
116
+ self._debug = original_debug
117
+
118
+ def configure(
119
+ self,
120
+ *,
121
+ debug: bool | None = None,
122
+ project_root: Path | None = None,
123
+ trace_all: bool = False,
124
+ trace_buffer_size_mb: float = 256,
125
+ max_search_depth: int = 10,
126
+ populate_app_call_resources: bool = True,
127
+ logger: logging.Logger | None = None,
128
+ ) -> None:
129
+ """
130
+ Configures various settings for the application.
131
+
132
+ :param debug: Whether debug mode is enabled.
133
+ :param project_root: The path to the project root directory.
134
+ :param trace_all: Whether to trace all operations. Defaults to False.
135
+ :param trace_buffer_size_mb: The trace buffer size in megabytes. Defaults to 256.
136
+ :param max_search_depth: The maximum depth to search for a specific file. Defaults to 10.
137
+ :param populate_app_call_resources: Whether to populate app call resources. Defaults to True.
138
+ :param logger: A custom logger to use. Defaults to AlgoKitLogger instance.
139
+ """
140
+ if logger is not None:
141
+ self._logger = logger
142
+
143
+ if debug is not None:
144
+ self._debug = debug
145
+ # Update logger's level so debug messages are processed only when debug is True.
146
+ self._logger.setLevel(logging.DEBUG)
147
+
148
+ if project_root is not None:
149
+ self._project_root = project_root.resolve(strict=True)
150
+ elif debug is not None and ALGOKIT_PROJECT_ROOT:
151
+ self._project_root = Path(ALGOKIT_PROJECT_ROOT).resolve(strict=True)
152
+
153
+ self._trace_all = trace_all
154
+ self._trace_buffer_size_mb = trace_buffer_size_mb
155
+ self._max_search_depth = max_search_depth
156
+ self._populate_app_call_resources = populate_app_call_resources
157
+
158
+
159
+ config = UpdatableConfig()
@@ -0,0 +1 @@
1
+ from algokit_utils.errors.logic_error import * # noqa: F403
@@ -0,0 +1,160 @@
1
+ import base64
2
+ import re
3
+ from collections.abc import Callable, Mapping, Sequence
4
+ from copy import copy
5
+ from typing import TYPE_CHECKING, TypedDict
6
+
7
+ from algokit_algod_client.models import (
8
+ PendingTransactionResponse,
9
+ SimulateTransactionResult,
10
+ SimulationTransactionExecTrace,
11
+ )
12
+ from algokit_common import ProgramSourceMap
13
+
14
+ if TYPE_CHECKING:
15
+ pass
16
+ __all__ = [
17
+ "LogicError",
18
+ "LogicErrorData",
19
+ "create_simulate_traces_for_logic_error",
20
+ "parse_logic_error",
21
+ ]
22
+
23
+
24
+ LOGIC_ERROR = (
25
+ ".*transaction (?P<transaction_id>[A-Z0-9]+): logic eval error: (?P<message>.*). Details: .*pc=(?P<pc>[0-9]+).*"
26
+ )
27
+
28
+
29
+ class LogicErrorData(TypedDict):
30
+ transaction_id: str
31
+ message: str
32
+ pc: int
33
+
34
+
35
+ def parse_logic_error(
36
+ error_str: str,
37
+ ) -> LogicErrorData | None:
38
+ match = re.match(LOGIC_ERROR, error_str)
39
+ if match is None:
40
+ return None
41
+
42
+ return {
43
+ "transaction_id": match.group("transaction_id"),
44
+ "message": match.group("message"),
45
+ "pc": int(match.group("pc")),
46
+ }
47
+
48
+
49
+ class LogicError(Exception):
50
+ def __init__(
51
+ self,
52
+ *,
53
+ logic_error_str: str,
54
+ program: str,
55
+ source_map: "ProgramSourceMap | None",
56
+ transaction_id: str,
57
+ message: str,
58
+ pc: int,
59
+ logic_error: Exception | None = None,
60
+ traces: list[SimulateTransactionResult] | None = None,
61
+ get_line_for_pc: Callable[[int], int | None] | None = None,
62
+ ):
63
+ self.logic_error = logic_error
64
+ self.logic_error_str = logic_error_str
65
+ try:
66
+ self.program = base64.b64decode(program).decode("utf-8")
67
+ except Exception:
68
+ self.program = program
69
+ self.source_map = source_map
70
+ self.lines = self.program.split("\n")
71
+ self.transaction_id = transaction_id
72
+ self.message = message
73
+ self.pc = pc
74
+ self.traces = traces
75
+ self.line_no = (
76
+ self.source_map.get_line_for_pc(self.pc)
77
+ if self.source_map
78
+ else get_line_for_pc(self.pc)
79
+ if get_line_for_pc
80
+ else None
81
+ )
82
+
83
+ def __str__(self) -> str:
84
+ return (
85
+ f"Txn {self.transaction_id} had error '{self.message}' at PC {self.pc}"
86
+ + (":" if self.line_no is None else f" and Source Line {self.line_no}:")
87
+ + f"\n{self.trace()}"
88
+ )
89
+
90
+ def trace(self, lines: int = 5) -> str:
91
+ if self.line_no is None:
92
+ return """
93
+ Could not determine TEAL source line for the error as no approval source map was provided, to receive a trace of the
94
+ error please provide an approval SourceMap. Either by:
95
+ 1.Providing template_values when creating the AppClient, so a SourceMap can be obtained automatically OR
96
+ 2.Set approval_source_map from a previously compiled approval program OR
97
+ 3.Import a previously exported source map using import_source_map"""
98
+
99
+ program_lines = copy(self.lines)
100
+ program_lines[self.line_no] += "\t\t<-- Error"
101
+ lines_before = max(0, self.line_no - lines)
102
+ lines_after = min(len(program_lines), self.line_no + lines)
103
+ return "\n\t" + "\n\t".join(program_lines[lines_before:lines_after])
104
+
105
+
106
+ def create_simulate_traces_for_logic_error(simulate: object) -> list[SimulateTransactionResult]:
107
+ """Extract simulation traces from a simulate response for logic error debugging.
108
+
109
+ Args:
110
+ simulate: An object with simulate_response and failed_at attributes.
111
+
112
+ Returns:
113
+ A list of SimulateTransactionResult objects extracted from the simulation response.
114
+ """
115
+ traces: list[SimulateTransactionResult] = []
116
+ simulate_response = getattr(simulate, "simulate_response", None)
117
+ failed_at = getattr(simulate, "failed_at", None)
118
+
119
+ if not failed_at or not isinstance(simulate_response, Mapping):
120
+ return traces
121
+
122
+ txn_groups = simulate_response.get("txn-groups", [])
123
+ if not isinstance(txn_groups, Sequence):
124
+ return traces
125
+
126
+ for txn_group in txn_groups:
127
+ if not isinstance(txn_group, Mapping):
128
+ continue
129
+ txn_results = txn_group.get("txn-results", [])
130
+
131
+ if not isinstance(txn_results, Sequence):
132
+ continue
133
+
134
+ for txn_result in txn_results:
135
+ if not isinstance(txn_result, Mapping):
136
+ continue
137
+ exec_trace_raw = txn_result.get("exec-trace")
138
+ app_budget_consumed = txn_result.get("app-budget-consumed")
139
+ logic_sig_budget_consumed = txn_result.get("logic-sig-budget-consumed")
140
+ txn_result_inner = txn_result.get("txn-result", {})
141
+ logs_raw = txn_result_inner.get("logs", []) if isinstance(txn_result_inner, Mapping) else []
142
+ logs = [base64.b64decode(log) if isinstance(log, str) else log for log in logs_raw] if logs_raw else None
143
+
144
+ # Create PendingTransactionResponse with logs for the SimulateTransactionResult
145
+ # Note: txn is required but we don't have it from raw JSON, use placeholder
146
+ pending_response = PendingTransactionResponse(
147
+ txn=None, # type: ignore[arg-type] # placeholder for raw response parsing
148
+ logs=logs,
149
+ )
150
+
151
+ # Create SimulateTransactionResult with available data
152
+ traces.append(
153
+ SimulateTransactionResult(
154
+ txn_result=pending_response,
155
+ app_budget_consumed=app_budget_consumed,
156
+ logic_sig_budget_consumed=logic_sig_budget_consumed,
157
+ exec_trace=exec_trace_raw if isinstance(exec_trace_raw, SimulationTransactionExecTrace) else None,
158
+ )
159
+ )
160
+ return traces
@@ -0,0 +1,7 @@
1
+ from algokit_utils.models.account import * # noqa: F403
2
+ from algokit_utils.models.amount import * # noqa: F403
3
+ from algokit_utils.models.application import * # noqa: F403
4
+ from algokit_utils.models.network import * # noqa: F403
5
+ from algokit_utils.models.simulate import * # noqa: F403
6
+ from algokit_utils.models.state import * # noqa: F403
7
+ from algokit_utils.models.transaction import * # noqa: F403
@@ -0,0 +1,12 @@
1
+ from algokit_transact import AddressWithSigners, LogicSigAccount, MultisigAccount, MultisigMetadata
2
+
3
+ __all__ = [
4
+ "DISPENSER_ACCOUNT_NAME",
5
+ "AddressWithSigners",
6
+ "LogicSigAccount",
7
+ "MultisigAccount",
8
+ "MultisigMetadata",
9
+ ]
10
+
11
+
12
+ DISPENSER_ACCOUNT_NAME = "DISPENSER"