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,610 @@
1
+ import builtins
2
+ import sys
3
+ import types
4
+ from collections.abc import Callable, Mapping
5
+ from dataclasses import dataclass, fields, is_dataclass
6
+ from enum import Enum
7
+ from typing import TypeVar, Union, cast, get_args, get_origin, get_type_hints
8
+
9
+ from algokit_common import address_from_public_key, public_key_from_address
10
+ from algokit_common.serde._primitives import (
11
+ decode_int_like,
12
+ encode_bool,
13
+ encode_int,
14
+ omit_defaults_and_sort,
15
+ sort_msgpack_value,
16
+ )
17
+
18
+ __all__ = [
19
+ "DecodeError",
20
+ "EncodeError",
21
+ "addr",
22
+ "addr_seq",
23
+ "bytes_seq",
24
+ "enum_value",
25
+ "flatten",
26
+ "from_wire",
27
+ "int_seq",
28
+ "nested",
29
+ "sort_msgpack_value",
30
+ "to_wire",
31
+ "to_wire_canonical",
32
+ "wire",
33
+ ]
34
+
35
+
36
+ DecodedValueT = TypeVar("DecodedValueT")
37
+
38
+
39
+ class EncodeError(ValueError):
40
+ pass
41
+
42
+
43
+ class DecodeError(ValueError):
44
+ pass
45
+
46
+
47
+ # Metadata helpers
48
+ def wire(
49
+ alias: str,
50
+ *,
51
+ encode: Callable[..., object] | None = None,
52
+ decode: Callable[..., object] | type | None = None,
53
+ omit_if_none: bool = True,
54
+ keep_zero: bool = False,
55
+ keep_false: bool = False,
56
+ omit_empty_seq: bool = True,
57
+ required: bool = False,
58
+ pass_obj: bool = False,
59
+ ) -> dict[str, object]:
60
+ return {
61
+ "kind": "wire",
62
+ "alias": alias,
63
+ "encode": encode,
64
+ "decode": decode,
65
+ "omit_if_none": omit_if_none,
66
+ "keep_zero": keep_zero,
67
+ "keep_false": keep_false,
68
+ "omit_empty_seq": omit_empty_seq,
69
+ "required": required,
70
+ "pass_obj": pass_obj,
71
+ }
72
+
73
+
74
+ ChildType = type[object] | Callable[[], type[object]] | None
75
+
76
+
77
+ def _expects_text_value(type_hint: object) -> bool:
78
+ if isinstance(type_hint, type) and issubclass(type_hint, Enum):
79
+ return True
80
+ if type_hint is str:
81
+ return True
82
+ origin = get_origin(type_hint)
83
+ if origin is None:
84
+ return False
85
+ if origin is str:
86
+ return True
87
+ if origin in (list, tuple, set, frozenset, dict):
88
+ return False
89
+ args = [arg for arg in get_args(type_hint) if arg is not type(None)]
90
+ return any(_expects_text_value(arg) for arg in args)
91
+
92
+
93
+ def flatten(
94
+ child_cls: ChildType,
95
+ *,
96
+ present_if: Callable[[Mapping[str, object]], bool] | None = None,
97
+ ) -> dict[str, object]:
98
+ return {"kind": "flatten", "child_cls": child_cls, "present_if": present_if}
99
+
100
+
101
+ def nested(
102
+ alias: str,
103
+ child_cls: ChildType,
104
+ *,
105
+ present_if: Callable[[Mapping[str, object]], bool] | None = None,
106
+ omit_empty_seq: bool = True,
107
+ required: bool = False,
108
+ ) -> dict[str, object]:
109
+ return {
110
+ "kind": "nested",
111
+ "alias": alias,
112
+ "child_cls": child_cls,
113
+ "present_if": present_if,
114
+ "omit_empty_seq": omit_empty_seq,
115
+ "required": required,
116
+ }
117
+
118
+
119
+ @dataclass(slots=True)
120
+ class _FieldHandler:
121
+ name: str
122
+ alias: str | None
123
+ encode_fn: Callable[..., object] | None
124
+ decode_fn: Callable[[object], object] | type | None
125
+ omit_if_none: bool
126
+ keep_zero: bool
127
+ keep_false: bool
128
+ omit_empty_seq: bool
129
+ required: bool
130
+ kind: str
131
+ child_cls: ChildType
132
+ nested_alias: str | None
133
+ present_if: Callable[[Mapping[str, object]], bool] | None = None
134
+ pass_obj: bool = False
135
+ expects_text: bool = False
136
+ nested_required: bool = False # For nested fields: whether they are required
137
+
138
+
139
+ class _SerdePlan:
140
+ __slots__ = ("cls", "fields")
141
+
142
+ def __init__(self, cls: type[object], handlers: list[_FieldHandler]) -> None:
143
+ self.cls = cls
144
+ self.fields = handlers
145
+
146
+
147
+ _SERDE_CACHE: dict[type[object], _SerdePlan] = {}
148
+
149
+
150
+ def _get_dataclass(typ: type) -> type | None:
151
+ if get_origin(typ) in {Union, types.UnionType}:
152
+ typs = set(get_args(typ))
153
+ else:
154
+ typs = {typ}
155
+ typs = typs - {types.NoneType}
156
+ try:
157
+ (maybe_dataclass,) = typs
158
+ except ValueError:
159
+ return None
160
+ if is_dataclass(maybe_dataclass):
161
+ return cast(type, maybe_dataclass)
162
+ else:
163
+ return None
164
+
165
+
166
+ def _compile_plan(cls: type[object]) -> _SerdePlan:
167
+ if not is_dataclass(cls):
168
+ raise TypeError(f"{cls!r} is not a dataclass")
169
+ handlers: list[_FieldHandler] = []
170
+ # Use explicit globalns with builtins and empty localns to avoid issues with
171
+ # dataclass fields that shadow builtin names (e.g. 'bytes', 'type').
172
+ # When slots=True, the class namespace contains member descriptors that can
173
+ # interfere with type hint evaluation.
174
+ module = sys.modules.get(cls.__module__, None)
175
+ globalns = {**vars(builtins), **(vars(module) if module else {})}
176
+ cls_type_hints = get_type_hints(cls, globalns=globalns, localns={})
177
+ for f in fields(cls):
178
+ meta = dict(f.metadata or {})
179
+ field_type = cls_type_hints[f.name]
180
+ maybe_dataclass = _get_dataclass(field_type)
181
+ if maybe_dataclass and not meta:
182
+ kind = "nested"
183
+ meta = {"child_cls": maybe_dataclass, "alias": f.name, "omit_if_none": True}
184
+ else:
185
+ kind = cast(str | None, meta.get("kind")) or "wire"
186
+ if kind not in ("wire", "flatten", "nested"):
187
+ kind = "wire"
188
+
189
+ if kind == "wire":
190
+ handlers.append(
191
+ _FieldHandler(
192
+ name=f.name,
193
+ alias=cast(str | None, meta.get("alias", f.name)),
194
+ encode_fn=cast(Callable[..., object] | None, meta.get("encode")),
195
+ decode_fn=cast(Callable[[object], object] | type | None, meta.get("decode")),
196
+ omit_if_none=bool(meta.get("omit_if_none", True)),
197
+ keep_zero=bool(meta.get("keep_zero", False)),
198
+ keep_false=bool(meta.get("keep_false", False)),
199
+ omit_empty_seq=bool(meta.get("omit_empty_seq", True)),
200
+ required=bool(meta.get("required", False)),
201
+ kind=kind,
202
+ child_cls=None,
203
+ nested_alias=None,
204
+ pass_obj=bool(meta.get("pass_obj", False)),
205
+ expects_text=_expects_text_value(field_type),
206
+ )
207
+ )
208
+ elif kind == "nested":
209
+ handlers.append(
210
+ _FieldHandler(
211
+ name=f.name,
212
+ alias=None,
213
+ encode_fn=None,
214
+ decode_fn=None,
215
+ omit_if_none=True,
216
+ keep_zero=False,
217
+ keep_false=False,
218
+ omit_empty_seq=meta.get("omit_empty_seq", True),
219
+ required=False,
220
+ kind=kind,
221
+ child_cls=cast(type[object] | None, meta.get("child_cls")),
222
+ nested_alias=cast(str | None, meta.get("alias")),
223
+ present_if=cast(Callable[[Mapping[str, object]], bool] | None, meta.get("present_if")),
224
+ nested_required=bool(meta.get("required", False)),
225
+ )
226
+ )
227
+ else: # flatten
228
+ handlers.append(
229
+ _FieldHandler(
230
+ name=f.name,
231
+ alias=None,
232
+ encode_fn=None,
233
+ decode_fn=None,
234
+ omit_if_none=True,
235
+ keep_zero=False,
236
+ keep_false=False,
237
+ omit_empty_seq=True,
238
+ required=False,
239
+ kind=kind,
240
+ child_cls=cast(type[object] | None, meta.get("child_cls")),
241
+ nested_alias=None,
242
+ present_if=cast(Callable[[Mapping[str, object]], bool] | None, meta.get("present_if")),
243
+ )
244
+ )
245
+
246
+ plan = _SerdePlan(cls, handlers)
247
+ _SERDE_CACHE[cls] = plan
248
+ return plan
249
+
250
+
251
+ def _plan_for(cls: type[object]) -> _SerdePlan:
252
+ return _SERDE_CACHE.get(cls) or _compile_plan(cls)
253
+
254
+
255
+ # Cache for default instances to avoid repeated construction
256
+ _DEFAULT_INSTANCE_CACHE: dict[type[object], object] = {}
257
+
258
+
259
+ def _construct_default_instance(cls: type[object]) -> object:
260
+ """Construct a default instance of a dataclass with all required fields set to defaults.
261
+
262
+ This mirrors TypeScript's ObjectModelCodec.defaultValue() behavior:
263
+ - Required primitive fields get type-appropriate defaults (0, "", False, b"", etc.)
264
+ - Required nested object fields get recursively constructed default instances
265
+ - Optional fields are not set (they use their dataclass defaults, typically None)
266
+
267
+ The result is cached for performance.
268
+ """
269
+ if cls in _DEFAULT_INSTANCE_CACHE:
270
+ return _DEFAULT_INSTANCE_CACHE[cls]
271
+
272
+ if not is_dataclass(cls):
273
+ raise TypeError(f"{cls!r} is not a dataclass")
274
+
275
+ plan = _plan_for(cls)
276
+ kwargs: dict[str, object] = {}
277
+
278
+ for h in plan.fields:
279
+ if h.kind == "wire":
280
+ # For wire fields, check if it has a default in the dataclass
281
+ # If not, we need to provide a default value for required primitives
282
+ # The dataclass defaults should already handle this via generator
283
+ pass
284
+ elif h.kind == "nested" and h.nested_required:
285
+ # Required nested fields need default instances
286
+ child_cls = _resolve_child_cls(h)
287
+ if child_cls is not None:
288
+ kwargs[h.name] = _construct_default_instance(child_cls)
289
+ # flatten and optional nested fields are not populated
290
+
291
+ # Create instance - dataclass defaults will fill in primitive defaults
292
+ try:
293
+ instance = cls(**kwargs)
294
+ except TypeError as exc:
295
+ raise DecodeError(f"Failed to construct default instance of {cls.__name__}: {exc}") from exc
296
+
297
+ _DEFAULT_INSTANCE_CACHE[cls] = instance
298
+ return instance
299
+
300
+
301
+ def _encode_scalar(value: object, *, keep_zero: bool, keep_false: bool) -> object | None:
302
+ if value is None:
303
+ return None
304
+ if isinstance(value, bool):
305
+ return value if keep_false else encode_bool(value)
306
+ if isinstance(value, int):
307
+ return encode_int(value, keep_zero=keep_zero)
308
+ if isinstance(value, bytes | bytearray | memoryview):
309
+ return bytes(value) if isinstance(value, bytearray | memoryview) else value
310
+ return value
311
+
312
+
313
+ def _resolve_child_cls(h: _FieldHandler) -> type[object] | None:
314
+ child = h.child_cls
315
+ if child is None:
316
+ return None
317
+ if isinstance(child, type):
318
+ return child
319
+ return child()
320
+
321
+
322
+ def _encode_nested_field(out: dict[str, object], obj: object, h: _FieldHandler) -> None:
323
+ if (value := getattr(obj, h.name)) is None:
324
+ return
325
+ if not (nested_payload := to_wire(value)) and h.omit_empty_seq:
326
+ return
327
+ if h.nested_alias is None:
328
+ raise EncodeError(f"Missing nested alias for field {h.name!r}")
329
+ out[h.nested_alias] = nested_payload
330
+
331
+
332
+ def _encode_flatten_field(out: dict[str, object], obj: object, h: _FieldHandler) -> None:
333
+ if (value := getattr(obj, h.name)) is None:
334
+ return
335
+ if child_payload := to_wire(value):
336
+ out.update(child_payload)
337
+
338
+
339
+ def _encode_wire_field(out: dict[str, object], obj: object, h: _FieldHandler) -> None:
340
+ if not h.alias:
341
+ return
342
+ value = getattr(obj, h.name)
343
+ if value is None:
344
+ if h.required:
345
+ raise EncodeError(f"Field {h.name!r} is required but None")
346
+ if h.omit_if_none:
347
+ return
348
+ _set_path(out, h.alias, None)
349
+ return
350
+
351
+ if h.encode_fn is not None:
352
+ encoded = h.encode_fn(obj, value) if h.pass_obj else h.encode_fn(value)
353
+ else:
354
+ encoded = _encode_scalar(value, keep_zero=h.keep_zero, keep_false=h.keep_false)
355
+
356
+ if h.omit_empty_seq and isinstance(encoded, list | tuple) and not encoded:
357
+ return
358
+ if encoded is None and h.omit_if_none:
359
+ return
360
+ _set_path(out, h.alias, encoded)
361
+
362
+
363
+ def to_wire(obj: object) -> dict[str, object]:
364
+ """Encode a dataclass instance to a wire-ready dict using field metadata."""
365
+ plan = _plan_for(obj.__class__)
366
+ out: dict[str, object] = {}
367
+ for h in plan.fields:
368
+ if h.kind == "nested":
369
+ _encode_nested_field(out, obj, h)
370
+ elif h.kind == "flatten":
371
+ _encode_flatten_field(out, obj, h)
372
+ elif h.kind == "wire":
373
+ _encode_wire_field(out, obj, h)
374
+ return out
375
+
376
+
377
+ def to_wire_canonical(obj: object) -> dict[str, object]:
378
+ """Return canonical, ready-to-msgpack dict (omit defaults and sort keys)."""
379
+ return cast(dict[str, object], omit_defaults_and_sort(dict(to_wire(obj))))
380
+
381
+
382
+ def _decode_with_hint(raw: object, decode_fn: Callable[[object], object] | type | None) -> object:
383
+ if decode_fn is None:
384
+ if isinstance(raw, bytes | bytearray):
385
+ return bytes(raw)
386
+ if isinstance(raw, int):
387
+ return decode_int_like(raw)
388
+ return raw
389
+
390
+ if isinstance(decode_fn, type):
391
+ try:
392
+ return cast("Callable[[object], object]", decode_fn)(raw)
393
+ except Exception as exc:
394
+ raise DecodeError(f"Failed to construct {decode_fn.__name__} from {raw!r}") from exc
395
+
396
+ return decode_fn(raw)
397
+
398
+
399
+ def _wire_aliases_for(cls: type[object]) -> frozenset[str]:
400
+ plan = _plan_for(cls)
401
+ aliases = {h.alias for h in plan.fields if h.kind == "wire" and h.alias}
402
+ aliases.update(h.nested_alias for h in plan.fields if h.kind == "nested" and h.nested_alias)
403
+ # For flattened fields, recursively collect wire aliases from child classes
404
+ for h in plan.fields:
405
+ if h.kind == "flatten":
406
+ child_cls = _resolve_child_cls(h)
407
+ if child_cls is not None:
408
+ aliases.update(_wire_aliases_for(child_cls))
409
+ return frozenset(aliases)
410
+
411
+
412
+ def _decode_wire_field(kwargs: dict[str, object], h: _FieldHandler, payload: Mapping[str, object]) -> None:
413
+ if not (alias := h.alias):
414
+ return
415
+ if not _has_path(payload, alias):
416
+ return
417
+ if (raw := _get_path(payload, alias)) is None:
418
+ if h.required:
419
+ raise DecodeError(f"Missing required field {h.name!r} (alias {alias!r})")
420
+ kwargs[h.name] = None
421
+ return
422
+ value = raw
423
+ needs_text = bool(
424
+ h.expects_text and (h.decode_fn is None or (isinstance(h.decode_fn, type) and issubclass(h.decode_fn, Enum)))
425
+ )
426
+ if needs_text and isinstance(value, bytes | bytearray | memoryview):
427
+ raw_bytes = bytes(value)
428
+ try:
429
+ value = raw_bytes.decode("utf-8")
430
+ except UnicodeDecodeError:
431
+ # Some Algorand fields legitimately carry printable data inside binary slots.
432
+ value = raw_bytes
433
+ kwargs[h.name] = _decode_with_hint(value, h.decode_fn)
434
+
435
+
436
+ def _decode_nested_field(kwargs: dict[str, object], h: _FieldHandler, payload: Mapping[str, object]) -> None:
437
+ child_cls = _resolve_child_cls(h)
438
+ if child_cls is None or h.nested_alias is None:
439
+ kwargs[h.name] = None
440
+ return
441
+ if isinstance(raw_nested := payload.get(h.nested_alias), Mapping):
442
+ kwargs[h.name] = from_wire(child_cls, raw_nested)
443
+ return
444
+ # Field is missing or not a Mapping - check if it's required
445
+ if h.nested_required:
446
+ # Required nested fields get a default instance (mirrors TS ObjectModelCodec.defaultValue())
447
+ kwargs[h.name] = _construct_default_instance(child_cls)
448
+ return
449
+ if not h.omit_if_none:
450
+ kwargs[h.name] = None
451
+
452
+
453
+ def _decode_flatten_field(kwargs: dict[str, object], h: _FieldHandler, payload: Mapping[str, object]) -> None:
454
+ child_cls = _resolve_child_cls(h)
455
+ if child_cls is None:
456
+ kwargs[h.name] = None
457
+ return
458
+ alias_set = _wire_aliases_for(child_cls)
459
+ has_any = any(_has_path(payload, k) for k in alias_set)
460
+ # If present_if is provided, it takes precedence over the wire alias check.
461
+ # This is important for transaction types where the same wire keys (e.g., 'amt', 'rcv')
462
+ # could be present but the type field indicates a different transaction type.
463
+ if h.present_if is not None:
464
+ if not h.present_if(payload):
465
+ kwargs[h.name] = None
466
+ return
467
+ elif not has_any:
468
+ kwargs[h.name] = None
469
+ return
470
+ sub: dict[str, object] = {}
471
+ for key in alias_set:
472
+ if _has_path(payload, key):
473
+ _set_path(sub, key, _get_path(payload, key))
474
+ kwargs[h.name] = from_wire(child_cls, sub)
475
+
476
+
477
+ def _set_path(target: dict[str, object], path: str, value: object) -> None:
478
+ if "." not in path:
479
+ target[path] = value
480
+ return
481
+ parts = path.split(".")
482
+ cur = target
483
+ for key in parts[:-1]:
484
+ if not isinstance(nxt := cur.get(key), dict):
485
+ nxt = {}
486
+ cur[key] = nxt
487
+ cur = nxt
488
+ cur[parts[-1]] = value
489
+
490
+
491
+ def _get_path(source: Mapping[str, object], path: str) -> object | None:
492
+ if "." not in path:
493
+ return source.get(path)
494
+ cur: object = source
495
+ for key in path.split("."):
496
+ if not isinstance(cur, Mapping) or (cur := cur.get(key)) is None:
497
+ return None
498
+ return cur
499
+
500
+
501
+ def _has_path(source: Mapping[str, object], path: str) -> bool:
502
+ if "." not in path:
503
+ return path in source
504
+ cur: object = source
505
+ for key in path.split("."):
506
+ if not isinstance(cur, Mapping) or key not in cur:
507
+ return False
508
+ cur = cur[key]
509
+ return True
510
+
511
+
512
+ def from_wire(cls: type[DecodedValueT], payload: Mapping[str, object]) -> DecodedValueT:
513
+ """Decode a wire dict into a dataclass instance using field metadata."""
514
+ plan = _plan_for(cls)
515
+ kwargs: dict[str, object] = {}
516
+ for h in plan.fields:
517
+ if h.kind == "wire":
518
+ _decode_wire_field(kwargs, h, payload)
519
+ elif h.kind == "nested":
520
+ _decode_nested_field(kwargs, h, payload)
521
+ elif h.kind == "flatten":
522
+ _decode_flatten_field(kwargs, h, payload)
523
+ try:
524
+ return cast(DecodedValueT, plan.cls(**kwargs))
525
+ except TypeError as exc:
526
+ raise DecodeError(f"Failed to construct {plan.cls.__name__}: {exc}") from exc
527
+
528
+
529
+ def addr(alias: str, *, omit_if_none: bool = True) -> dict[str, object]:
530
+ """Typed helper for address fields (str <-> bytes)."""
531
+ return wire(
532
+ alias,
533
+ encode=lambda v: public_key_from_address(cast(str, v)),
534
+ decode=lambda v: address_from_public_key(cast(bytes, v)),
535
+ omit_if_none=omit_if_none,
536
+ )
537
+
538
+
539
+ E = TypeVar("E", bound=Enum)
540
+
541
+
542
+ def enum_value(alias: str, enum_type: type[E], *, fallback: E | None = None) -> dict[str, object]:
543
+ """Typed helper for Enum fields that serialize via their .value.
544
+
545
+ Args:
546
+ alias: The wire format key name
547
+ enum_type: The Enum class to encode/decode
548
+ fallback: Optional fallback value to use when decoding an unknown value.
549
+ If not provided, decoding unknown values will raise DecodeError.
550
+ This is useful for forward-compatibility when new enum values may
551
+ be added in the future (e.g., new transaction types).
552
+ """
553
+
554
+ def _decode(value: object) -> E:
555
+ # Normalize bytes to str (msgpack may return string values as bytes)
556
+ if isinstance(value, bytes | bytearray | memoryview):
557
+ value = bytes(value).decode("utf-8")
558
+ try:
559
+ return enum_type(value)
560
+ except ValueError:
561
+ if fallback is not None:
562
+ return fallback
563
+ raise
564
+
565
+ return wire(alias, encode=lambda e: e.value if isinstance(e, enum_type) else e, decode=_decode)
566
+
567
+
568
+ def bytes_seq(alias: str, *, omit_if_none: bool = True) -> dict[str, object]:
569
+ def _enc(value: object) -> object:
570
+ if value is None or not isinstance(value, tuple | list):
571
+ return None
572
+ out = [bytes(item) for item in value if isinstance(item, bytes | bytearray | memoryview)]
573
+ return out or None
574
+
575
+ def _dec(value: object) -> object:
576
+ if not isinstance(value, list):
577
+ return value
578
+ return tuple(bytes(item) for item in value if isinstance(item, bytes | bytearray | memoryview))
579
+
580
+ return wire(alias, encode=_enc, decode=_dec, omit_if_none=omit_if_none)
581
+
582
+
583
+ def int_seq(alias: str, *, omit_if_none: bool = True) -> dict[str, object]:
584
+ def _enc(value: object) -> object:
585
+ if value is None or not isinstance(value, tuple | list):
586
+ return None
587
+ out = [int(item) for item in value if isinstance(item, int)]
588
+ return out or None
589
+
590
+ def _dec(value: object) -> object:
591
+ if not isinstance(value, list):
592
+ return value
593
+ return tuple(int(item) for item in value if isinstance(item, int))
594
+
595
+ return wire(alias, encode=_enc, decode=_dec, omit_if_none=omit_if_none)
596
+
597
+
598
+ def addr_seq(alias: str, *, omit_if_none: bool = True) -> dict[str, object]:
599
+ def _enc(value: object) -> object:
600
+ if value is None or not isinstance(value, tuple | list):
601
+ return None
602
+ out = [public_key_from_address(cast(str, item)) for item in value]
603
+ return out or None
604
+
605
+ def _dec(value: object) -> object:
606
+ if not isinstance(value, list):
607
+ return value
608
+ return tuple(address_from_public_key(bytes(item)) for item in value if isinstance(item, bytes | bytearray))
609
+
610
+ return wire(alias, encode=_enc, decode=_dec, omit_if_none=omit_if_none)