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,596 @@
1
+ import base64
2
+ import binascii
3
+ import typing
4
+ from collections import OrderedDict
5
+
6
+ from nacl.exceptions import BadSignatureError
7
+ from nacl.signing import SigningKey, VerifyKey
8
+
9
+ from . import constants, encoding, error, logic
10
+
11
+
12
+ class Transaction(typing.Protocol):
13
+ """
14
+ Superclass for various transaction types.
15
+ """
16
+
17
+ sender: bytes | str
18
+
19
+ def get_txid(self) -> str: ...
20
+
21
+ def raw_sign(self, private_key: str) -> bytes: ...
22
+
23
+
24
+ class MultisigTransaction:
25
+ """
26
+ Represents a signed transaction.
27
+
28
+ Args:
29
+ transaction (Transaction): transaction that was signed
30
+ multisig (Multisig): multisig account and signatures
31
+
32
+ Attributes:
33
+ transaction (Transaction)
34
+ multisig (Multisig)
35
+ auth_addr (str, optional)
36
+ """
37
+
38
+ def __init__(self, transaction: Transaction, multisig: "Multisig") -> None:
39
+ self.transaction = transaction
40
+ self.multisig = multisig
41
+
42
+ msigAddr = multisig.address()
43
+ if transaction.sender != msigAddr:
44
+ self.auth_addr = msigAddr
45
+ else:
46
+ self.auth_addr = None
47
+
48
+ def sign(self, private_key: str) -> None:
49
+ """
50
+ Sign the multisig transaction.
51
+
52
+ Args:
53
+ private_key (str): private key of signing account
54
+
55
+ Note:
56
+ A new signature will replace the old if there is already a
57
+ signature for the address. To sign another transaction, you can
58
+ either overwrite the signatures in the current Multisig, or you
59
+ can use Multisig.get_multisig_account() to get a new multisig
60
+ object with the same addresses.
61
+ """
62
+ self.multisig.validate()
63
+ index = -1
64
+ public_key = base64.b64decode(bytes(private_key, "utf-8"))
65
+ public_key = public_key[constants.key_len_bytes :]
66
+ for s in range(len(self.multisig.subsigs)):
67
+ if self.multisig.subsigs[s].public_key == public_key:
68
+ index = s
69
+ break
70
+ if index == -1:
71
+ raise error.InvalidSecretKeyError
72
+ sig = self.transaction.raw_sign(private_key)
73
+ self.multisig.subsigs[index].signature = sig
74
+
75
+ def get_txid(self) -> str:
76
+ """
77
+ Get the transaction's ID.
78
+
79
+ Returns:
80
+ str: transaction ID
81
+ """
82
+ return self.transaction.get_txid()
83
+
84
+ def __eq__(self, other) -> bool:
85
+ if isinstance(other, MultisigTransaction):
86
+ return (
87
+ self.transaction == other.transaction
88
+ and self.auth_addr == other.auth_addr
89
+ and self.multisig == other.multisig
90
+ )
91
+
92
+ return False
93
+
94
+
95
+ class Multisig:
96
+ """
97
+ Represents a multisig account and signatures.
98
+
99
+ Args:
100
+ version (int): currently, the version is 1
101
+ threshold (int): how many signatures are necessary
102
+ addresses (str[]): addresses in the multisig account
103
+
104
+ Attributes:
105
+ version (int)
106
+ threshold (int)
107
+ subsigs (MultisigSubsig[])
108
+ """
109
+
110
+ def __init__(self, version, threshold, addresses):
111
+ self.version = version
112
+ self.threshold = threshold
113
+ self.subsigs = []
114
+ for a in addresses:
115
+ self.subsigs.append(MultisigSubsig(encoding.decode_address(a)))
116
+
117
+ def validate(self):
118
+ """Check if the multisig account is valid."""
119
+ if not self.version == 1:
120
+ raise error.UnknownMsigVersionError
121
+ if self.threshold <= 0 or len(self.subsigs) == 0 or self.threshold > len(self.subsigs):
122
+ raise error.InvalidThresholdError
123
+ if len(self.subsigs) > constants.multisig_account_limit:
124
+ raise error.MultisigAccountSizeError
125
+
126
+ def address_bytes(self):
127
+ """Return the raw bytes of the multisig account address."""
128
+ msig_bytes = bytes(constants.msig_addr_prefix, "utf-8") + bytes([self.version]) + bytes([self.threshold])
129
+ for s in self.subsigs:
130
+ msig_bytes += s.public_key
131
+ return encoding.checksum(msig_bytes)
132
+
133
+ def address(self):
134
+ """Return the multisig account address."""
135
+ return encoding.encode_address(self.address_bytes())
136
+
137
+ def verify(self, message):
138
+ """Verify that the multisig is valid for the message."""
139
+ try:
140
+ self.validate()
141
+ except (error.UnknownMsigVersionError, error.InvalidThresholdError):
142
+ return False
143
+ counter = sum(map(lambda s: s.signature is not None, self.subsigs))
144
+ if counter < self.threshold:
145
+ return False
146
+
147
+ verified_count = 0
148
+ for subsig in self.subsigs:
149
+ if subsig.signature is not None:
150
+ verify_key = VerifyKey(subsig.public_key)
151
+ try:
152
+ verify_key.verify(message, subsig.signature)
153
+ verified_count += 1
154
+ except (BadSignatureError, ValueError, TypeError):
155
+ return False
156
+
157
+ if verified_count < self.threshold:
158
+ return False
159
+
160
+ return True
161
+
162
+ def dictify(self):
163
+ od = OrderedDict()
164
+ od["subsig"] = [subsig.dictify() for subsig in self.subsigs]
165
+ od["thr"] = self.threshold
166
+ od["v"] = self.version
167
+ return od
168
+
169
+ def json_dictify(self):
170
+ d = {
171
+ "subsig": [subsig.json_dictify() for subsig in self.subsigs],
172
+ "thr": self.threshold,
173
+ "v": self.version,
174
+ }
175
+ return d
176
+
177
+ @staticmethod
178
+ def undictify(d):
179
+ subsigs = [MultisigSubsig.undictify(s) for s in d["subsig"]]
180
+ msig = Multisig(d["v"], d["thr"], [])
181
+ msig.subsigs = subsigs
182
+ return msig
183
+
184
+ def get_multisig_account(self):
185
+ """Return a Multisig object without signatures."""
186
+ msig = Multisig(self.version, self.threshold, self.get_public_keys())
187
+ for s in msig.subsigs:
188
+ s.signature = None
189
+ return msig
190
+
191
+ def get_public_keys(self):
192
+ """Return the base32 encoded addresses for the multisig account."""
193
+ pks = [encoding.encode_address(s.public_key) for s in self.subsigs]
194
+ return pks
195
+
196
+ def __eq__(self, other):
197
+ if not isinstance(other, Multisig):
198
+ return False
199
+ return self.version == other.version and self.threshold == other.threshold and self.subsigs == other.subsigs
200
+
201
+
202
+ class MultisigSubsig:
203
+ """
204
+ Attributes:
205
+ public_key (bytes)
206
+ signature (bytes)
207
+ """
208
+
209
+ def __init__(self, public_key, signature=None):
210
+ self.public_key = public_key
211
+ self.signature = signature
212
+
213
+ def dictify(self):
214
+ od = OrderedDict()
215
+ od["pk"] = self.public_key
216
+ if self.signature:
217
+ od["s"] = self.signature
218
+ return od
219
+
220
+ def json_dictify(self):
221
+ d = {"pk": base64.b64encode(self.public_key).decode()}
222
+ if self.signature:
223
+ d["s"] = base64.b64encode(self.signature).decode()
224
+ return d
225
+
226
+ @staticmethod
227
+ def undictify(d):
228
+ sig = None
229
+ if "s" in d:
230
+ sig = d["s"]
231
+ mss = MultisigSubsig(d["pk"], sig)
232
+ return mss
233
+
234
+ def __eq__(self, other):
235
+ if not isinstance(other, MultisigSubsig):
236
+ return False
237
+ return self.public_key == other.public_key and self.signature == other.signature
238
+
239
+
240
+ class LogicSig:
241
+ """
242
+ Represents a logic signature
243
+
244
+ NOTE: LogicSig cannot sign transactions in all cases. Instead, use LogicSigAccount as a safe, general purpose signing mechanism. Since LogicSig does not track the provided signature's public key, LogicSig cannot sign transactions when delegated to a non-multisig account _and_ the sender is not the delegating account.
245
+
246
+ Arguments:
247
+ logic (bytes): compiled program
248
+ args (list[bytes]): args are not signed, but are checked by logic
249
+
250
+ Attributes:
251
+ logic (bytes)
252
+ sig (bytes)
253
+ msig (Multisig)
254
+ args (list[bytes])
255
+ """
256
+
257
+ def __init__(self, program, args=None):
258
+ self._sanity_check_program(program)
259
+ self.logic = program
260
+ self.args = args
261
+ self.sig = None
262
+ self.msig = None
263
+ self.lmsig = None
264
+
265
+ @staticmethod
266
+ def _sanity_check_program(program):
267
+ """
268
+ Performs heuristic program validation:
269
+ check if passed in bytes are Algorand address, or they are B64 encoded, rather than Teal bytes
270
+
271
+ Args:
272
+ program (bytes): compiled program
273
+ """
274
+
275
+ def is_ascii_printable(program_bytes):
276
+ return all(
277
+ map(
278
+ lambda x: x == ord("\n") or (ord(" ") <= x <= ord("~")),
279
+ program_bytes,
280
+ )
281
+ )
282
+
283
+ if not program:
284
+ raise error.InvalidProgram("empty program")
285
+
286
+ if is_ascii_printable(program):
287
+ try:
288
+ encoding.decode_address(program.decode("utf-8"))
289
+ raise error.InvalidProgram("requesting program bytes, get Algorand address")
290
+ except error.WrongChecksumError:
291
+ pass
292
+ except error.WrongKeyLengthError:
293
+ pass
294
+
295
+ try:
296
+ base64.b64decode(program.decode("utf-8"))
297
+ raise error.InvalidProgram("program should not be b64 encoded")
298
+ except binascii.Error:
299
+ pass
300
+
301
+ raise error.InvalidProgram(
302
+ "program bytes are all ASCII printable characters, not looking like Teal byte code"
303
+ )
304
+
305
+ def dictify(self):
306
+ od = OrderedDict()
307
+ if self.args:
308
+ od["arg"] = self.args
309
+ od["l"] = self.logic
310
+ if self.sig:
311
+ od["sig"] = base64.b64decode(self.sig)
312
+ elif self.msig:
313
+ od["msig"] = self.msig.dictify()
314
+ elif self.lmsig:
315
+ od["lmsig"] = self.lmsig.dictify()
316
+ return od
317
+
318
+ @staticmethod
319
+ def undictify(d):
320
+ lsig = LogicSig(d["l"], d.get("arg", None))
321
+ if "sig" in d:
322
+ lsig.sig = base64.b64encode(d["sig"]).decode()
323
+ elif "msig" in d:
324
+ lsig.msig = Multisig.undictify(d["msig"])
325
+ elif "lmsig" in d:
326
+ lsig.lmsig = Multisig.undictify(d["lmsig"])
327
+ return lsig
328
+
329
+ def sig_count(self):
330
+ return int(self.sig is not None) + int(self.msig is not None) + int(self.lmsig is not None)
331
+
332
+ def verify(self, public_key):
333
+ """
334
+ Verifies LogicSig against the transaction's sender address
335
+
336
+ Args:
337
+ public_key (bytes): sender address
338
+
339
+ Returns:
340
+ bool: true if the signature is valid (the sender address matches\
341
+ the logic hash or the signature is valid against the sender\
342
+ address), false otherwise
343
+ """
344
+ try:
345
+ self._sanity_check_program(self.logic)
346
+ except error.InvalidProgram:
347
+ return False
348
+
349
+ if self.sig_count() > 1:
350
+ return False
351
+
352
+ if self.sig:
353
+ verify_key = VerifyKey(public_key)
354
+ try:
355
+ to_sign = constants.logic_prefix + self.logic
356
+ verify_key.verify(to_sign, base64.b64decode(self.sig))
357
+ return True
358
+ except (BadSignatureError, ValueError, TypeError):
359
+ return False
360
+
361
+ if self.msig:
362
+ to_sign = constants.logic_prefix + self.logic
363
+ return self.msig.verify(to_sign)
364
+
365
+ if self.lmsig:
366
+ to_sign = constants.multisig_logic_prefix + self.lmsig.address_bytes() + self.logic
367
+ return self.lmsig.verify(to_sign)
368
+
369
+ # Non-delegated
370
+ to_sign = constants.logic_prefix + self.logic
371
+ return public_key == encoding.checksum(to_sign)
372
+
373
+ def address(self):
374
+ """
375
+ Compute hash of the logic sig program (that is the same as escrow
376
+ account address) as string address
377
+
378
+ Returns:
379
+ str: program address
380
+ """
381
+ return logic.address(self.logic)
382
+
383
+ @staticmethod
384
+ def sign_program(program, private_key):
385
+ private_key = base64.b64decode(private_key)
386
+ signing_key = SigningKey(private_key[: constants.key_len_bytes])
387
+ to_sign = constants.logic_prefix + program
388
+ signed = signing_key.sign(to_sign)
389
+ return base64.b64encode(signed.signature).decode()
390
+
391
+ @staticmethod
392
+ def multisig_sign_program(program, private_key, multisig):
393
+ private_key = base64.b64decode(private_key)
394
+ signing_key = SigningKey(private_key[: constants.key_len_bytes])
395
+ to_sign = constants.multisig_logic_prefix + multisig.address_bytes() + program
396
+ signed = signing_key.sign(to_sign)
397
+ return base64.b64encode(signed.signature).decode()
398
+
399
+ @staticmethod
400
+ def single_sig_multisig(program, private_key, multisig):
401
+ index = -1
402
+ public_key = base64.b64decode(bytes(private_key, "utf-8"))
403
+ public_key = public_key[constants.key_len_bytes :]
404
+ for s in range(len(multisig.subsigs)):
405
+ if multisig.subsigs[s].public_key == public_key:
406
+ index = s
407
+ break
408
+ if index == -1:
409
+ raise error.InvalidSecretKeyError
410
+ sig = LogicSig.multisig_sign_program(program, private_key, multisig)
411
+
412
+ return sig, index
413
+
414
+ def sign(self, private_key, multisig=None):
415
+ """
416
+ Creates signature (if no pk provided) or multi signature
417
+
418
+ Args:
419
+ private_key (str): private key of signing account
420
+ multisig (Multisig): optional multisig account without signatures
421
+ to sign with
422
+
423
+ Raises:
424
+ InvalidSecretKeyError: if no matching private key in multisig\
425
+ object
426
+ LogicSigOverspecifiedSignature: if the opposite signature type has
427
+ already been provided
428
+ """
429
+ if not multisig:
430
+ if self.msig or self.lmsig:
431
+ raise error.LogicSigOverspecifiedSignature
432
+ self.sig = LogicSig.sign_program(self.logic, private_key)
433
+ else:
434
+ if self.sig:
435
+ raise error.LogicSigOverspecifiedSignature
436
+ sig, index = LogicSig.single_sig_multisig(self.logic, private_key, multisig)
437
+ multisig.subsigs[index].signature = base64.b64decode(sig)
438
+ self.lmsig = multisig
439
+
440
+ def append_to_multisig(self, private_key):
441
+ """
442
+ Appends a signature to multi signature
443
+
444
+ Args:
445
+ private_key (str): private key of signing account
446
+
447
+ Raises:
448
+ InvalidSecretKeyError: if no matching private key in multisig\
449
+ object
450
+ """
451
+ if self.lmsig is None:
452
+ raise error.InvalidSecretKeyError
453
+ sig, index = LogicSig.single_sig_multisig(self.logic, private_key, self.lmsig)
454
+ self.lmsig.subsigs[index].signature = base64.b64decode(sig)
455
+
456
+ def __eq__(self, other: object) -> bool:
457
+ if not isinstance(other, LogicSig):
458
+ return False
459
+ return (
460
+ self.logic == other.logic
461
+ and self.args == other.args
462
+ and self.sig == other.sig
463
+ and self.msig == other.msig
464
+ and self.lmsig == other.lmsig
465
+ )
466
+
467
+
468
+ class LogicSigAccount:
469
+ """
470
+ Represents an account that can sign with a LogicSig program.
471
+
472
+ Create a new LogicSigAccount. By default this constructs an escrow LogicSig account.
473
+ Call `sign` or `sign_multisig` on the newly created LogicSigAccount to make it a delegated account.
474
+ """
475
+
476
+ def __init__(self, program: bytes, args: list[bytes] | None = None) -> None:
477
+ self.lsig = LogicSig(program, args)
478
+ self.sigkey: bytes | None = None
479
+
480
+ def is_delegated(self) -> bool:
481
+ """
482
+ Check if this LogicSigAccount has been delegated to another account with
483
+ a signature.
484
+
485
+ Returns:
486
+ bool: True if and only if this is a delegated LogicSigAccount.
487
+ """
488
+ return bool(self.lsig.sig or self.lsig.msig or self.lsig.lmsig)
489
+
490
+ def verify(self) -> bool:
491
+ """
492
+ Verifies the LogicSig's program and signatures.
493
+
494
+ Returns:
495
+ bool: True if and only if the LogicSig program and signatures are
496
+ valid.
497
+ """
498
+ addr = self.address()
499
+ return self.lsig.verify(encoding.decode_address(addr))
500
+
501
+ def sig_count(self) -> int:
502
+ """
503
+ Returns the number of cryptographic signatures on the LogicSig
504
+
505
+ Returns:
506
+ int: The number of signatures. Should never exceed 1.
507
+ """
508
+ return self.lsig.sig_count()
509
+
510
+ def address(self) -> str:
511
+ """
512
+ Get the address of this LogicSigAccount.
513
+
514
+ If the LogicSig is delegated to another account, this will return the
515
+ address of that account.
516
+
517
+ If the LogicSig is not delegated to another account, this will return an
518
+ escrow address that is the hash of the LogicSig's program code.
519
+ """
520
+ if self.sig_count() > 1:
521
+ raise error.LogicSigOverspecifiedSignature
522
+
523
+ if self.lsig.sig:
524
+ if not self.sigkey:
525
+ raise error.LogicSigSigningKeyMissing
526
+ return encoding.encode_address(self.sigkey)
527
+
528
+ if self.lsig.msig:
529
+ return self.lsig.msig.address()
530
+
531
+ if self.lsig.lmsig:
532
+ return self.lsig.lmsig.address()
533
+
534
+ return self.lsig.address()
535
+
536
+ def sign_multisig(self, multisig: Multisig, private_key: str) -> None:
537
+ """
538
+ Turns this LogicSigAccount into a delegated LogicSig.
539
+
540
+ This type of LogicSig has the authority to sign transactions on behalf
541
+ of another account, called the delegating account. Use this function if
542
+ the delegating account is a multisig account.
543
+
544
+ Args:
545
+ multisig (Multisig): The multisig delegating account
546
+ private_key (str): The private key of one of the members of the
547
+ delegating multisig account. Use `append_to_multisig` to add
548
+ additional signatures from other members.
549
+
550
+ Raises:
551
+ InvalidSecretKeyError: if no matching private key in multisig
552
+ object
553
+ LogicSigOverspecifiedSignature: if this LogicSigAccount has already
554
+ been signed with a single private key.
555
+ """
556
+ self.lsig.sign(private_key, multisig)
557
+
558
+ def append_to_multisig(self, private_key: str) -> None:
559
+ """
560
+ Adds an additional signature from a member of the delegating multisig
561
+ account.
562
+
563
+ Args:
564
+ private_key (str): The private key of one of the members of the
565
+ delegating multisig account.
566
+
567
+ Raises:
568
+ InvalidSecretKeyError: if no matching private key in multisig
569
+ object
570
+ """
571
+ self.lsig.append_to_multisig(private_key)
572
+
573
+ def sign(self, private_key: str) -> None:
574
+ """
575
+ Turns this LogicSigAccount into a delegated LogicSig.
576
+
577
+ This type of LogicSig has the authority to sign transactions on behalf
578
+ of another account, called the delegating account. If the delegating
579
+ account is a multisig account, use `sign_multisig` instead.
580
+
581
+ Args:
582
+ private_key (str): The private key of the delegating account.
583
+
584
+ Raises:
585
+ LogicSigOverspecifiedSignature: if this LogicSigAccount has already
586
+ been signed by a multisig account.
587
+ """
588
+ self.lsig.sign(private_key)
589
+ public_key = base64.b64decode(bytes(private_key, "utf-8"))
590
+ public_key = public_key[constants.key_len_bytes :]
591
+ self.sigkey = public_key
592
+
593
+ def __eq__(self, other: object) -> bool:
594
+ if not isinstance(other, LogicSigAccount):
595
+ return False
596
+ return self.lsig == other.lsig and self.sigkey == other.sigkey