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.
- algokit_abi/__init__.py +9 -0
- algokit_abi/_arc32_to_arc56.py +242 -0
- algokit_abi/_arc56_serde.py +161 -0
- algokit_abi/abi.py +667 -0
- algokit_abi/arc32.py +210 -0
- algokit_abi/arc56.py +821 -0
- algokit_abi/py.typed +0 -0
- algokit_algo25/__init__.py +38 -0
- algokit_algo25/_encoding.py +46 -0
- algokit_algo25/_wordlist.py +2065 -0
- algokit_algo25/exceptions.py +29 -0
- algokit_algo25/mnemonic.py +128 -0
- algokit_algo25/py.typed +0 -0
- algokit_algod_client/__init__.py +10 -0
- algokit_algod_client/client.py +1585 -0
- algokit_algod_client/config.py +36 -0
- algokit_algod_client/exceptions.py +59 -0
- algokit_algod_client/models/__init__.py +229 -0
- algokit_algod_client/models/_account.py +150 -0
- algokit_algod_client/models/_account_application_response.py +25 -0
- algokit_algod_client/models/_account_asset_response.py +25 -0
- algokit_algod_client/models/_account_participation.py +53 -0
- algokit_algod_client/models/_account_state_delta.py +30 -0
- algokit_algod_client/models/_allocations_for_genesis_file.py +23 -0
- algokit_algod_client/models/_allocations_for_genesis_file_state_model.py +42 -0
- algokit_algod_client/models/_application.py +23 -0
- algokit_algod_client/models/_application_initial_states.py +37 -0
- algokit_algod_client/models/_application_kvstorage.py +29 -0
- algokit_algod_client/models/_application_local_state.py +33 -0
- algokit_algod_client/models/_application_params.py +63 -0
- algokit_algod_client/models/_application_state_operation.py +41 -0
- algokit_algod_client/models/_application_state_schema.py +22 -0
- algokit_algod_client/models/_asset.py +23 -0
- algokit_algod_client/models/_asset_holding.py +29 -0
- algokit_algod_client/models/_asset_params.py +102 -0
- algokit_algod_client/models/_avm_key_value.py +28 -0
- algokit_algod_client/models/_avm_value.py +32 -0
- algokit_algod_client/models/_block.py +363 -0
- algokit_algod_client/models/_block_hash_response.py +14 -0
- algokit_algod_client/models/_block_txids_response.py +14 -0
- algokit_algod_client/models/_box.py +36 -0
- algokit_algod_client/models/_box_descriptor.py +24 -0
- algokit_algod_client/models/_boxes_response.py +21 -0
- algokit_algod_client/models/_build_version_contains_the_current_algod_build_version_information.py +34 -0
- algokit_algod_client/models/_compile_response.py +24 -0
- algokit_algod_client/models/_disassemble_response.py +14 -0
- algokit_algod_client/models/_error_response.py +22 -0
- algokit_algod_client/models/_eval_delta.py +32 -0
- algokit_algod_client/models/_eval_delta_key_value.py +28 -0
- algokit_algod_client/models/_genesis_file_in_json.py +53 -0
- algokit_algod_client/models/_get_block_time_stamp_offset_response.py +14 -0
- algokit_algod_client/models/_get_sync_round_response.py +14 -0
- algokit_algod_client/models/_ledger_state_delta.py +389 -0
- algokit_algod_client/models/_light_block_header_proof.py +32 -0
- algokit_algod_client/models/_node_status_response.py +118 -0
- algokit_algod_client/models/_pending_transaction_response.py +91 -0
- algokit_algod_client/models/_pending_transactions_response.py +29 -0
- algokit_algod_client/models/_post_transactions_response.py +14 -0
- algokit_algod_client/models/_scratch_change.py +23 -0
- algokit_algod_client/models/_serde_helpers.py +241 -0
- algokit_algod_client/models/_simulate_initial_states.py +25 -0
- algokit_algod_client/models/_simulate_request.py +54 -0
- algokit_algod_client/models/_simulate_request_transaction_group.py +25 -0
- algokit_algod_client/models/_simulate_response.py +44 -0
- algokit_algod_client/models/_simulate_trace_config.py +30 -0
- algokit_algod_client/models/_simulate_transaction_group_result.py +46 -0
- algokit_algod_client/models/_simulate_transaction_result.py +41 -0
- algokit_algod_client/models/_simulate_unnamed_resources_accessed.py +64 -0
- algokit_algod_client/models/_simulation_eval_overrides.py +40 -0
- algokit_algod_client/models/_simulation_opcode_trace_unit.py +55 -0
- algokit_algod_client/models/_simulation_transaction_exec_trace.py +82 -0
- algokit_algod_client/models/_source_map.py +30 -0
- algokit_algod_client/models/_state_delta.py +6 -0
- algokit_algod_client/models/_state_proof.py +28 -0
- algokit_algod_client/models/_state_proof_message.py +44 -0
- algokit_algod_client/models/_supply_response.py +26 -0
- algokit_algod_client/models/_teal_key_value.py +28 -0
- algokit_algod_client/models/_teal_key_value_store.py +6 -0
- algokit_algod_client/models/_teal_value.py +32 -0
- algokit_algod_client/models/_transaction_group_ledger_state_deltas_for_round_response.py +21 -0
- algokit_algod_client/models/_transaction_parameters_response.py +45 -0
- algokit_algod_client/models/_transaction_proof.py +44 -0
- algokit_algod_client/models/_version_contains_the_current_algod_version.py +38 -0
- algokit_algod_client/models/suggested_params.py +42 -0
- algokit_algod_client/py.typed +1 -0
- algokit_algod_client/types.py +7 -0
- algokit_algosdk/__init__.py +38 -0
- algokit_algosdk/account.py +32 -0
- algokit_algosdk/app_access.py +228 -0
- algokit_algosdk/box_reference.py +100 -0
- algokit_algosdk/constants.py +147 -0
- algokit_algosdk/encoding.py +89 -0
- algokit_algosdk/error.py +180 -0
- algokit_algosdk/logic.py +61 -0
- algokit_algosdk/logicsig.py +218 -0
- algokit_algosdk/mnemonic.py +216 -0
- algokit_algosdk/multisig.py +161 -0
- algokit_algosdk/py.typed +0 -0
- algokit_algosdk/transaction.py +596 -0
- algokit_algosdk/wordlist.py +2054 -0
- algokit_common/__init__.py +50 -0
- algokit_common/address.py +34 -0
- algokit_common/constants.py +47 -0
- algokit_common/hashing.py +25 -0
- algokit_common/py.typed +0 -0
- algokit_common/serde/__init__.py +40 -0
- algokit_common/serde/_core.py +610 -0
- algokit_common/serde/_primitives.py +135 -0
- algokit_common/source_map.py +158 -0
- algokit_indexer_client/__init__.py +10 -0
- algokit_indexer_client/client.py +1456 -0
- algokit_indexer_client/config.py +36 -0
- algokit_indexer_client/exceptions.py +59 -0
- algokit_indexer_client/models/__init__.py +148 -0
- algokit_indexer_client/models/_account.py +161 -0
- algokit_indexer_client/models/_account_participation.py +53 -0
- algokit_indexer_client/models/_account_response.py +19 -0
- algokit_indexer_client/models/_account_state_delta.py +29 -0
- algokit_indexer_client/models/_accounts_response.py +29 -0
- algokit_indexer_client/models/_application.py +35 -0
- algokit_indexer_client/models/_application_local_state.py +45 -0
- algokit_indexer_client/models/_application_local_states_response.py +29 -0
- algokit_indexer_client/models/_application_log_data.py +28 -0
- algokit_indexer_client/models/_application_logs_response.py +33 -0
- algokit_indexer_client/models/_application_params.py +62 -0
- algokit_indexer_client/models/_application_response.py +20 -0
- algokit_indexer_client/models/_application_state_schema.py +22 -0
- algokit_indexer_client/models/_applications_response.py +29 -0
- algokit_indexer_client/models/_asset.py +35 -0
- algokit_indexer_client/models/_asset_balances_response.py +29 -0
- algokit_indexer_client/models/_asset_holding.py +41 -0
- algokit_indexer_client/models/_asset_holdings_response.py +29 -0
- algokit_indexer_client/models/_asset_params.py +102 -0
- algokit_indexer_client/models/_asset_response.py +19 -0
- algokit_indexer_client/models/_assets_response.py +29 -0
- algokit_indexer_client/models/_block.py +150 -0
- algokit_indexer_client/models/_block_headers_response.py +29 -0
- algokit_indexer_client/models/_block_rewards.py +38 -0
- algokit_indexer_client/models/_block_upgrade_state.py +34 -0
- algokit_indexer_client/models/_block_upgrade_vote.py +26 -0
- algokit_indexer_client/models/_box.py +36 -0
- algokit_indexer_client/models/_box_descriptor.py +24 -0
- algokit_indexer_client/models/_box_reference.py +28 -0
- algokit_indexer_client/models/_boxes_response.py +29 -0
- algokit_indexer_client/models/_error_response.py +18 -0
- algokit_indexer_client/models/_eval_delta.py +32 -0
- algokit_indexer_client/models/_eval_delta_key_value.py +28 -0
- algokit_indexer_client/models/_hash_factory.py +14 -0
- algokit_indexer_client/models/_hb_proof_fields.py +57 -0
- algokit_indexer_client/models/_health_check.py +42 -0
- algokit_indexer_client/models/_holding_ref.py +23 -0
- algokit_indexer_client/models/_indexer_state_proof_message.py +40 -0
- algokit_indexer_client/models/_locals_ref.py +23 -0
- algokit_indexer_client/models/_merkle_array_proof.py +29 -0
- algokit_indexer_client/models/_mini_asset_holding.py +38 -0
- algokit_indexer_client/models/_on_completion.py +25 -0
- algokit_indexer_client/models/_participation_updates.py +22 -0
- algokit_indexer_client/models/_resource_ref.py +42 -0
- algokit_indexer_client/models/_serde_helpers.py +241 -0
- algokit_indexer_client/models/_state_delta.py +6 -0
- algokit_indexer_client/models/_state_proof_fields.py +57 -0
- algokit_indexer_client/models/_state_proof_participant.py +20 -0
- algokit_indexer_client/models/_state_proof_reveal.py +25 -0
- algokit_indexer_client/models/_state_proof_sig_slot.py +20 -0
- algokit_indexer_client/models/_state_proof_signature.py +37 -0
- algokit_indexer_client/models/_state_proof_tracking.py +32 -0
- algokit_indexer_client/models/_state_proof_verifier.py +24 -0
- algokit_indexer_client/models/_state_schema.py +25 -0
- algokit_indexer_client/models/_teal_key_value.py +28 -0
- algokit_indexer_client/models/_teal_key_value_store.py +6 -0
- algokit_indexer_client/models/_teal_value.py +32 -0
- algokit_indexer_client/models/_transaction.py +213 -0
- algokit_indexer_client/models/_transaction_application.py +105 -0
- algokit_indexer_client/models/_transaction_asset_config.py +31 -0
- algokit_indexer_client/models/_transaction_asset_freeze.py +29 -0
- algokit_indexer_client/models/_transaction_asset_transfer.py +41 -0
- algokit_indexer_client/models/_transaction_heartbeat.py +52 -0
- algokit_indexer_client/models/_transaction_keyreg.py +59 -0
- algokit_indexer_client/models/_transaction_payment.py +33 -0
- algokit_indexer_client/models/_transaction_response.py +19 -0
- algokit_indexer_client/models/_transaction_signature.py +35 -0
- algokit_indexer_client/models/_transaction_signature_logicsig.py +59 -0
- algokit_indexer_client/models/_transaction_signature_multisig.py +36 -0
- algokit_indexer_client/models/_transaction_signature_multisig_subsignature.py +28 -0
- algokit_indexer_client/models/_transaction_state_proof.py +32 -0
- algokit_indexer_client/models/_transactions_response.py +29 -0
- algokit_indexer_client/py.typed +1 -0
- algokit_indexer_client/types.py +7 -0
- algokit_kmd_client/__init__.py +10 -0
- algokit_kmd_client/client.py +1240 -0
- algokit_kmd_client/config.py +36 -0
- algokit_kmd_client/exceptions.py +59 -0
- algokit_kmd_client/models/__init__.py +112 -0
- algokit_kmd_client/models/_classical_signatures.py +4 -0
- algokit_kmd_client/models/_create_wallet_request.py +30 -0
- algokit_kmd_client/models/_create_wallet_response.py +19 -0
- algokit_kmd_client/models/_delete_key_request.py +27 -0
- algokit_kmd_client/models/_delete_multisig_request.py +27 -0
- algokit_kmd_client/models/_digest_represents_a32_byte_value_holding_the256_bit_hash_digest.py +4 -0
- algokit_kmd_client/models/_ed25519_public_key.py +4 -0
- algokit_kmd_client/models/_export_key_request.py +27 -0
- algokit_kmd_client/models/_export_key_response.py +24 -0
- algokit_kmd_client/models/_export_master_key_request.py +22 -0
- algokit_kmd_client/models/_export_master_key_response.py +18 -0
- algokit_kmd_client/models/_export_multisig_request.py +23 -0
- algokit_kmd_client/models/_export_multisig_response.py +26 -0
- algokit_kmd_client/models/_generate_key_request.py +18 -0
- algokit_kmd_client/models/_generate_key_response.py +19 -0
- algokit_kmd_client/models/_import_key_request.py +28 -0
- algokit_kmd_client/models/_import_key_response.py +19 -0
- algokit_kmd_client/models/_import_multisig_request.py +30 -0
- algokit_kmd_client/models/_import_multisig_response.py +19 -0
- algokit_kmd_client/models/_init_wallet_handle_token_request.py +22 -0
- algokit_kmd_client/models/_init_wallet_handle_token_response.py +18 -0
- algokit_kmd_client/models/_list_keys_request.py +18 -0
- algokit_kmd_client/models/_list_keys_response.py +18 -0
- algokit_kmd_client/models/_list_multisig_request.py +18 -0
- algokit_kmd_client/models/_list_multisig_response.py +18 -0
- algokit_kmd_client/models/_list_wallets_request.py +11 -0
- algokit_kmd_client/models/_list_wallets_response.py +25 -0
- algokit_kmd_client/models/_master_derivation_key.py +4 -0
- algokit_kmd_client/models/_multisig_sig.py +33 -0
- algokit_kmd_client/models/_multisig_subsig.py +23 -0
- algokit_kmd_client/models/_public_key.py +4 -0
- algokit_kmd_client/models/_release_wallet_handle_token_request.py +18 -0
- algokit_kmd_client/models/_rename_wallet_request.py +26 -0
- algokit_kmd_client/models/_rename_wallet_response.py +19 -0
- algokit_kmd_client/models/_renew_wallet_handle_token_request.py +18 -0
- algokit_kmd_client/models/_renew_wallet_handle_token_response.py +19 -0
- algokit_kmd_client/models/_serde_helpers.py +241 -0
- algokit_kmd_client/models/_sign_multisig_response.py +24 -0
- algokit_kmd_client/models/_sign_multisig_txn_request.py +45 -0
- algokit_kmd_client/models/_sign_program_multisig_request.py +50 -0
- algokit_kmd_client/models/_sign_program_multisig_response.py +24 -0
- algokit_kmd_client/models/_sign_program_request.py +37 -0
- algokit_kmd_client/models/_sign_program_response.py +24 -0
- algokit_kmd_client/models/_sign_transaction_response.py +24 -0
- algokit_kmd_client/models/_sign_txn_request.py +36 -0
- algokit_kmd_client/models/_signature.py +4 -0
- algokit_kmd_client/models/_tx_type.py +4 -0
- algokit_kmd_client/models/_versions_request.py +11 -0
- algokit_kmd_client/models/_versions_response.py +19 -0
- algokit_kmd_client/models/_wallet.py +38 -0
- algokit_kmd_client/models/_wallet_handle.py +24 -0
- algokit_kmd_client/models/_wallet_info_request.py +18 -0
- algokit_kmd_client/models/_wallet_info_response.py +19 -0
- algokit_kmd_client/py.typed +1 -0
- algokit_kmd_client/types.py +7 -0
- algokit_transact/__init__.py +190 -0
- algokit_transact/codec/__init__.py +0 -0
- algokit_transact/codec/msgpack.py +11 -0
- algokit_transact/codec/serde.py +7 -0
- algokit_transact/codec/signed.py +57 -0
- algokit_transact/codec/transaction.py +65 -0
- algokit_transact/exceptions.py +17 -0
- algokit_transact/logicsig.py +220 -0
- algokit_transact/models/__init__.py +0 -0
- algokit_transact/models/app_call.py +447 -0
- algokit_transact/models/asset_config.py +19 -0
- algokit_transact/models/asset_freeze.py +11 -0
- algokit_transact/models/asset_transfer.py +13 -0
- algokit_transact/models/common.py +17 -0
- algokit_transact/models/heartbeat.py +21 -0
- algokit_transact/models/key_registration.py +14 -0
- algokit_transact/models/payment.py +14 -0
- algokit_transact/models/signed_transaction.py +21 -0
- algokit_transact/models/state_proof.py +150 -0
- algokit_transact/models/transaction.py +88 -0
- algokit_transact/multisig.py +93 -0
- algokit_transact/ops/__init__.py +0 -0
- algokit_transact/ops/fees.py +47 -0
- algokit_transact/ops/group.py +28 -0
- algokit_transact/ops/ids.py +14 -0
- algokit_transact/ops/validate.py +503 -0
- algokit_transact/py.typed +0 -0
- algokit_transact/signer.py +195 -0
- algokit_transact/signing/__init__.py +0 -0
- algokit_transact/signing/logic_signature.py +19 -0
- algokit_transact/signing/multisig.py +84 -0
- algokit_transact/signing/types.py +39 -0
- algokit_transact/signing/validation.py +63 -0
- algokit_utils/__init__.py +23 -0
- algokit_utils/_debugging.py +304 -0
- algokit_utils/accounts/__init__.py +2 -0
- algokit_utils/accounts/account_manager.py +1051 -0
- algokit_utils/accounts/kmd_account_manager.py +206 -0
- algokit_utils/algo25.py +46 -0
- algokit_utils/algorand.py +383 -0
- algokit_utils/applications/__init__.py +7 -0
- algokit_utils/applications/abi.py +280 -0
- algokit_utils/applications/app_client.py +2193 -0
- algokit_utils/applications/app_deployer.py +788 -0
- algokit_utils/applications/app_factory.py +1140 -0
- algokit_utils/applications/app_manager.py +575 -0
- algokit_utils/applications/app_spec/__init__.py +6 -0
- algokit_utils/applications/enums.py +40 -0
- algokit_utils/assets/__init__.py +1 -0
- algokit_utils/assets/asset_manager.py +344 -0
- algokit_utils/clients/__init__.py +41 -0
- algokit_utils/clients/client_manager.py +756 -0
- algokit_utils/clients/dispenser_api_client.py +212 -0
- algokit_utils/common.py +40 -0
- algokit_utils/config.py +159 -0
- algokit_utils/errors/__init__.py +1 -0
- algokit_utils/errors/logic_error.py +160 -0
- algokit_utils/models/__init__.py +7 -0
- algokit_utils/models/account.py +12 -0
- algokit_utils/models/amount.py +198 -0
- algokit_utils/models/application.py +90 -0
- algokit_utils/models/network.py +29 -0
- algokit_utils/models/simulate.py +7 -0
- algokit_utils/models/state.py +53 -0
- algokit_utils/models/transaction.py +49 -0
- algokit_utils/protocols/__init__.py +3 -0
- algokit_utils/protocols/account.py +11 -0
- algokit_utils/protocols/signer.py +17 -0
- algokit_utils/protocols/typed_clients.py +110 -0
- algokit_utils/py.typed +0 -0
- algokit_utils/transact.py +195 -0
- algokit_utils/transactions/__init__.py +3 -0
- algokit_utils/transactions/builders/__init__.py +67 -0
- algokit_utils/transactions/builders/app.py +248 -0
- algokit_utils/transactions/builders/asset.py +256 -0
- algokit_utils/transactions/builders/common.py +263 -0
- algokit_utils/transactions/builders/keyreg.py +103 -0
- algokit_utils/transactions/builders/method_call.py +380 -0
- algokit_utils/transactions/builders/payment.py +43 -0
- algokit_utils/transactions/composer_resources.py +409 -0
- algokit_utils/transactions/fee_coverage.py +79 -0
- algokit_utils/transactions/helpers.py +9 -0
- algokit_utils/transactions/transaction_composer.py +1574 -0
- algokit_utils/transactions/transaction_creator.py +699 -0
- algokit_utils/transactions/transaction_sender.py +1240 -0
- algokit_utils/transactions/types.py +262 -0
- algokit_utils-5.0.0a3.dist-info/METADATA +105 -0
- algokit_utils-5.0.0a3.dist-info/RECORD +337 -0
- 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
|