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,503 @@
1
+ from collections.abc import Mapping
2
+ from dataclasses import dataclass
3
+ from enum import Enum
4
+
5
+ from algokit_common.constants import (
6
+ MAX_ACCOUNT_REFERENCES,
7
+ MAX_APP_ARGS,
8
+ MAX_APP_REFERENCES,
9
+ MAX_ARGS_SIZE,
10
+ MAX_ASSET_DECIMALS,
11
+ MAX_ASSET_NAME_LENGTH,
12
+ MAX_ASSET_REFERENCES,
13
+ MAX_ASSET_UNIT_NAME_LENGTH,
14
+ MAX_ASSET_URL_LENGTH,
15
+ MAX_BOX_REFERENCES,
16
+ MAX_EXTRA_PROGRAM_PAGES,
17
+ MAX_GLOBAL_STATE_KEYS,
18
+ MAX_LOCAL_STATE_KEYS,
19
+ MAX_OVERALL_REFERENCES,
20
+ PROGRAM_PAGE_SIZE,
21
+ )
22
+ from algokit_transact.exceptions import TransactionValidationError
23
+ from algokit_transact.models.app_call import AppCallTransactionFields
24
+ from algokit_transact.models.asset_config import AssetConfigTransactionFields
25
+ from algokit_transact.models.asset_freeze import AssetFreezeTransactionFields
26
+ from algokit_transact.models.asset_transfer import AssetTransferTransactionFields
27
+ from algokit_transact.models.common import OnApplicationComplete
28
+ from algokit_transact.models.key_registration import KeyRegistrationTransactionFields
29
+ from algokit_transact.models.transaction import Transaction
30
+
31
+
32
+ class ValidationIssueCode(Enum):
33
+ REQUIRED_FIELD = "required_field"
34
+ FIELD_TOO_LONG = "field_too_long"
35
+ IMMUTABLE_FIELD = "immutable_field"
36
+ ZERO_VALUE_FIELD = "zero_value_field"
37
+ ARBITRARY_CONSTRAINT = "arbitrary_constraint"
38
+
39
+
40
+ @dataclass(slots=True, frozen=True)
41
+ class ValidationIssue:
42
+ code: ValidationIssueCode
43
+ message: str
44
+ field: str | None = None
45
+ context: Mapping[str, object] | None = None
46
+
47
+
48
+ def _issue(
49
+ code: ValidationIssueCode,
50
+ message: str,
51
+ *,
52
+ field: str | None = None,
53
+ context: Mapping[str, object] | None = None,
54
+ ) -> ValidationIssue:
55
+ return ValidationIssue(code=code, message=message, field=field, context=context)
56
+
57
+
58
+ def validate_transaction(transaction: Transaction) -> None:
59
+ if not transaction.sender:
60
+ raise TransactionValidationError("Transaction sender is required")
61
+
62
+ type_fields = [
63
+ transaction.payment,
64
+ transaction.asset_transfer,
65
+ transaction.asset_config,
66
+ transaction.application_call,
67
+ transaction.key_registration,
68
+ transaction.asset_freeze,
69
+ transaction.heartbeat,
70
+ transaction.state_proof,
71
+ ]
72
+ match sum(1 for f in type_fields if f is not None):
73
+ case 0:
74
+ raise TransactionValidationError("No transaction type specific field is set")
75
+ case n if n > 1:
76
+ raise TransactionValidationError("Multiple transaction type specific fields set")
77
+
78
+ issues: list[ValidationIssue] = []
79
+ type_label: str | None = None
80
+
81
+ match transaction:
82
+ case Transaction(application_call=app_call) if app_call is not None:
83
+ issues.extend(validate_app_call_fields(app_call))
84
+ type_label = "App call"
85
+ case Transaction(asset_config=asset_config) if asset_config is not None:
86
+ issues.extend(validate_asset_config_fields(asset_config))
87
+ type_label = "Asset config"
88
+ case Transaction(asset_transfer=asset_transfer) if asset_transfer is not None:
89
+ issues.extend(validate_asset_transfer_fields(asset_transfer))
90
+ type_label = "Asset transfer"
91
+ case Transaction(asset_freeze=asset_freeze) if asset_freeze is not None:
92
+ issues.extend(validate_asset_freeze_fields(asset_freeze))
93
+ type_label = "Asset freeze"
94
+ case Transaction(key_registration=key_registration) if key_registration is not None:
95
+ issues.extend(validate_key_registration_fields(key_registration))
96
+ type_label = "Key registration"
97
+
98
+ if issues and type_label:
99
+ messages = "\n".join(issue.message for issue in issues)
100
+ raise TransactionValidationError(f"{type_label} validation failed: {messages}", issues=issues)
101
+
102
+
103
+ def validate_app_call_fields(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
104
+ issues: list[ValidationIssue] = []
105
+
106
+ if app_call.app_id == 0:
107
+ issues.extend(_validate_app_creation(app_call))
108
+ else:
109
+ issues.extend(_validate_app_operation(app_call))
110
+
111
+ issues.extend(_validate_app_common_fields(app_call))
112
+ return issues
113
+
114
+
115
+ def _validate_app_creation(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
116
+ issues: list[ValidationIssue] = []
117
+ issues.extend(_require_creation_programs(app_call))
118
+ issues.extend(_validate_program_sizes(app_call))
119
+ issues.extend(_validate_state_schema_limits(app_call))
120
+ return issues
121
+
122
+
123
+ def _require_creation_programs(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
124
+ issues: list[ValidationIssue] = []
125
+ match (app_call.approval_program, app_call.clear_state_program):
126
+ case (None | b"", _):
127
+ issues.append(
128
+ _issue(ValidationIssueCode.REQUIRED_FIELD, "Approval program is required", field="Approval program")
129
+ )
130
+ case (_, None | b""):
131
+ issues.append(
132
+ _issue(
133
+ ValidationIssueCode.REQUIRED_FIELD, "Clear state program is required", field="Clear state program"
134
+ )
135
+ )
136
+ return issues
137
+
138
+
139
+ def _validate_program_sizes(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
140
+ issues: list[ValidationIssue] = []
141
+ extra_pages = app_call.extra_program_pages or 0
142
+ max_program_size = PROGRAM_PAGE_SIZE * (1 + extra_pages)
143
+ approval_size = len(app_call.approval_program or b"")
144
+ clear_state_size = len(app_call.clear_state_program or b"")
145
+ combined_size = approval_size + clear_state_size
146
+
147
+ match extra_pages:
148
+ case n if n > MAX_EXTRA_PROGRAM_PAGES:
149
+ issues.append(
150
+ _issue(
151
+ ValidationIssueCode.FIELD_TOO_LONG,
152
+ f"Extra program pages cannot exceed {MAX_EXTRA_PROGRAM_PAGES} pages, got {n}",
153
+ field="Extra program pages",
154
+ context={"max": MAX_EXTRA_PROGRAM_PAGES, "actual": n, "unit": "pages"},
155
+ )
156
+ )
157
+
158
+ match approval_size:
159
+ case size if size > max_program_size:
160
+ issues.append(
161
+ _issue(
162
+ ValidationIssueCode.FIELD_TOO_LONG,
163
+ f"Approval program cannot exceed {max_program_size} bytes",
164
+ field="Approval program",
165
+ context={"max": max_program_size, "actual": size, "unit": "bytes"},
166
+ )
167
+ )
168
+
169
+ match clear_state_size:
170
+ case size if size > max_program_size:
171
+ issues.append(
172
+ _issue(
173
+ ValidationIssueCode.FIELD_TOO_LONG,
174
+ f"Clear state program cannot exceed {max_program_size} bytes",
175
+ field="Clear state program",
176
+ context={"max": max_program_size, "actual": size, "unit": "bytes"},
177
+ )
178
+ )
179
+
180
+ match combined_size:
181
+ case size if size > max_program_size:
182
+ issues.append(
183
+ _issue(
184
+ ValidationIssueCode.FIELD_TOO_LONG,
185
+ f"Combined approval and clear state programs cannot exceed {max_program_size} bytes",
186
+ field="Combined program size",
187
+ context={"max": max_program_size, "actual": size, "unit": "bytes"},
188
+ )
189
+ )
190
+
191
+ return issues
192
+
193
+
194
+ def _validate_state_schema_limits(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
195
+ issues: list[ValidationIssue] = []
196
+ if app_call.global_state_schema is not None:
197
+ total = app_call.global_state_schema.num_uints + app_call.global_state_schema.num_byte_slices
198
+ if total > MAX_GLOBAL_STATE_KEYS:
199
+ issues.append(
200
+ _issue(
201
+ ValidationIssueCode.FIELD_TOO_LONG,
202
+ f"Global state schema cannot exceed {MAX_GLOBAL_STATE_KEYS} keys",
203
+ field="Global state schema",
204
+ context={"max": MAX_GLOBAL_STATE_KEYS, "actual": total, "unit": "keys"},
205
+ )
206
+ )
207
+
208
+ if app_call.local_state_schema is not None:
209
+ total = app_call.local_state_schema.num_uints + app_call.local_state_schema.num_byte_slices
210
+ if total > MAX_LOCAL_STATE_KEYS:
211
+ issues.append(
212
+ _issue(
213
+ ValidationIssueCode.FIELD_TOO_LONG,
214
+ f"Local state schema cannot exceed {MAX_LOCAL_STATE_KEYS} keys",
215
+ field="Local state schema",
216
+ context={"max": MAX_LOCAL_STATE_KEYS, "actual": total, "unit": "keys"},
217
+ )
218
+ )
219
+
220
+ return issues
221
+
222
+
223
+ def _validate_app_operation(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
224
+ issues: list[ValidationIssue] = []
225
+
226
+ def immutable(field: str) -> None:
227
+ issues.append(
228
+ _issue(ValidationIssueCode.IMMUTABLE_FIELD, f"{field} is immutable and cannot be changed", field=field)
229
+ )
230
+
231
+ match app_call.on_complete:
232
+ case OnApplicationComplete.UpdateApplication:
233
+ if not app_call.approval_program:
234
+ issues.append(
235
+ _issue(ValidationIssueCode.REQUIRED_FIELD, "Approval program is required", field="Approval program")
236
+ )
237
+ if not app_call.clear_state_program:
238
+ issues.append(
239
+ _issue(
240
+ ValidationIssueCode.REQUIRED_FIELD,
241
+ "Clear state program is required",
242
+ field="Clear state program",
243
+ )
244
+ )
245
+
246
+ if app_call.global_state_schema is not None:
247
+ immutable("Global state schema")
248
+ if app_call.local_state_schema is not None:
249
+ immutable("Local state schema")
250
+ if app_call.extra_program_pages is not None:
251
+ immutable("Extra program pages")
252
+
253
+ return issues
254
+
255
+
256
+ def _validate_app_common_fields(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
257
+ return [
258
+ *_validate_app_args_limits(app_call),
259
+ *_validate_reference_limits(app_call),
260
+ *_validate_box_reference_constraints(app_call),
261
+ *_validate_total_reference_limit(app_call),
262
+ ]
263
+
264
+
265
+ def _validate_app_args_limits(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
266
+ issues: list[ValidationIssue] = []
267
+ if app_call.args is None:
268
+ return issues
269
+ if len(app_call.args) > MAX_APP_ARGS:
270
+ issues.append(
271
+ _issue(
272
+ ValidationIssueCode.FIELD_TOO_LONG,
273
+ f"Args cannot exceed {MAX_APP_ARGS} arguments",
274
+ field="Args",
275
+ context={"max": MAX_APP_ARGS, "actual": len(app_call.args), "unit": "arguments"},
276
+ )
277
+ )
278
+ total_size = sum(len(arg) for arg in app_call.args)
279
+ if total_size > MAX_ARGS_SIZE:
280
+ issues.append(
281
+ _issue(
282
+ ValidationIssueCode.FIELD_TOO_LONG,
283
+ f"Args total size cannot exceed {MAX_ARGS_SIZE} bytes",
284
+ field="Args total size",
285
+ context={"max": MAX_ARGS_SIZE, "actual": total_size, "unit": "bytes"},
286
+ )
287
+ )
288
+ return issues
289
+
290
+
291
+ def _validate_reference_limits(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
292
+ issues: list[ValidationIssue] = []
293
+ reference_limits = (
294
+ ("Account references", app_call.account_references, MAX_ACCOUNT_REFERENCES),
295
+ ("App references", app_call.app_references, MAX_APP_REFERENCES),
296
+ ("Asset references", app_call.asset_references, MAX_ASSET_REFERENCES),
297
+ )
298
+ for label, refs, limit in reference_limits:
299
+ if refs is not None and len(refs) > limit:
300
+ issues.append(
301
+ _issue(
302
+ ValidationIssueCode.FIELD_TOO_LONG,
303
+ f"{label} cannot exceed {limit} refs",
304
+ field=label,
305
+ context={"max": limit, "actual": len(refs), "unit": "refs"},
306
+ )
307
+ )
308
+
309
+ return issues
310
+
311
+
312
+ def _validate_box_reference_constraints(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
313
+ issues: list[ValidationIssue] = []
314
+ box_refs = app_call.box_references or ()
315
+ if not box_refs:
316
+ return issues
317
+ if len(box_refs) > MAX_BOX_REFERENCES:
318
+ issues.append(
319
+ _issue(
320
+ ValidationIssueCode.FIELD_TOO_LONG,
321
+ f"Box references cannot exceed {MAX_BOX_REFERENCES} refs",
322
+ field="Box references",
323
+ context={"max": MAX_BOX_REFERENCES, "actual": len(box_refs), "unit": "refs"},
324
+ )
325
+ )
326
+ allowed_app_ids: set[int] = {app_call.app_id, 0}
327
+ allowed_app_ids.update(app_call.app_references or ())
328
+ for ref in box_refs:
329
+ if ref.app_id not in allowed_app_ids:
330
+ issues.append(
331
+ _issue(
332
+ ValidationIssueCode.ARBITRARY_CONSTRAINT,
333
+ f"Box reference for app ID {ref.app_id} must reference the current app or an app reference",
334
+ field="Box references",
335
+ )
336
+ )
337
+ return issues
338
+
339
+
340
+ def _validate_total_reference_limit(app_call: AppCallTransactionFields) -> list[ValidationIssue]:
341
+ total_refs = (
342
+ len(app_call.account_references or ())
343
+ + len(app_call.app_references or ())
344
+ + len(app_call.asset_references or ())
345
+ + len(app_call.box_references or ())
346
+ )
347
+ if total_refs <= MAX_OVERALL_REFERENCES:
348
+ return []
349
+ return [
350
+ _issue(
351
+ ValidationIssueCode.FIELD_TOO_LONG,
352
+ f"Total references cannot exceed {MAX_OVERALL_REFERENCES} refs",
353
+ field="Total references",
354
+ context={"max": MAX_OVERALL_REFERENCES, "actual": total_refs, "unit": "refs"},
355
+ )
356
+ ]
357
+
358
+
359
+ def validate_asset_config_fields(asset_config: AssetConfigTransactionFields) -> list[ValidationIssue]:
360
+ if asset_config.asset_id == 0:
361
+ return _validate_asset_creation(asset_config)
362
+ return _validate_asset_configuration(asset_config)
363
+
364
+
365
+ def _validate_asset_creation(asset_config: AssetConfigTransactionFields) -> list[ValidationIssue]:
366
+ issues: list[ValidationIssue] = []
367
+
368
+ def check_len(name: str, value: str | None, limit: int) -> None:
369
+ match value:
370
+ case str(s) if len(s) > limit:
371
+ issues.append(
372
+ _issue(
373
+ ValidationIssueCode.FIELD_TOO_LONG,
374
+ f"{name} cannot exceed {limit} bytes, got {len(s)}",
375
+ field=name,
376
+ context={"max": limit, "actual": len(s), "unit": "bytes"},
377
+ )
378
+ )
379
+
380
+ match asset_config.total:
381
+ case None:
382
+ issues.append(_issue(ValidationIssueCode.REQUIRED_FIELD, "Total is required", field="Total"))
383
+
384
+ match asset_config.decimals:
385
+ case int(d) if d > MAX_ASSET_DECIMALS:
386
+ issues.append(
387
+ _issue(
388
+ ValidationIssueCode.FIELD_TOO_LONG,
389
+ f"Decimals cannot exceed {MAX_ASSET_DECIMALS} decimal places, got {d}",
390
+ field="Decimals",
391
+ context={"max": MAX_ASSET_DECIMALS, "actual": d, "unit": "decimal places"},
392
+ )
393
+ )
394
+
395
+ check_len("Unit name", asset_config.unit_name, MAX_ASSET_UNIT_NAME_LENGTH)
396
+ check_len("Asset name", asset_config.asset_name, MAX_ASSET_NAME_LENGTH)
397
+ check_len("Url", asset_config.url, MAX_ASSET_URL_LENGTH)
398
+
399
+ return issues
400
+
401
+
402
+ def _validate_asset_configuration(asset_config: AssetConfigTransactionFields) -> list[ValidationIssue]:
403
+ immutable_fields = [
404
+ ("total", "Total"),
405
+ ("decimals", "Decimals"),
406
+ ("default_frozen", "Default frozen"),
407
+ ("asset_name", "Asset name"),
408
+ ("unit_name", "Unit name"),
409
+ ("url", "Url"),
410
+ ("metadata_hash", "Metadata hash"),
411
+ ]
412
+
413
+ return [
414
+ _issue(
415
+ ValidationIssueCode.IMMUTABLE_FIELD,
416
+ f"{label} is immutable and cannot be changed",
417
+ field=label,
418
+ )
419
+ for attr, label in immutable_fields
420
+ if getattr(asset_config, attr) is not None
421
+ ]
422
+
423
+
424
+ def validate_asset_transfer_fields(asset_transfer: AssetTransferTransactionFields) -> list[ValidationIssue]:
425
+ issues: list[ValidationIssue] = []
426
+
427
+ if asset_transfer.asset_id == 0:
428
+ issues.append(
429
+ _issue(
430
+ ValidationIssueCode.ZERO_VALUE_FIELD,
431
+ "Asset ID must not be 0",
432
+ field="Asset ID",
433
+ )
434
+ )
435
+
436
+ return issues
437
+
438
+
439
+ def validate_asset_freeze_fields(asset_freeze: AssetFreezeTransactionFields) -> list[ValidationIssue]:
440
+ issues: list[ValidationIssue] = []
441
+
442
+ if asset_freeze.asset_id == 0:
443
+ issues.append(
444
+ _issue(
445
+ ValidationIssueCode.ZERO_VALUE_FIELD,
446
+ "Asset ID must not be 0",
447
+ field="Asset ID",
448
+ )
449
+ )
450
+
451
+ return issues
452
+
453
+
454
+ def validate_key_registration_fields(key_reg: KeyRegistrationTransactionFields) -> list[ValidationIssue]:
455
+ issues: list[ValidationIssue] = []
456
+
457
+ has_participation_fields = any(
458
+ field is not None
459
+ for field in (
460
+ key_reg.vote_key,
461
+ key_reg.selection_key,
462
+ key_reg.state_proof_key,
463
+ key_reg.vote_first,
464
+ key_reg.vote_last,
465
+ key_reg.vote_key_dilution,
466
+ )
467
+ )
468
+
469
+ if not has_participation_fields:
470
+ return issues
471
+
472
+ required_fields = [
473
+ (key_reg.vote_key, "Vote key"),
474
+ (key_reg.selection_key, "Selection key"),
475
+ (key_reg.state_proof_key, "State proof key"),
476
+ (key_reg.vote_first, "Vote first"),
477
+ (key_reg.vote_last, "Vote last"),
478
+ (key_reg.vote_key_dilution, "Vote key dilution"),
479
+ ]
480
+
481
+ for value, field_name in required_fields:
482
+ if value is None:
483
+ issues.append(_issue(ValidationIssueCode.REQUIRED_FIELD, f"{field_name} is required", field=field_name))
484
+
485
+ if key_reg.vote_first is not None and key_reg.vote_last is not None and key_reg.vote_first >= key_reg.vote_last:
486
+ issues.append(
487
+ _issue(
488
+ ValidationIssueCode.ARBITRARY_CONSTRAINT,
489
+ "Vote first must be less than vote last",
490
+ field="Vote first",
491
+ )
492
+ )
493
+
494
+ if key_reg.non_participation:
495
+ issues.append(
496
+ _issue(
497
+ ValidationIssueCode.ARBITRARY_CONSTRAINT,
498
+ "Online key registration cannot have non participation flag set",
499
+ field="Non participation",
500
+ )
501
+ )
502
+
503
+ return issues
File without changes
@@ -0,0 +1,195 @@
1
+ """Transaction and data signing types and utilities."""
2
+
3
+ import base64
4
+ from collections.abc import Callable, Sequence
5
+ from dataclasses import dataclass
6
+ from typing import Protocol, runtime_checkable
7
+
8
+ import nacl.signing
9
+
10
+ from algokit_common import address_from_public_key, public_key_from_address
11
+ from algokit_common.constants import (
12
+ EMPTY_SIGNATURE,
13
+ LOGIC_DATA_DOMAIN_SEPARATOR,
14
+ MULTISIG_PROGRAM_DOMAIN_SEPARATOR,
15
+ MX_BYTES_DOMAIN_SEPARATOR,
16
+ PROGRAM_DOMAIN_SEPARATOR,
17
+ )
18
+ from algokit_transact.codec.signed import encode_signed_transaction
19
+ from algokit_transact.codec.transaction import encode_transaction
20
+ from algokit_transact.models.signed_transaction import SignedTransaction
21
+ from algokit_transact.models.transaction import Transaction
22
+
23
+ # Type aliases for signing functions
24
+ BytesSigner = Callable[[bytes], bytes]
25
+ TransactionSigner = Callable[[Sequence[Transaction], Sequence[int]], list[bytes]]
26
+ DelegatedLsigSigner = Callable[[bytes, bytes | None], bytes]
27
+ ProgramDataSigner = Callable[[bytes, bytes], bytes]
28
+ MxBytesSigner = Callable[[bytes], bytes]
29
+
30
+
31
+ @runtime_checkable
32
+ class Addressable(Protocol):
33
+ """Protocol for objects with an address."""
34
+
35
+ @property
36
+ def addr(self) -> str: ...
37
+
38
+
39
+ @runtime_checkable
40
+ class AddressWithTransactionSigner(Addressable, Protocol):
41
+ """Protocol for objects with transaction signing capability."""
42
+
43
+ @property
44
+ def signer(self) -> TransactionSigner: ...
45
+
46
+
47
+ @runtime_checkable
48
+ class AddressWithDelegatedLsigSigner(Addressable, Protocol):
49
+ """Protocol for objects with logic signature delegation signing."""
50
+
51
+ @property
52
+ def delegated_lsig_signer(self) -> DelegatedLsigSigner: ...
53
+
54
+
55
+ @runtime_checkable
56
+ class AddressWithProgramDataSigner(Addressable, Protocol):
57
+ """Protocol for objects with program data signing capability."""
58
+
59
+ @property
60
+ def program_data_signer(self) -> ProgramDataSigner: ...
61
+
62
+
63
+ @runtime_checkable
64
+ class AddressWithMxBytesSigner(Addressable, Protocol):
65
+ """Protocol for objects with MX-prefixed bytes signing capability."""
66
+
67
+ @property
68
+ def mx_bytes_signer(self) -> MxBytesSigner: ...
69
+
70
+
71
+ @dataclass(frozen=True, slots=True)
72
+ class AddressWithSigners:
73
+ """Container for an address with all signing capabilities."""
74
+
75
+ addr: str
76
+ signer: TransactionSigner
77
+ delegated_lsig_signer: DelegatedLsigSigner
78
+ program_data_signer: ProgramDataSigner
79
+ bytes_signer: BytesSigner
80
+ mx_bytes_signer: MxBytesSigner
81
+
82
+
83
+ def generate_address_with_signers(
84
+ ed25519_pubkey: bytes,
85
+ raw_ed25519_signer: BytesSigner,
86
+ *,
87
+ sending_address: str | None = None,
88
+ ) -> AddressWithSigners:
89
+ """Generate domain-separated signers from an ed25519 pubkey and raw signer.
90
+
91
+ Args:
92
+ ed25519_pubkey: The ed25519 public key bytes.
93
+ raw_ed25519_signer: A function that signs raw bytes with the ed25519 private key.
94
+ sending_address: Optional address to use as the sending address. If provided,
95
+ this will be the `addr` in the returned object, and the address derived
96
+ from `ed25519_pubkey` will be used as the auth_address when signing
97
+ transactions where the sender differs from the sending_address.
98
+
99
+ Returns:
100
+ An AddressWithSigners containing the address and all signing functions.
101
+ """
102
+ auth_addr = address_from_public_key(ed25519_pubkey)
103
+ addr = sending_address if sending_address is not None else auth_addr
104
+
105
+ def transaction_signer(txn_group: Sequence[Transaction], indexes_to_sign: Sequence[int]) -> list[bytes]:
106
+ result: list[bytes] = []
107
+ for index in indexes_to_sign:
108
+ txn = txn_group[index]
109
+ bytes_to_sign = encode_transaction(txn)
110
+ signature = raw_ed25519_signer(bytes_to_sign)
111
+ stxn = SignedTransaction(
112
+ txn=txn,
113
+ sig=signature,
114
+ auth_address=auth_addr if txn.sender != auth_addr else None,
115
+ )
116
+ result.append(encode_signed_transaction(stxn))
117
+ return result
118
+
119
+ def delegated_lsig_signer(program: bytes, msig_address: bytes | None = None) -> bytes:
120
+ if msig_address is not None:
121
+ payload = MULTISIG_PROGRAM_DOMAIN_SEPARATOR.encode() + msig_address + program
122
+ else:
123
+ payload = PROGRAM_DOMAIN_SEPARATOR.encode() + program
124
+ return raw_ed25519_signer(payload)
125
+
126
+ def program_data_signer(data: bytes, program_address: bytes) -> bytes:
127
+ payload = LOGIC_DATA_DOMAIN_SEPARATOR.encode() + program_address + data
128
+ return raw_ed25519_signer(payload)
129
+
130
+ def mx_bytes_signer(data: bytes) -> bytes:
131
+ payload = MX_BYTES_DOMAIN_SEPARATOR.encode() + data
132
+ return raw_ed25519_signer(payload)
133
+
134
+ return AddressWithSigners(
135
+ addr=addr,
136
+ signer=transaction_signer,
137
+ delegated_lsig_signer=delegated_lsig_signer,
138
+ program_data_signer=program_data_signer,
139
+ bytes_signer=raw_ed25519_signer,
140
+ mx_bytes_signer=mx_bytes_signer,
141
+ )
142
+
143
+
144
+ def make_empty_transaction_signer() -> TransactionSigner:
145
+ """Create a signer that returns empty signatures (for simulation only)."""
146
+
147
+ def empty_signer(txn_group: Sequence[Transaction], indexes_to_sign: Sequence[int]) -> list[bytes]:
148
+ result: list[bytes] = []
149
+ for index in indexes_to_sign:
150
+ stxn = SignedTransaction(
151
+ txn=txn_group[index],
152
+ sig=EMPTY_SIGNATURE,
153
+ )
154
+ result.append(encode_signed_transaction(stxn))
155
+ return result
156
+
157
+ return empty_signer
158
+
159
+
160
+ def bytes_to_sign_for_delegation(program: bytes, msig_public_key: bytes | None = None) -> bytes:
161
+ """Get bytes to sign for delegating a logic signature."""
162
+ if msig_public_key is not None:
163
+ return MULTISIG_PROGRAM_DOMAIN_SEPARATOR.encode() + msig_public_key + program
164
+ return PROGRAM_DOMAIN_SEPARATOR.encode() + program
165
+
166
+
167
+ def program_data_to_sign(data: bytes, program_address: str) -> bytes:
168
+ """Get bytes to sign for program data."""
169
+ program_public_key = public_key_from_address(program_address)
170
+ return LOGIC_DATA_DOMAIN_SEPARATOR.encode() + program_public_key + data
171
+
172
+
173
+ def make_basic_account_transaction_signer(private_key: str) -> TransactionSigner:
174
+ """Create a transaction signer from a base64-encoded private key.
175
+
176
+ Args:
177
+ private_key: Base64-encoded 64-byte private key (first 32 bytes are seed,
178
+ last 32 bytes are public key).
179
+
180
+ Returns:
181
+ A TransactionSigner function that can sign transactions.
182
+ """
183
+ # Decode the base64 private key (64 bytes: 32-byte seed + 32-byte public key)
184
+ key_bytes = base64.b64decode(private_key)
185
+ seed = key_bytes[:32]
186
+ public_key = key_bytes[32:]
187
+
188
+ # Create signing key from seed
189
+ signing_key = nacl.signing.SigningKey(seed)
190
+
191
+ def raw_signer(bytes_to_sign: bytes) -> bytes:
192
+ signed = signing_key.sign(bytes_to_sign)
193
+ return signed.signature
194
+
195
+ return generate_address_with_signers(public_key, raw_signer).signer
File without changes