algokit-utils 3.0.0b1__py3-none-any.whl → 3.0.0b2__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.
Potentially problematic release.
This version of algokit-utils might be problematic. Click here for more details.
- algokit_utils/__init__.py +23 -183
- algokit_utils/_debugging.py +123 -97
- algokit_utils/_legacy_v2/__init__.py +177 -0
- algokit_utils/{_ensure_funded.py → _legacy_v2/_ensure_funded.py} +19 -18
- algokit_utils/{_transfer.py → _legacy_v2/_transfer.py} +24 -23
- algokit_utils/_legacy_v2/account.py +203 -0
- algokit_utils/_legacy_v2/application_client.py +1471 -0
- algokit_utils/_legacy_v2/application_specification.py +21 -0
- algokit_utils/_legacy_v2/asset.py +168 -0
- algokit_utils/_legacy_v2/common.py +28 -0
- algokit_utils/_legacy_v2/deploy.py +822 -0
- algokit_utils/_legacy_v2/logic_error.py +14 -0
- algokit_utils/{models.py → _legacy_v2/models.py} +19 -142
- algokit_utils/_legacy_v2/network_clients.py +140 -0
- algokit_utils/account.py +12 -183
- algokit_utils/accounts/__init__.py +2 -0
- algokit_utils/accounts/account_manager.py +909 -0
- algokit_utils/accounts/kmd_account_manager.py +159 -0
- algokit_utils/algorand.py +265 -0
- algokit_utils/application_client.py +9 -1453
- algokit_utils/application_specification.py +39 -197
- algokit_utils/applications/__init__.py +7 -0
- algokit_utils/applications/abi.py +276 -0
- algokit_utils/applications/app_client.py +2056 -0
- algokit_utils/applications/app_deployer.py +600 -0
- algokit_utils/applications/app_factory.py +826 -0
- algokit_utils/applications/app_manager.py +470 -0
- algokit_utils/applications/app_spec/__init__.py +2 -0
- algokit_utils/applications/app_spec/arc32.py +207 -0
- algokit_utils/applications/app_spec/arc56.py +1023 -0
- algokit_utils/applications/enums.py +40 -0
- algokit_utils/asset.py +32 -168
- algokit_utils/assets/__init__.py +1 -0
- algokit_utils/assets/asset_manager.py +320 -0
- algokit_utils/beta/_utils.py +36 -0
- algokit_utils/beta/account_manager.py +4 -195
- algokit_utils/beta/algorand_client.py +4 -314
- algokit_utils/beta/client_manager.py +5 -74
- algokit_utils/beta/composer.py +5 -712
- algokit_utils/clients/__init__.py +2 -0
- algokit_utils/clients/client_manager.py +656 -0
- algokit_utils/clients/dispenser_api_client.py +192 -0
- algokit_utils/common.py +8 -26
- algokit_utils/config.py +71 -18
- algokit_utils/deploy.py +7 -892
- algokit_utils/dispenser_api.py +8 -176
- algokit_utils/errors/__init__.py +1 -0
- algokit_utils/errors/logic_error.py +121 -0
- algokit_utils/logic_error.py +7 -80
- algokit_utils/models/__init__.py +8 -0
- algokit_utils/models/account.py +193 -0
- algokit_utils/models/amount.py +198 -0
- algokit_utils/models/application.py +61 -0
- algokit_utils/models/network.py +25 -0
- algokit_utils/models/simulate.py +11 -0
- algokit_utils/models/state.py +59 -0
- algokit_utils/models/transaction.py +100 -0
- algokit_utils/network_clients.py +7 -152
- algokit_utils/protocols/__init__.py +2 -0
- algokit_utils/protocols/account.py +22 -0
- algokit_utils/protocols/typed_clients.py +108 -0
- algokit_utils/transactions/__init__.py +3 -0
- algokit_utils/transactions/transaction_composer.py +2293 -0
- algokit_utils/transactions/transaction_creator.py +156 -0
- algokit_utils/transactions/transaction_sender.py +574 -0
- {algokit_utils-3.0.0b1.dist-info → algokit_utils-3.0.0b2.dist-info}/METADATA +12 -7
- algokit_utils-3.0.0b2.dist-info/RECORD +70 -0
- {algokit_utils-3.0.0b1.dist-info → algokit_utils-3.0.0b2.dist-info}/WHEEL +1 -1
- algokit_utils-3.0.0b1.dist-info/RECORD +0 -24
- {algokit_utils-3.0.0b1.dist-info → algokit_utils-3.0.0b2.dist-info}/LICENSE +0 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""AlgoKit Python Utilities (Legacy V2) - a set of utilities for building solutions on Algorand
|
|
2
|
+
|
|
3
|
+
This module provides commonly used utilities and types at the root level for convenience.
|
|
4
|
+
For more specific functionality, import directly from the relevant submodules:
|
|
5
|
+
|
|
6
|
+
from algokit_utils.accounts import KmdAccountManager
|
|
7
|
+
from algokit_utils.applications import AppClient
|
|
8
|
+
from algokit_utils.applications.app_spec import Arc52Contract
|
|
9
|
+
etc.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
# Debugging utilities
|
|
13
|
+
from algokit_utils._legacy_v2._ensure_funded import (
|
|
14
|
+
EnsureBalanceParameters,
|
|
15
|
+
EnsureFundedResponse,
|
|
16
|
+
ensure_funded,
|
|
17
|
+
)
|
|
18
|
+
from algokit_utils._legacy_v2._transfer import (
|
|
19
|
+
TransferAssetParameters,
|
|
20
|
+
TransferParameters,
|
|
21
|
+
transfer,
|
|
22
|
+
transfer_asset,
|
|
23
|
+
)
|
|
24
|
+
from algokit_utils._legacy_v2.account import (
|
|
25
|
+
create_kmd_wallet_account,
|
|
26
|
+
get_account,
|
|
27
|
+
get_account_from_mnemonic,
|
|
28
|
+
get_dispenser_account,
|
|
29
|
+
get_kmd_wallet_account,
|
|
30
|
+
get_localnet_default_account,
|
|
31
|
+
get_or_create_kmd_wallet_account,
|
|
32
|
+
)
|
|
33
|
+
from algokit_utils._legacy_v2.application_client import (
|
|
34
|
+
ApplicationClient,
|
|
35
|
+
execute_atc_with_logic_error,
|
|
36
|
+
get_next_version,
|
|
37
|
+
get_sender_from_signer,
|
|
38
|
+
num_extra_program_pages,
|
|
39
|
+
)
|
|
40
|
+
from algokit_utils._legacy_v2.application_specification import (
|
|
41
|
+
ApplicationSpecification,
|
|
42
|
+
AppSpecStateDict,
|
|
43
|
+
CallConfig,
|
|
44
|
+
DefaultArgumentDict,
|
|
45
|
+
DefaultArgumentType,
|
|
46
|
+
MethodConfigDict,
|
|
47
|
+
MethodHints,
|
|
48
|
+
OnCompleteActionName,
|
|
49
|
+
)
|
|
50
|
+
from algokit_utils._legacy_v2.asset import opt_in, opt_out
|
|
51
|
+
from algokit_utils._legacy_v2.common import Program
|
|
52
|
+
from algokit_utils._legacy_v2.deploy import (
|
|
53
|
+
NOTE_PREFIX,
|
|
54
|
+
ABICallArgs,
|
|
55
|
+
ABICallArgsDict,
|
|
56
|
+
ABICreateCallArgs,
|
|
57
|
+
ABICreateCallArgsDict,
|
|
58
|
+
AppDeployMetaData,
|
|
59
|
+
AppLookup,
|
|
60
|
+
AppMetaData,
|
|
61
|
+
AppReference,
|
|
62
|
+
DeployCallArgs,
|
|
63
|
+
DeployCallArgsDict,
|
|
64
|
+
DeployCreateCallArgs,
|
|
65
|
+
DeployCreateCallArgsDict,
|
|
66
|
+
DeploymentFailedError,
|
|
67
|
+
DeployResponse,
|
|
68
|
+
TemplateValueDict,
|
|
69
|
+
TemplateValueMapping,
|
|
70
|
+
get_app_id_from_tx_id,
|
|
71
|
+
get_creator_apps,
|
|
72
|
+
replace_template_variables,
|
|
73
|
+
)
|
|
74
|
+
from algokit_utils._legacy_v2.models import (
|
|
75
|
+
ABIArgsDict,
|
|
76
|
+
ABIMethod,
|
|
77
|
+
ABITransactionResponse,
|
|
78
|
+
Account,
|
|
79
|
+
CommonCallParameters,
|
|
80
|
+
CommonCallParametersDict,
|
|
81
|
+
CreateCallParameters,
|
|
82
|
+
CreateCallParametersDict,
|
|
83
|
+
CreateTransactionParameters,
|
|
84
|
+
OnCompleteCallParameters,
|
|
85
|
+
OnCompleteCallParametersDict,
|
|
86
|
+
TransactionParameters,
|
|
87
|
+
TransactionParametersDict,
|
|
88
|
+
TransactionResponse,
|
|
89
|
+
)
|
|
90
|
+
from algokit_utils._legacy_v2.network_clients import (
|
|
91
|
+
AlgoClientConfig,
|
|
92
|
+
get_algod_client,
|
|
93
|
+
get_algonode_config,
|
|
94
|
+
get_default_localnet_config,
|
|
95
|
+
get_indexer_client,
|
|
96
|
+
get_kmd_client_from_algod_client,
|
|
97
|
+
is_localnet,
|
|
98
|
+
is_mainnet,
|
|
99
|
+
is_testnet,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
__all__ = [
|
|
103
|
+
"NOTE_PREFIX",
|
|
104
|
+
"ABIArgsDict",
|
|
105
|
+
"ABICallArgs",
|
|
106
|
+
"ABICallArgsDict",
|
|
107
|
+
"ABICreateCallArgs",
|
|
108
|
+
"ABICreateCallArgsDict",
|
|
109
|
+
"ABIMethod",
|
|
110
|
+
"ABITransactionResponse",
|
|
111
|
+
"Account",
|
|
112
|
+
"AlgoClientConfig",
|
|
113
|
+
"AppDeployMetaData",
|
|
114
|
+
"AppLookup",
|
|
115
|
+
"AppMetaData",
|
|
116
|
+
"AppReference",
|
|
117
|
+
"AppSpecStateDict",
|
|
118
|
+
"ApplicationClient",
|
|
119
|
+
"ApplicationSpecification",
|
|
120
|
+
"CallConfig",
|
|
121
|
+
"CommonCallParameters",
|
|
122
|
+
"CommonCallParametersDict",
|
|
123
|
+
"CreateCallParameters",
|
|
124
|
+
"CreateCallParametersDict",
|
|
125
|
+
"CreateTransactionParameters",
|
|
126
|
+
"DefaultArgumentDict",
|
|
127
|
+
"DefaultArgumentType",
|
|
128
|
+
"DeployCallArgs",
|
|
129
|
+
"DeployCallArgsDict",
|
|
130
|
+
"DeployCreateCallArgs",
|
|
131
|
+
"DeployCreateCallArgsDict",
|
|
132
|
+
"DeployResponse",
|
|
133
|
+
"DeploymentFailedError",
|
|
134
|
+
"EnsureBalanceParameters",
|
|
135
|
+
"EnsureFundedResponse",
|
|
136
|
+
"MethodConfigDict",
|
|
137
|
+
"MethodHints",
|
|
138
|
+
"OnCompleteActionName",
|
|
139
|
+
"OnCompleteCallParameters",
|
|
140
|
+
"OnCompleteCallParametersDict",
|
|
141
|
+
"Program",
|
|
142
|
+
"TemplateValueDict",
|
|
143
|
+
"TemplateValueMapping",
|
|
144
|
+
"TransactionParameters",
|
|
145
|
+
"TransactionParametersDict",
|
|
146
|
+
"TransactionResponse",
|
|
147
|
+
"TransferAssetParameters",
|
|
148
|
+
"TransferParameters",
|
|
149
|
+
# Legacy v2 functions
|
|
150
|
+
"create_kmd_wallet_account",
|
|
151
|
+
"ensure_funded",
|
|
152
|
+
"execute_atc_with_logic_error",
|
|
153
|
+
"get_account",
|
|
154
|
+
"get_account_from_mnemonic",
|
|
155
|
+
"get_algod_client",
|
|
156
|
+
"get_algonode_config",
|
|
157
|
+
"get_app_id_from_tx_id",
|
|
158
|
+
"get_creator_apps",
|
|
159
|
+
"get_default_localnet_config",
|
|
160
|
+
"get_dispenser_account",
|
|
161
|
+
"get_indexer_client",
|
|
162
|
+
"get_kmd_client_from_algod_client",
|
|
163
|
+
"get_kmd_wallet_account",
|
|
164
|
+
"get_localnet_default_account",
|
|
165
|
+
"get_next_version",
|
|
166
|
+
"get_or_create_kmd_wallet_account",
|
|
167
|
+
"get_sender_from_signer",
|
|
168
|
+
"is_localnet",
|
|
169
|
+
"is_mainnet",
|
|
170
|
+
"is_testnet",
|
|
171
|
+
"num_extra_program_pages",
|
|
172
|
+
"opt_in",
|
|
173
|
+
"opt_out",
|
|
174
|
+
"replace_template_variables",
|
|
175
|
+
"transfer",
|
|
176
|
+
"transfer_asset",
|
|
177
|
+
]
|
|
@@ -4,15 +4,16 @@ from algosdk.account import address_from_private_key
|
|
|
4
4
|
from algosdk.atomic_transaction_composer import AccountTransactionSigner
|
|
5
5
|
from algosdk.transaction import SuggestedParams
|
|
6
6
|
from algosdk.v2client.algod import AlgodClient
|
|
7
|
+
from typing_extensions import deprecated
|
|
7
8
|
|
|
8
|
-
from algokit_utils._transfer import TransferParameters, transfer
|
|
9
|
-
from algokit_utils.account import get_dispenser_account
|
|
10
|
-
from algokit_utils.
|
|
9
|
+
from algokit_utils._legacy_v2._transfer import TransferParameters, transfer
|
|
10
|
+
from algokit_utils._legacy_v2.account import get_dispenser_account
|
|
11
|
+
from algokit_utils._legacy_v2.models import Account
|
|
12
|
+
from algokit_utils._legacy_v2.network_clients import is_testnet
|
|
13
|
+
from algokit_utils.clients.dispenser_api_client import (
|
|
11
14
|
DispenserAssetName,
|
|
12
15
|
TestNetDispenserApiClient,
|
|
13
16
|
)
|
|
14
|
-
from algokit_utils.models import Account
|
|
15
|
-
from algokit_utils.network_clients import is_testnet
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@dataclass(kw_only=True)
|
|
@@ -63,7 +64,7 @@ def _get_address_to_fund(parameters: EnsureBalanceParameters) -> str:
|
|
|
63
64
|
if isinstance(parameters.account_to_fund, str):
|
|
64
65
|
return parameters.account_to_fund
|
|
65
66
|
else:
|
|
66
|
-
return str(address_from_private_key(parameters.account_to_fund.private_key))
|
|
67
|
+
return str(address_from_private_key(parameters.account_to_fund.private_key))
|
|
67
68
|
|
|
68
69
|
|
|
69
70
|
def _get_account_info(client: AlgodClient, address_to_fund: str) -> dict:
|
|
@@ -111,28 +112,28 @@ def _fund_using_transfer(
|
|
|
111
112
|
fee_micro_algos=parameters.fee_micro_algos,
|
|
112
113
|
),
|
|
113
114
|
)
|
|
114
|
-
transaction_id = response.get_txid()
|
|
115
|
+
transaction_id = response.get_txid()
|
|
115
116
|
return EnsureFundedResponse(transaction_id=transaction_id, amount=response.amt)
|
|
116
117
|
|
|
117
118
|
|
|
119
|
+
@deprecated(
|
|
120
|
+
"Use `algorand.account.ensure_funded()`, `algorand.account.ensure_funded_from_environment()`, "
|
|
121
|
+
"or `algorand.account.ensure_funded_from_testnet_dispenser_api()` instead"
|
|
122
|
+
)
|
|
118
123
|
def ensure_funded(
|
|
119
124
|
client: AlgodClient,
|
|
120
125
|
parameters: EnsureBalanceParameters,
|
|
121
126
|
) -> EnsureFundedResponse | None:
|
|
122
127
|
"""
|
|
123
|
-
Funds a given account using a funding source
|
|
124
|
-
(accounting for ALGOs locked in minimum balance requirement)
|
|
125
|
-
see <https://developer.algorand.org/docs/get-details/accounts/#minimum-balance>
|
|
126
|
-
|
|
128
|
+
Funds a given account using a funding source to ensure it has sufficient spendable ALGOs.
|
|
127
129
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
specifies the account to fund and the minimum spending balance.
|
|
130
|
+
Ensures the target account has enough ALGOs free to spend after accounting for ALGOs locked in minimum balance
|
|
131
|
+
requirements. See https://developer.algorand.org/docs/get-details/accounts/#minimum-balance for details on minimum
|
|
132
|
+
balance requirements.
|
|
132
133
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
:param client: An instance of the AlgodClient class from the AlgoSDK library
|
|
135
|
+
:param parameters: Parameters specifying the account to fund and minimum spending balance requirements
|
|
136
|
+
:return: If funds are needed, returns payment transaction details or dispenser API response. Returns None if no funding needed
|
|
136
137
|
"""
|
|
137
138
|
|
|
138
139
|
address_to_fund = _get_address_to_fund(parameters)
|
|
@@ -6,30 +6,29 @@ import algosdk.transaction
|
|
|
6
6
|
from algosdk.account import address_from_private_key
|
|
7
7
|
from algosdk.atomic_transaction_composer import AccountTransactionSigner
|
|
8
8
|
from algosdk.transaction import AssetTransferTxn, PaymentTxn, SuggestedParams
|
|
9
|
+
from typing_extensions import deprecated
|
|
9
10
|
|
|
10
|
-
from algokit_utils.models import Account
|
|
11
|
+
from algokit_utils._legacy_v2.models import Account
|
|
11
12
|
|
|
12
13
|
if TYPE_CHECKING:
|
|
13
14
|
from algosdk.v2client.algod import AlgodClient
|
|
14
15
|
|
|
15
|
-
__all__ = ["
|
|
16
|
+
__all__ = ["TransferAssetParameters", "TransferParameters", "transfer", "transfer_asset"]
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
@dataclasses.dataclass(kw_only=True)
|
|
20
21
|
class TransferParametersBase:
|
|
21
|
-
"""Parameters for transferring µALGOs between accounts
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
max_fee_micro_algos (int | None): (optional) The maximum fee that you are happy to pay (default: unbounded)
|
|
32
|
-
- if this is set it's possible the transaction could get rejected during network congestion
|
|
22
|
+
"""Parameters for transferring µALGOs between accounts.
|
|
23
|
+
|
|
24
|
+
This class contains the base parameters needed for transferring µALGOs between Algorand accounts.
|
|
25
|
+
|
|
26
|
+
:ivar from_account: The account (with private key) or signer that will send the µALGOs
|
|
27
|
+
:ivar to_address: The account address that will receive the µALGOs
|
|
28
|
+
:ivar suggested_params: Transaction parameters, defaults to None
|
|
29
|
+
:ivar note: Transaction note, defaults to None
|
|
30
|
+
:ivar fee_micro_algos: The flat fee you want to pay, useful for covering extra fees in a transaction group or app call, defaults to None
|
|
31
|
+
:ivar max_fee_micro_algos: The maximum fee that you are happy to pay - if this is set it's possible the transaction could get rejected during network congestion, defaults to None
|
|
33
32
|
"""
|
|
34
33
|
|
|
35
34
|
from_account: Account | AccountTransactionSigner
|
|
@@ -49,13 +48,13 @@ class TransferParameters(TransferParametersBase):
|
|
|
49
48
|
|
|
50
49
|
@dataclasses.dataclass(kw_only=True)
|
|
51
50
|
class TransferAssetParameters(TransferParametersBase):
|
|
52
|
-
"""Parameters for transferring assets between accounts
|
|
51
|
+
"""Parameters for transferring assets between accounts.
|
|
52
|
+
|
|
53
|
+
Defines the parameters needed to transfer Algorand Standard Assets (ASAs) between accounts.
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
clawback_from (str | None): An address of a target account from which to perform a clawback operation. Please
|
|
58
|
-
note, in such cases senderAccount must be equal to clawback field on ASA metadata.
|
|
55
|
+
:param asset_id: The asset id that will be transferred
|
|
56
|
+
:param amount: The amount of the asset to send
|
|
57
|
+
:param clawback_from: An address of a target account from which to perform a clawback operation. Please note, in such cases senderAccount must be equal to clawback field on ASA metadata, defaults to None
|
|
59
58
|
"""
|
|
60
59
|
|
|
61
60
|
asset_id: int
|
|
@@ -80,6 +79,7 @@ def _check_fee(transaction: PaymentTxn | AssetTransferTxn, max_fee: int | None)
|
|
|
80
79
|
)
|
|
81
80
|
|
|
82
81
|
|
|
82
|
+
@deprecated("Use the `TransactionComposer` abstraction instead to construct appropriate transfer transactions")
|
|
83
83
|
def transfer(client: "AlgodClient", parameters: TransferParameters) -> PaymentTxn:
|
|
84
84
|
"""Transfer µALGOs between accounts"""
|
|
85
85
|
|
|
@@ -93,13 +93,14 @@ def transfer(client: "AlgodClient", parameters: TransferParameters) -> PaymentTx
|
|
|
93
93
|
amt=params.micro_algos,
|
|
94
94
|
note=params.note.encode("utf-8") if isinstance(params.note, str) else params.note,
|
|
95
95
|
sp=params.suggested_params,
|
|
96
|
-
)
|
|
96
|
+
)
|
|
97
97
|
|
|
98
98
|
result = _send_transaction(client=client, transaction=transaction, parameters=params)
|
|
99
99
|
assert isinstance(result, PaymentTxn)
|
|
100
100
|
return result
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
@deprecated("Use the `TransactionComposer` abstraction instead to construct appropriate transfer transactions")
|
|
103
104
|
def transfer_asset(client: "AlgodClient", parameters: TransferAssetParameters) -> AssetTransferTxn:
|
|
104
105
|
"""Transfer assets between accounts"""
|
|
105
106
|
|
|
@@ -117,7 +118,7 @@ def transfer_asset(client: "AlgodClient", parameters: TransferAssetParameters) -
|
|
|
117
118
|
note=params.note,
|
|
118
119
|
index=params.asset_id,
|
|
119
120
|
rekey_to=None,
|
|
120
|
-
)
|
|
121
|
+
)
|
|
121
122
|
|
|
122
123
|
result = _send_transaction(client=client, transaction=xfer_txn, parameters=params)
|
|
123
124
|
assert isinstance(result, AssetTransferTxn)
|
|
@@ -148,5 +149,5 @@ def _get_address(account: Account | AccountTransactionSigner) -> str:
|
|
|
148
149
|
if type(account) is Account:
|
|
149
150
|
return account.address
|
|
150
151
|
else:
|
|
151
|
-
address = address_from_private_key(account.private_key)
|
|
152
|
+
address = address_from_private_key(account.private_key)
|
|
152
153
|
return str(address)
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from algosdk.account import address_from_private_key
|
|
6
|
+
from algosdk.mnemonic import from_private_key, to_private_key
|
|
7
|
+
from algosdk.util import algos_to_microalgos
|
|
8
|
+
from typing_extensions import deprecated
|
|
9
|
+
|
|
10
|
+
from algokit_utils._legacy_v2._transfer import TransferParameters, transfer
|
|
11
|
+
from algokit_utils._legacy_v2.models import Account
|
|
12
|
+
from algokit_utils._legacy_v2.network_clients import get_kmd_client_from_algod_client, is_localnet
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
|
|
17
|
+
from algosdk.kmd import KMDClient
|
|
18
|
+
from algosdk.v2client.algod import AlgodClient
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"create_kmd_wallet_account",
|
|
22
|
+
"get_account",
|
|
23
|
+
"get_account_from_mnemonic",
|
|
24
|
+
"get_dispenser_account",
|
|
25
|
+
"get_kmd_wallet_account",
|
|
26
|
+
"get_localnet_default_account",
|
|
27
|
+
"get_or_create_kmd_wallet_account",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
_DEFAULT_ACCOUNT_MINIMUM_BALANCE = 1_000_000_000
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@deprecated(
|
|
35
|
+
"Use `algorand.account.from_mnemonic()` instead. Example: " "`account = algorand.account.from_mnemonic(mnemonic)`"
|
|
36
|
+
)
|
|
37
|
+
def get_account_from_mnemonic(mnemonic: str) -> Account:
|
|
38
|
+
"""Convert a mnemonic (25 word passphrase) into an Account"""
|
|
39
|
+
private_key = to_private_key(mnemonic)
|
|
40
|
+
address = str(address_from_private_key(private_key))
|
|
41
|
+
return Account(private_key=private_key, address=address)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@deprecated("Use `algorand.account.from_kmd()` instead. Example: " "`account = algorand.account.from_kmd(name)`")
|
|
45
|
+
def create_kmd_wallet_account(kmd_client: "KMDClient", name: str) -> Account:
|
|
46
|
+
"""Creates a wallet with specified name"""
|
|
47
|
+
wallet_id = kmd_client.create_wallet(name, "")["id"]
|
|
48
|
+
wallet_handle = kmd_client.init_wallet_handle(wallet_id, "")
|
|
49
|
+
kmd_client.generate_key(wallet_handle)
|
|
50
|
+
|
|
51
|
+
key_ids: list[str] = kmd_client.list_keys(wallet_handle)
|
|
52
|
+
account_key = key_ids[0]
|
|
53
|
+
|
|
54
|
+
private_account_key = kmd_client.export_key(wallet_handle, "", account_key)
|
|
55
|
+
return get_account_from_mnemonic(from_private_key(private_account_key))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@deprecated(
|
|
59
|
+
"Use `algorand.account.from_kmd()` instead. Example: "
|
|
60
|
+
"`account = algorand.account.from_kmd(name, fund_with=AlgoAmount.from_algo(1000))`"
|
|
61
|
+
)
|
|
62
|
+
def get_or_create_kmd_wallet_account(
|
|
63
|
+
client: "AlgodClient", name: str, fund_with_algos: float = 1000, kmd_client: "KMDClient | None" = None
|
|
64
|
+
) -> Account:
|
|
65
|
+
"""Returns a wallet with specified name, or creates one if not found"""
|
|
66
|
+
kmd_client = kmd_client or get_kmd_client_from_algod_client(client)
|
|
67
|
+
account = get_kmd_wallet_account(client, kmd_client, name)
|
|
68
|
+
|
|
69
|
+
if account:
|
|
70
|
+
account_info = client.account_info(account.address)
|
|
71
|
+
assert isinstance(account_info, dict)
|
|
72
|
+
if account_info["amount"] > 0:
|
|
73
|
+
return account
|
|
74
|
+
logger.debug(f"Found existing account in LocalNet with name '{name}', but no funds in the account.")
|
|
75
|
+
else:
|
|
76
|
+
account = create_kmd_wallet_account(kmd_client, name)
|
|
77
|
+
|
|
78
|
+
logger.debug(
|
|
79
|
+
f"Couldn't find existing account in LocalNet with name '{name}'. "
|
|
80
|
+
f"So created account {account.address} with keys stored in KMD."
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
logger.debug(f"Funding account {account.address} with {fund_with_algos} ALGOs")
|
|
84
|
+
|
|
85
|
+
if fund_with_algos:
|
|
86
|
+
transfer(
|
|
87
|
+
client,
|
|
88
|
+
TransferParameters(
|
|
89
|
+
from_account=get_dispenser_account(client),
|
|
90
|
+
to_address=account.address,
|
|
91
|
+
micro_algos=algos_to_microalgos(fund_with_algos),
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return account
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _is_default_account(account: dict[str, Any]) -> bool:
|
|
99
|
+
return bool(account["status"] != "Offline" and account["amount"] > _DEFAULT_ACCOUNT_MINIMUM_BALANCE)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@deprecated(
|
|
103
|
+
"Use `algorand.account.from_kmd()` instead. Example: "
|
|
104
|
+
"`account = algorand.account.from_kmd('unencrypted-default-wallet', lambda a: a['status'] != 'Offline' and a['amount'] > 1_000_000_000)`"
|
|
105
|
+
)
|
|
106
|
+
def get_localnet_default_account(client: "AlgodClient") -> Account:
|
|
107
|
+
"""Returns the default Account in a LocalNet instance"""
|
|
108
|
+
if not is_localnet(client):
|
|
109
|
+
raise Exception("Can't get a default account from non LocalNet network")
|
|
110
|
+
|
|
111
|
+
account = get_kmd_wallet_account(
|
|
112
|
+
client, get_kmd_client_from_algod_client(client), "unencrypted-default-wallet", _is_default_account
|
|
113
|
+
)
|
|
114
|
+
assert account
|
|
115
|
+
return account
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@deprecated(
|
|
119
|
+
"Use `algorand.account.dispenser_from_environment()` or `algorand.account.localnet_dispenser()` instead. "
|
|
120
|
+
"Example: `dispenser = algorand.account.dispenser_from_environment()`"
|
|
121
|
+
)
|
|
122
|
+
def get_dispenser_account(client: "AlgodClient") -> Account:
|
|
123
|
+
"""Returns an Account based on DISPENSER_MNENOMIC environment variable or the default account on LocalNet"""
|
|
124
|
+
if is_localnet(client):
|
|
125
|
+
return get_localnet_default_account(client)
|
|
126
|
+
return get_account(client, "DISPENSER")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@deprecated(
|
|
130
|
+
"Use `algorand.account.from_kmd()` instead. Example: " "`account = algorand.account.from_kmd(name, predicate)`"
|
|
131
|
+
)
|
|
132
|
+
def get_kmd_wallet_account(
|
|
133
|
+
client: "AlgodClient",
|
|
134
|
+
kmd_client: "KMDClient",
|
|
135
|
+
name: str,
|
|
136
|
+
predicate: "Callable[[dict[str, Any]], bool] | None" = None,
|
|
137
|
+
) -> Account | None:
|
|
138
|
+
"""Returns wallet matching specified name and predicate or None if not found"""
|
|
139
|
+
wallets: list[dict] = kmd_client.list_wallets()
|
|
140
|
+
|
|
141
|
+
wallet = next((w for w in wallets if w["name"] == name), None)
|
|
142
|
+
if wallet is None:
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
wallet_id = wallet["id"]
|
|
146
|
+
wallet_handle = kmd_client.init_wallet_handle(wallet_id, "")
|
|
147
|
+
key_ids: list[str] = kmd_client.list_keys(wallet_handle)
|
|
148
|
+
matched_account_key = None
|
|
149
|
+
if predicate:
|
|
150
|
+
for key in key_ids:
|
|
151
|
+
account = client.account_info(key)
|
|
152
|
+
assert isinstance(account, dict)
|
|
153
|
+
if predicate(account):
|
|
154
|
+
matched_account_key = key
|
|
155
|
+
else:
|
|
156
|
+
matched_account_key = next(key_ids.__iter__(), None)
|
|
157
|
+
|
|
158
|
+
if not matched_account_key:
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
private_account_key = kmd_client.export_key(wallet_handle, "", matched_account_key)
|
|
162
|
+
return get_account_from_mnemonic(from_private_key(private_account_key))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@deprecated(
|
|
166
|
+
"Use `algorand.account.from_environment()` or `algorand.account.from_kmd()` or `algorand.account.random()` instead. "
|
|
167
|
+
"Example: "
|
|
168
|
+
"`account = algorand.account.from_environment('ACCOUNT', AlgoAmount.from_algo(1000))`"
|
|
169
|
+
)
|
|
170
|
+
def get_account(
|
|
171
|
+
client: "AlgodClient", name: str, fund_with_algos: float = 1000, kmd_client: "KMDClient | None" = None
|
|
172
|
+
) -> Account:
|
|
173
|
+
"""Returns an Algorand account with private key loaded by convention based on the given name identifier.
|
|
174
|
+
Returns an Algorand account with private key loaded by convention based on the given name identifier.
|
|
175
|
+
|
|
176
|
+
For non-LocalNet environments, loads the mnemonic secret from environment variable {name}_MNEMONIC.
|
|
177
|
+
For LocalNet environments, loads or creates an account from a KMD wallet named {name}.
|
|
178
|
+
|
|
179
|
+
:example:
|
|
180
|
+
>>> # If you have a mnemonic secret loaded into `os.environ["ACCOUNT_MNEMONIC"]` then you can call:
|
|
181
|
+
>>> account = get_account('ACCOUNT', algod)
|
|
182
|
+
>>> # If that code runs against LocalNet then a wallet called 'ACCOUNT' will automatically be created
|
|
183
|
+
>>> # with an account that is automatically funded with 1000 (default) ALGOs from the default LocalNet dispenser.
|
|
184
|
+
|
|
185
|
+
:param client: The Algorand client to use
|
|
186
|
+
:param name: The name identifier to use for loading/creating the account
|
|
187
|
+
:param fund_with_algos: Amount of Algos to fund new LocalNet accounts with, defaults to 1000
|
|
188
|
+
:param kmd_client: Optional KMD client to use for LocalNet wallet operations
|
|
189
|
+
:raises Exception: If required environment variable is missing in non-LocalNet environment
|
|
190
|
+
:return: An Account object with loaded private key
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
mnemonic_key = f"{name.upper()}_MNEMONIC"
|
|
194
|
+
mnemonic = os.getenv(mnemonic_key)
|
|
195
|
+
if mnemonic:
|
|
196
|
+
return get_account_from_mnemonic(mnemonic)
|
|
197
|
+
|
|
198
|
+
if is_localnet(client):
|
|
199
|
+
account = get_or_create_kmd_wallet_account(client, name, fund_with_algos, kmd_client)
|
|
200
|
+
os.environ[mnemonic_key] = from_private_key(account.private_key)
|
|
201
|
+
return account
|
|
202
|
+
|
|
203
|
+
raise Exception(f"Missing environment variable '{mnemonic_key}' when looking for account '{name}'")
|