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
algokit_abi/abi.py ADDED
@@ -0,0 +1,667 @@
1
+ import abc
2
+ import dataclasses
3
+ import decimal
4
+ import typing
5
+ from collections.abc import Iterator, Mapping, Sequence
6
+ from functools import cached_property
7
+
8
+ from algokit_common import address_from_public_key, public_key_from_address
9
+
10
+ BytesLike = bytes | bytearray | memoryview
11
+
12
+
13
+ _ABI_BOOL_TRUE_UINT = 0x80
14
+ _ABI_BOOL_TRUE = _ABI_BOOL_TRUE_UINT.to_bytes(length=1, byteorder="big")
15
+ _ABI_BOOL_FALSE = b"\x00"
16
+ _MAX_UINT_N = 512
17
+ _U16_NUM_BYTES = 2
18
+ _MAX_U16 = 2**16 - 1
19
+
20
+
21
+ class ABIType(abc.ABC):
22
+ @property
23
+ def display_name(self) -> str:
24
+ return self.name
25
+
26
+ @property
27
+ @abc.abstractmethod
28
+ def name(self) -> str: ...
29
+
30
+ @abc.abstractmethod
31
+ def encode(self, value: typing.Any) -> bytes: ... # noqa: ANN401
32
+
33
+ @abc.abstractmethod
34
+ def decode(self, value: BytesLike) -> typing.Any: ... # noqa: ANN401
35
+
36
+ def is_dynamic(self) -> bool:
37
+ return self.byte_len() is None
38
+
39
+ @abc.abstractmethod
40
+ def byte_len(self) -> int | None: ...
41
+
42
+ @classmethod
43
+ def from_string(cls, value: str) -> "ABIType":
44
+ try:
45
+ return _COMMON_TYPES[value]
46
+ except KeyError:
47
+ pass
48
+ if value.startswith("(") and value.endswith(")"):
49
+ tup_inner = value[1:-1]
50
+ tup_elements = [cls.from_string(t) for t in split_tuple_str(tup_inner)]
51
+ return TupleType(tup_elements)
52
+ if value.endswith("[]"):
53
+ element = cls.from_string(value[:-2])
54
+ return DynamicArrayType(element)
55
+ if value.endswith("]"):
56
+ array_start = value.rindex("[")
57
+ size_str = value[array_start + 1 : -1]
58
+ try:
59
+ size = int(size_str)
60
+ except ValueError:
61
+ pass # fall through to error
62
+ else:
63
+ element = cls.from_string(value[:array_start])
64
+ return StaticArrayType(element, size)
65
+ elif value.startswith("ufixed"):
66
+ n_m_str = value.removeprefix("ufixed")
67
+ try:
68
+ n, m = map(int, n_m_str.split("x"))
69
+ except ValueError:
70
+ pass # fall through to error
71
+ else:
72
+ return UfixedType(n, m)
73
+ raise ValueError(f"unknown abi type: {value}")
74
+
75
+ def __eq__(self, other: object) -> bool:
76
+ if isinstance(other, StructType):
77
+ # structs can only equal structs
78
+ return False
79
+ if isinstance(other, ABIType):
80
+ return self.name == other.name
81
+ else:
82
+ return False
83
+
84
+ def __hash__(self) -> int:
85
+ return hash(self.display_name)
86
+
87
+ def __str__(self) -> str:
88
+ return self.display_name
89
+
90
+ def _check_num_bytes(self, value: BytesLike) -> None:
91
+ expected_bytes_len = self.byte_len()
92
+ if expected_bytes_len is not None and len(value) != expected_bytes_len:
93
+ raise ValueError(f"expected {expected_bytes_len} bytes for {self.display_name}, got {len(value)} bytes")
94
+
95
+
96
+ @typing.final
97
+ class BoolType(ABIType):
98
+ @property
99
+ def name(self) -> str:
100
+ return "bool"
101
+
102
+ def byte_len(self) -> int:
103
+ return 1
104
+
105
+ def encode(self, value: bool) -> bytes: # noqa: FBT001
106
+ # note: bool in an array or tuple is handled separately
107
+ # intentionally comparing to True and False to handle invalid types
108
+ if value is True:
109
+ return _ABI_BOOL_TRUE
110
+ elif value is False:
111
+ return _ABI_BOOL_FALSE
112
+ else:
113
+ raise ValueError(f"expected a bool, got: {_error_str(value)}")
114
+
115
+ def decode(self, value: BytesLike) -> bool:
116
+ if value == _ABI_BOOL_TRUE:
117
+ return True
118
+ elif value == _ABI_BOOL_FALSE:
119
+ return False
120
+ else:
121
+ raise ValueError(f"bool value could not be decoded: {_error_str(value)}")
122
+
123
+
124
+ @typing.final
125
+ @dataclasses.dataclass(frozen=True)
126
+ class UintType(ABIType):
127
+ bit_size: int = dataclasses.field()
128
+
129
+ def __post_init__(self) -> None:
130
+ if (
131
+ not isinstance(self.bit_size, int)
132
+ or self.bit_size <= 0
133
+ or self.bit_size > _MAX_UINT_N
134
+ or self.bit_size % 8 != 0
135
+ ):
136
+ raise ValueError(f"bit_size must be between 8 and {_MAX_UINT_N} and divisible by 8")
137
+
138
+ @property
139
+ def name(self) -> str:
140
+ return f"uint{self.bit_size}"
141
+
142
+ def byte_len(self) -> int:
143
+ return self.bit_size // 8
144
+
145
+ def encode(self, value: int) -> bytes:
146
+ if not isinstance(value, int):
147
+ raise TypeError("expected int")
148
+ return value.to_bytes(self.byte_len(), byteorder="big", signed=False)
149
+
150
+ def decode(self, value: BytesLike) -> int:
151
+ self._check_num_bytes(value)
152
+ return int.from_bytes(value, byteorder="big", signed=False)
153
+
154
+
155
+ _MAX_PRECISION = 160
156
+
157
+
158
+ @typing.final
159
+ @dataclasses.dataclass(frozen=True)
160
+ class UfixedType(ABIType):
161
+ bit_size: int
162
+ precision: int
163
+
164
+ def __post_init__(self) -> None:
165
+ if (
166
+ not isinstance(self.bit_size, int)
167
+ or self.bit_size <= 0
168
+ or self.bit_size > _MAX_UINT_N
169
+ or self.bit_size % 8 != 0
170
+ ):
171
+ raise ValueError(f"bit_size must be between 8 and {_MAX_UINT_N} and divisible by 8")
172
+ if not isinstance(self.precision, int) or self.precision <= 0 or self.precision > _MAX_PRECISION:
173
+ raise ValueError(f"precision must be between 0 and {_MAX_PRECISION}")
174
+
175
+ @property
176
+ def name(self) -> str:
177
+ return f"ufixed{self.bit_size}x{self.precision}"
178
+
179
+ def byte_len(self) -> int:
180
+ return self._int_type.byte_len()
181
+
182
+ @cached_property
183
+ def _int_type(self) -> UintType:
184
+ return UintType(bit_size=self.bit_size)
185
+
186
+ def encode(self, value: decimal.Decimal | int) -> bytes:
187
+ if isinstance(value, decimal.Decimal):
188
+ value = value.normalize()
189
+ decimal_tuple = value.as_tuple()
190
+ exponent = decimal_tuple.exponent
191
+ if not isinstance(exponent, int):
192
+ raise ValueError(f"unsupported decimal: {_error_str(value)}")
193
+ if -exponent > self.precision:
194
+ raise ValueError(f"precision exceeds {self.precision}: {_error_str(value)}")
195
+ value_int = int(value * 10**self.precision)
196
+ else:
197
+ value_int = value
198
+ return self._int_type.encode(value_int)
199
+
200
+ def decode(self, value: BytesLike) -> decimal.Decimal:
201
+ int_value = self._int_type.decode(value)
202
+ int_str = str(int_value).zfill(self.precision)
203
+ decimal_str = int_str[: -self.precision] + "." + int_str[-self.precision :]
204
+ return decimal.Decimal(decimal_str)
205
+
206
+
207
+ @typing.final
208
+ @dataclasses.dataclass(frozen=True)
209
+ class ByteType(ABIType):
210
+ _uint_type: UintType = dataclasses.field(default=UintType(bit_size=8), init=False)
211
+
212
+ @property
213
+ def name(self) -> str:
214
+ return "byte"
215
+
216
+ def byte_len(self) -> int:
217
+ return self._uint_type.byte_len()
218
+
219
+ def encode(self, value: int | bytes | bytearray) -> bytes:
220
+ if isinstance(value, int):
221
+ return self._uint_type.encode(value)
222
+ elif len(value) == 1:
223
+ return bytes(value)
224
+ else:
225
+ raise ValueError(f"expected 1 byte: {_error_str(value)}")
226
+
227
+ def decode(self, value: BytesLike) -> bytes:
228
+ self._check_num_bytes(value)
229
+ return bytes(value)
230
+
231
+
232
+ @dataclasses.dataclass(frozen=True)
233
+ class DynamicArrayType(ABIType):
234
+ element: ABIType
235
+
236
+ @property
237
+ def display_name(self) -> str:
238
+ return f"{self.element.display_name}[]"
239
+
240
+ @property
241
+ def name(self) -> str:
242
+ return f"{self.element.name}[]"
243
+
244
+ def byte_len(self) -> None:
245
+ return None
246
+
247
+ def encode(self, value: Sequence | bytes | bytearray) -> bytes:
248
+ static_type = StaticArrayType(element=self.element, size=len(value))
249
+ try:
250
+ len_bytes = _int_to_u16_bytes(len(value))
251
+ except OverflowError:
252
+ raise ValueError(f"array length exceeds {_MAX_U16}") from None
253
+ return len_bytes + static_type.encode(value)
254
+
255
+ def decode(self, value: BytesLike) -> list | bytes:
256
+ data = memoryview(value)
257
+ if data.nbytes < _U16_NUM_BYTES:
258
+ raise ValueError(f"not enough bytes to decode {self}: {_error_str(value)}")
259
+
260
+ array_len = int.from_bytes(data[:_U16_NUM_BYTES], byteorder="big")
261
+
262
+ static_type = StaticArrayType(element=self.element, size=array_len)
263
+ return static_type.decode(data[_U16_NUM_BYTES:])
264
+
265
+
266
+ @dataclasses.dataclass(frozen=True)
267
+ class _RepeatedSequence(Sequence[ABIType]):
268
+ element: ABIType
269
+ size: int
270
+
271
+ def __len__(self) -> int:
272
+ return self.size
273
+
274
+ def __iter__(self) -> Iterator[ABIType]:
275
+ for _ in range(self.size):
276
+ yield self.element
277
+
278
+ def __getitem__(self, item: int) -> ABIType: # type: ignore[override]
279
+ if item >= self.size or -item > self.size:
280
+ raise IndexError("index out of range")
281
+ return self.element
282
+
283
+ def __contains__(self, x: object, /) -> bool:
284
+ return x == self.element
285
+
286
+
287
+ @typing.final
288
+ @dataclasses.dataclass(frozen=True)
289
+ class StaticArrayType(ABIType):
290
+ element: ABIType
291
+ size: int
292
+
293
+ @property
294
+ def display_name(self) -> str:
295
+ return f"{self.element.display_name}[{self.size}]"
296
+
297
+ @property
298
+ def name(self) -> str:
299
+ return f"{self.element.name}[{self.size}]"
300
+
301
+ @cached_property
302
+ def _tuple_type(self) -> "TupleType":
303
+ return TupleType(elements=_RepeatedSequence(self.element, self.size))
304
+
305
+ def byte_len(self) -> int | None:
306
+ return self._tuple_type.byte_len()
307
+
308
+ def encode(self, value: Sequence | bytes | bytearray) -> bytes:
309
+ return self._tuple_type.encode(value)
310
+
311
+ def decode(self, value: BytesLike) -> list | bytes:
312
+ result = self._tuple_type.decode(value)
313
+ if isinstance(result, bytes):
314
+ return result
315
+ else:
316
+ return list(result)
317
+
318
+
319
+ @typing.final
320
+ @dataclasses.dataclass(frozen=True)
321
+ class TupleType(ABIType):
322
+ elements: Sequence[ABIType]
323
+
324
+ @cached_property
325
+ def display_name(self) -> str:
326
+ if self._homogenous_element:
327
+ return f"{self._homogenous_element.display_name}[{len(self.elements)}]"
328
+ else:
329
+ return f"({','.join(v.display_name for v in self.elements)})"
330
+
331
+ @cached_property
332
+ def name(self) -> str:
333
+ return f"({','.join(v.name for v in self.elements)})"
334
+
335
+ def byte_len(self) -> int | None:
336
+ return self._byte_len
337
+
338
+ @cached_property
339
+ def _byte_len(self) -> int | None:
340
+ total_bits = 0
341
+ for el in self.elements:
342
+ if el.name == "bool":
343
+ total_bits += 1
344
+ else:
345
+ el_byte_len = el.byte_len()
346
+ if el_byte_len is None:
347
+ return None
348
+ total_bits = _round_bits_to_nearest_byte(total_bits) + el_byte_len * 8
349
+ if self._homogenous_element:
350
+ total_bits *= len(self.elements)
351
+ break
352
+ return _bits_to_byte(total_bits)
353
+
354
+ @cached_property
355
+ def _homogenous_element(self) -> ABIType | None:
356
+ if isinstance(self.elements, _RepeatedSequence):
357
+ return self.elements.element
358
+ elif len({e.name for e in self.elements}) == 1:
359
+ return next(iter(self.elements))
360
+ else:
361
+ return None
362
+
363
+ @cached_property
364
+ def _head_num_bytes(self) -> int:
365
+ num_bits = 0
366
+ for element in self.elements:
367
+ if _is_bool(element):
368
+ num_bits += 1
369
+ else:
370
+ num_bits = _round_bits_to_nearest_byte(num_bits)
371
+ el_byte_len = element.byte_len()
372
+ if el_byte_len is None:
373
+ el_byte_len = _U16_NUM_BYTES
374
+ num_bits += el_byte_len * 8
375
+ if self._homogenous_element:
376
+ num_bits *= len(self.elements)
377
+ break
378
+ return _bits_to_byte(num_bits)
379
+
380
+ def encode(self, value: Sequence | bytes | bytearray) -> bytes:
381
+ if len(value) != len(self.elements):
382
+ raise ValueError(f"expected {len(self.elements)} elements: {_error_str(value)}")
383
+ if _is_byte(self._homogenous_element):
384
+ return bytes(value)
385
+ head = bytearray()
386
+ tail = bytearray()
387
+ bit_index = 0
388
+ tail_offset = self._head_num_bytes
389
+ for el, el_type in zip(value, self.elements, strict=True):
390
+ # there are 3 kinds of elements to consider when encoding a tuple
391
+ # 1. bool, these require packing consecutive values into a byte in the head
392
+ # 2. dynamically sized types, these require a pointer in the head and the actual data in the tail
393
+ # 3. statically sized types, these are stored directly in the head
394
+ if _is_bool(el_type):
395
+ # append a new value if start of a new byte
396
+ if bit_index % 8 == 0:
397
+ head.append(0)
398
+ if el is True:
399
+ head[-1] = _set_bit(head[-1], bit_index % 8)
400
+ elif el is False:
401
+ pass
402
+ else:
403
+ raise ValueError("expected bool")
404
+ bit_index += 1
405
+ else:
406
+ bit_index = 0
407
+ el_bytes = el_type.encode(el)
408
+ if el_type.is_dynamic():
409
+ try:
410
+ head.extend(_int_to_u16_bytes(tail_offset))
411
+ except OverflowError:
412
+ raise ValueError(f"encoded bytes length exceeds {_MAX_U16}") from None
413
+ tail_offset += len(el_bytes)
414
+ tail.extend(el_bytes)
415
+ else:
416
+ head.extend(el_bytes)
417
+ return bytes((*head, *tail))
418
+
419
+ @cached_property
420
+ def _tuple_head_offsets(self) -> Mapping[int, int]:
421
+ offsets = {}
422
+ num_bits = 0
423
+ for idx, element in enumerate(self.elements):
424
+ if element.is_dynamic():
425
+ offsets[idx] = _bits_to_byte(num_bits)
426
+ if _is_bool(element):
427
+ num_bits += 1
428
+ else:
429
+ num_bits = _round_bits_to_nearest_byte(num_bits)
430
+ el_byte_len = element.byte_len()
431
+ if el_byte_len is None:
432
+ el_byte_len = _U16_NUM_BYTES
433
+ num_bits += el_byte_len * 8
434
+ return offsets
435
+
436
+ def _get_next_dynamic_head_offset(self, index: int, value: memoryview) -> int | None:
437
+ # the last element reads to end
438
+ if index == len(self.elements) - 1:
439
+ return None
440
+ if self._homogenous_element:
441
+ assert self._homogenous_element.is_dynamic()
442
+ next_head_offset = _U16_NUM_BYTES * (index + 1)
443
+ else:
444
+ for idx in range(index + 1, len(self.elements)):
445
+ try:
446
+ next_head_offset = self._tuple_head_offsets[idx]
447
+ except KeyError:
448
+ continue
449
+ else:
450
+ break
451
+ else:
452
+ return None
453
+ return _u16_bytes_to_int(value[next_head_offset : next_head_offset + _U16_NUM_BYTES])
454
+
455
+ def decode(self, value: BytesLike) -> tuple | bytes:
456
+ self._check_num_bytes(value)
457
+ if _is_byte(self._homogenous_element):
458
+ return bytes(value)
459
+
460
+ value = memoryview(value)
461
+ result = []
462
+ head_offset = 0
463
+ bit_index = 0
464
+ expected_tail_offset = self._head_num_bytes
465
+ for el_idx, el_type in enumerate(self.elements):
466
+ if _is_bool(el_type):
467
+ current_byte = value[head_offset + bit_index // 8]
468
+ bool_value = _get_bit(current_byte, bit_index % 8)
469
+ result.append(bool_value)
470
+ bit_index += 1
471
+ else:
472
+ head_offset += _bits_to_byte(bit_index)
473
+ bit_index = 0
474
+ el_byte_len = el_type.byte_len()
475
+ if el_byte_len is None:
476
+ el_offset = _u16_bytes_to_int(value[head_offset : head_offset + _U16_NUM_BYTES])
477
+ if el_offset != expected_tail_offset:
478
+ raise ValueError(f"expected tail offset of {expected_tail_offset} got: {el_offset}")
479
+ head_offset += _U16_NUM_BYTES
480
+ next_el_offset = self._get_next_dynamic_head_offset(el_idx, value)
481
+ el_bytes = value[el_offset:next_el_offset]
482
+ expected_tail_offset += len(el_bytes)
483
+ result.append(el_type.decode(el_bytes))
484
+ else:
485
+ result.append(el_type.decode(value[head_offset : head_offset + el_byte_len]))
486
+ head_offset += el_byte_len
487
+ if self.is_dynamic() and expected_tail_offset != len(value):
488
+ raise ValueError(f"expected {expected_tail_offset} bytes for {self.display_name}, got {len(value)} bytes")
489
+ return tuple(result)
490
+
491
+
492
+ @typing.final
493
+ @dataclasses.dataclass(frozen=True, kw_only=True)
494
+ class StructType(ABIType):
495
+ struct_name: str
496
+ fields: Mapping[str, ABIType]
497
+ decode_type: type = dataclasses.field(default=dict)
498
+
499
+ @property
500
+ def display_name(self) -> str:
501
+ return self.struct_name
502
+
503
+ @cached_property
504
+ def name(self) -> str:
505
+ return self._tuple_type.name
506
+
507
+ @cached_property
508
+ def _tuple_type(self) -> TupleType:
509
+ return TupleType(elements=tuple(self.fields.values()))
510
+
511
+ def byte_len(self) -> int | None:
512
+ return self._tuple_type.byte_len()
513
+
514
+ def encode(self, value: dict[str, typing.Any] | tuple | object) -> bytes:
515
+ if isinstance(value, dict): # structs as a dictionary mapped by field name
516
+ field_values = tuple(value[field_name] for field_name in self.fields)
517
+ elif isinstance(value, tuple): # structs that have already been converted to a tuple
518
+ field_values = value
519
+ else: # objects with struct field names
520
+ field_values = tuple(getattr(value, field_name) for field_name in self.fields)
521
+ return self._tuple_type.encode(field_values)
522
+
523
+ def decode(self, value: BytesLike) -> typing.Any: # noqa: ANN401
524
+ field_values = self._tuple_type.decode(value)
525
+ fields = dict(zip(self.fields, field_values, strict=True))
526
+ return self.decode_type(**fields)
527
+
528
+ def __hash__(self) -> int:
529
+ return hash(self.display_name)
530
+
531
+ def __eq__(self, other: object) -> bool:
532
+ if not isinstance(other, StructType):
533
+ return False
534
+ return (
535
+ self.display_name == other.display_name
536
+ and self.fields.keys() == other.fields.keys()
537
+ and self._tuple_type == other._tuple_type
538
+ )
539
+
540
+
541
+ @typing.final
542
+ @dataclasses.dataclass(frozen=True)
543
+ class StringType(ABIType):
544
+ _array_type: DynamicArrayType = dataclasses.field(default=DynamicArrayType(element=ByteType()), init=False)
545
+
546
+ @property
547
+ def name(self) -> str:
548
+ return "string"
549
+
550
+ def byte_len(self) -> None:
551
+ return None
552
+
553
+ def encode(self, value: str) -> bytes:
554
+ if not isinstance(value, str):
555
+ raise TypeError("expected str")
556
+ return self._array_type.encode(value.encode("utf-8"))
557
+
558
+ def decode(self, value: BytesLike) -> str:
559
+ bytes_ = self._array_type.decode(value)
560
+ assert isinstance(bytes_, bytes)
561
+ return bytes_.decode("utf-8")
562
+
563
+
564
+ @typing.final
565
+ @dataclasses.dataclass(frozen=True)
566
+ class AddressType(ABIType):
567
+ _array_type: StaticArrayType = dataclasses.field(default=StaticArrayType(element=ByteType(), size=32), init=False)
568
+
569
+ @property
570
+ def name(self) -> str:
571
+ return "address"
572
+
573
+ def byte_len(self) -> int | None:
574
+ return self._array_type.byte_len()
575
+
576
+ def encode(self, value: str | bytes | bytearray) -> bytes:
577
+ if isinstance(value, str):
578
+ value = public_key_from_address(value)
579
+ return self._array_type.encode(value)
580
+
581
+ def decode(self, value: BytesLike) -> str:
582
+ public_key = self._array_type.decode(value)
583
+ assert isinstance(public_key, bytes)
584
+ return address_from_public_key(public_key)
585
+
586
+
587
+ def _is_bool(typ: ABIType | None) -> bool:
588
+ return type(typ) is BoolType
589
+
590
+
591
+ def _is_byte(typ: ABIType | None) -> bool:
592
+ return type(typ) is ByteType
593
+
594
+
595
+ _COMMON_TYPES = {
596
+ **{f"uint{n}": UintType(n) for n in range(8, _MAX_UINT_N + 1, 8)},
597
+ "byte": ByteType(),
598
+ "bool": BoolType(),
599
+ "address": AddressType(),
600
+ "string": StringType(),
601
+ }
602
+
603
+
604
+ def split_tuple_str(s: str) -> Iterator[str]:
605
+ """
606
+ Split a well-formed tuple into it's top level elements
607
+
608
+ e.g. "(uint64,(bool,uint8),uint32)"
609
+ """
610
+ if not s:
611
+ return
612
+
613
+ if s.startswith(",") or s.endswith(","):
614
+ raise ValueError(f"cannot have leading or trailing commas in ({s})")
615
+
616
+ depth = 0
617
+ current_element = ""
618
+ for char in s:
619
+ if char == "(":
620
+ depth += 1
621
+ elif char == ")":
622
+ depth -= 1
623
+ elif char == "," and depth == 0:
624
+ # yield only top level tuple elements, nested elements will be recursively parsed
625
+ if not current_element:
626
+ raise ValueError(f"commas must follow a tuple element: ({s})")
627
+ yield current_element
628
+ current_element = ""
629
+ continue
630
+ current_element += char
631
+ if current_element:
632
+ yield current_element
633
+ if depth != 0:
634
+ raise ValueError(f"parenthesis mismatch: ({s})")
635
+
636
+
637
+ def _set_bit(value: int, bit_index: int) -> int:
638
+ return value | (_ABI_BOOL_TRUE_UINT >> bit_index)
639
+
640
+
641
+ def _get_bit(value: int, bit_index: int) -> bool:
642
+ return (value & (_ABI_BOOL_TRUE_UINT >> bit_index)) != 0
643
+
644
+
645
+ def _int_to_u16_bytes(value: int) -> bytes:
646
+ return value.to_bytes(length=_U16_NUM_BYTES, byteorder="big", signed=False)
647
+
648
+
649
+ def _u16_bytes_to_int(value: memoryview) -> int:
650
+ if value.nbytes != _U16_NUM_BYTES:
651
+ raise ValueError("expected uint16 bytes")
652
+ return int.from_bytes(value, byteorder="big", signed=False)
653
+
654
+
655
+ def _bits_to_byte(bits: int) -> int:
656
+ return (bits + 7) // 8
657
+
658
+
659
+ def _round_bits_to_nearest_byte(bits: int) -> int:
660
+ return _bits_to_byte(bits) * 8
661
+
662
+
663
+ def _error_str(value: object) -> str:
664
+ if isinstance(value, bytes | bytearray | memoryview):
665
+ return f"0x{value.hex()}"
666
+ else:
667
+ return str(value)