algokit-utils 3.0.0b1__py3-none-any.whl → 3.0.0b3__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 +2054 -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 +197 -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 +2287 -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.0b3.dist-info}/METADATA +13 -8
- algokit_utils-3.0.0b3.dist-info/RECORD +70 -0
- {algokit_utils-3.0.0b1.dist-info → algokit_utils-3.0.0b3.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.0b3.dist-info}/LICENSE +0 -0
|
@@ -1,200 +1,9 @@
|
|
|
1
|
-
from collections.abc import Callable
|
|
2
|
-
from dataclasses import dataclass
|
|
3
1
|
from typing import Any
|
|
4
2
|
|
|
5
|
-
from algokit_utils.
|
|
6
|
-
from algosdk.account import generate_account
|
|
7
|
-
from algosdk.atomic_transaction_composer import AccountTransactionSigner, TransactionSigner
|
|
8
|
-
from typing_extensions import Self
|
|
3
|
+
from algokit_utils.beta._utils import handle_getattr
|
|
9
4
|
|
|
10
|
-
from .client_manager import ClientManager
|
|
11
5
|
|
|
6
|
+
def __getattr__(name: str) -> Any: # noqa: ANN401
|
|
7
|
+
"""Handle deprecated imports of parameter classes"""
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
class AddressAndSigner:
|
|
15
|
-
address: str
|
|
16
|
-
signer: TransactionSigner
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class AccountManager:
|
|
20
|
-
"""Creates and keeps track of addresses and signers"""
|
|
21
|
-
|
|
22
|
-
def __init__(self, client_manager: ClientManager):
|
|
23
|
-
"""
|
|
24
|
-
Create a new account manager.
|
|
25
|
-
|
|
26
|
-
:param client_manager: The ClientManager client to use for algod and kmd clients
|
|
27
|
-
"""
|
|
28
|
-
self._client_manager = client_manager
|
|
29
|
-
self._accounts = dict[str, TransactionSigner]()
|
|
30
|
-
self._default_signer: TransactionSigner | None = None
|
|
31
|
-
|
|
32
|
-
def set_default_signer(self, signer: TransactionSigner) -> Self:
|
|
33
|
-
"""
|
|
34
|
-
Sets the default signer to use if no other signer is specified.
|
|
35
|
-
|
|
36
|
-
:param signer: The signer to use, either a `TransactionSigner` or a `TransactionSignerAccount`
|
|
37
|
-
:return: The `AccountManager` so method calls can be chained
|
|
38
|
-
"""
|
|
39
|
-
self._default_signer = signer
|
|
40
|
-
return self
|
|
41
|
-
|
|
42
|
-
def set_signer(self, sender: str, signer: TransactionSigner) -> Self:
|
|
43
|
-
"""
|
|
44
|
-
Tracks the given account for later signing.
|
|
45
|
-
|
|
46
|
-
:param sender: The sender address to use this signer for
|
|
47
|
-
:param signer: The signer to sign transactions with for the given sender
|
|
48
|
-
:return: The AccountCreator instance for method chaining
|
|
49
|
-
"""
|
|
50
|
-
self._accounts[sender] = signer
|
|
51
|
-
return self
|
|
52
|
-
|
|
53
|
-
def get_signer(self, sender: str) -> TransactionSigner:
|
|
54
|
-
"""
|
|
55
|
-
Returns the `TransactionSigner` for the given sender address.
|
|
56
|
-
|
|
57
|
-
If no signer has been registered for that address then the default signer is used if registered.
|
|
58
|
-
|
|
59
|
-
:param sender: The sender address
|
|
60
|
-
:return: The `TransactionSigner` or throws an error if not found
|
|
61
|
-
"""
|
|
62
|
-
signer = self._accounts.get(sender, None) or self._default_signer
|
|
63
|
-
if not signer:
|
|
64
|
-
raise ValueError(f"No signer found for address {sender}")
|
|
65
|
-
return signer
|
|
66
|
-
|
|
67
|
-
def get_information(self, sender: str) -> dict[str, Any]:
|
|
68
|
-
"""
|
|
69
|
-
Returns the given sender account's current status, balance and spendable amounts.
|
|
70
|
-
|
|
71
|
-
Example:
|
|
72
|
-
address = "XBYLS2E6YI6XXL5BWCAMOA4GTWHXWENZMX5UHXMRNWWUQ7BXCY5WC5TEPA"
|
|
73
|
-
account_info = account.get_information(address)
|
|
74
|
-
|
|
75
|
-
`Response data schema details <https://developer.algorand.org/docs/rest-apis/algod/#get-v2accountsaddress>`_
|
|
76
|
-
|
|
77
|
-
:param sender: The address of the sender/account to look up
|
|
78
|
-
:return: The account information
|
|
79
|
-
"""
|
|
80
|
-
info = self._client_manager.algod.account_info(sender)
|
|
81
|
-
assert isinstance(info, dict)
|
|
82
|
-
return info
|
|
83
|
-
|
|
84
|
-
def get_asset_information(self, sender: str, asset_id: int) -> dict[str, Any]:
|
|
85
|
-
info = self._client_manager.algod.account_asset_info(sender, asset_id)
|
|
86
|
-
assert isinstance(info, dict)
|
|
87
|
-
return info
|
|
88
|
-
|
|
89
|
-
# TODO
|
|
90
|
-
# def from_mnemonic(self, mnemonic_secret: str, sender: Optional[str] = None) -> AddrAndSigner:
|
|
91
|
-
# """
|
|
92
|
-
# Tracks and returns an Algorand account with secret key loaded (i.e. that can sign transactions) by taking the mnemonic secret.
|
|
93
|
-
|
|
94
|
-
# Example:
|
|
95
|
-
# account = account.from_mnemonic("mnemonic secret ...")
|
|
96
|
-
# rekeyed_account = account.from_mnemonic("mnemonic secret ...", "SENDERADDRESS...")
|
|
97
|
-
|
|
98
|
-
# :param mnemonic_secret: The mnemonic secret representing the private key of an account; **Note: Be careful how the mnemonic is handled**,
|
|
99
|
-
# never commit it into source control and ideally load it from the environment (ideally via a secret storage service) rather than the file system.
|
|
100
|
-
# :param sender: The optional sender address to use this signer for (aka a rekeyed account)
|
|
101
|
-
# :return: The account
|
|
102
|
-
# """
|
|
103
|
-
# account = mnemonic_account(mnemonic_secret)
|
|
104
|
-
# return self.signer_account(rekeyed_account(account, sender) if sender else account)
|
|
105
|
-
|
|
106
|
-
def from_kmd(
|
|
107
|
-
self,
|
|
108
|
-
name: str,
|
|
109
|
-
predicate: Callable[[dict[str, Any]], bool] | None = None,
|
|
110
|
-
) -> AddressAndSigner:
|
|
111
|
-
"""
|
|
112
|
-
Tracks and returns an Algorand account with private key loaded from the given KMD wallet (identified by name).
|
|
113
|
-
|
|
114
|
-
Example (Get default funded account in a LocalNet):
|
|
115
|
-
default_dispenser_account = account.from_kmd('unencrypted-default-wallet',
|
|
116
|
-
lambda a: a['status'] != 'Offline' and a['amount'] > 1_000_000_000
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
:param name: The name of the wallet to retrieve an account from
|
|
120
|
-
:param predicate: An optional filter to use to find the account (otherwise it will return a random account from the wallet)
|
|
121
|
-
:return: The account
|
|
122
|
-
"""
|
|
123
|
-
account = get_kmd_wallet_account(
|
|
124
|
-
name=name, predicate=predicate, client=self._client_manager.algod, kmd_client=self._client_manager.kmd
|
|
125
|
-
)
|
|
126
|
-
if not account:
|
|
127
|
-
raise ValueError(f"Unable to find KMD account {name}{' with predicate' if predicate else ''}")
|
|
128
|
-
|
|
129
|
-
self.set_signer(account.address, account.signer)
|
|
130
|
-
return AddressAndSigner(address=account.address, signer=account.signer)
|
|
131
|
-
|
|
132
|
-
# TODO
|
|
133
|
-
# def multisig(
|
|
134
|
-
# self, multisig_params: algosdk.MultisigMetadata, signing_accounts: Union[algosdk.Account, SigningAccount]
|
|
135
|
-
# ) -> TransactionSignerAccount:
|
|
136
|
-
# """
|
|
137
|
-
# Tracks and returns an account that supports partial or full multisig signing.
|
|
138
|
-
|
|
139
|
-
# Example:
|
|
140
|
-
# account = account.multisig(
|
|
141
|
-
# {
|
|
142
|
-
# "version": 1,
|
|
143
|
-
# "threshold": 1,
|
|
144
|
-
# "addrs": ["ADDRESS1...", "ADDRESS2..."]
|
|
145
|
-
# },
|
|
146
|
-
# account.from_environment('ACCOUNT1')
|
|
147
|
-
# )
|
|
148
|
-
|
|
149
|
-
# :param multisig_params: The parameters that define the multisig account
|
|
150
|
-
# :param signing_accounts: The signers that are currently present
|
|
151
|
-
# :return: A multisig account wrapper
|
|
152
|
-
# """
|
|
153
|
-
# return self.signer_account(multisig_account(multisig_params, signing_accounts))
|
|
154
|
-
|
|
155
|
-
def random(self) -> AddressAndSigner:
|
|
156
|
-
"""
|
|
157
|
-
Tracks and returns a new, random Algorand account with secret key loaded.
|
|
158
|
-
|
|
159
|
-
Example:
|
|
160
|
-
account = account.random()
|
|
161
|
-
|
|
162
|
-
:return: The account
|
|
163
|
-
"""
|
|
164
|
-
(sk, addr) = generate_account() # type: ignore[no-untyped-call]
|
|
165
|
-
signer = AccountTransactionSigner(sk)
|
|
166
|
-
|
|
167
|
-
self.set_signer(addr, signer)
|
|
168
|
-
|
|
169
|
-
return AddressAndSigner(address=addr, signer=signer)
|
|
170
|
-
|
|
171
|
-
def dispenser(self) -> AddressAndSigner:
|
|
172
|
-
"""
|
|
173
|
-
Returns an account (with private key loaded) that can act as a dispenser.
|
|
174
|
-
|
|
175
|
-
Example:
|
|
176
|
-
account = account.dispenser()
|
|
177
|
-
|
|
178
|
-
If running on LocalNet then it will return the default dispenser account automatically,
|
|
179
|
-
otherwise it will load the account mnemonic stored in os.environ['DISPENSER_MNEMONIC'].
|
|
180
|
-
|
|
181
|
-
:return: The account
|
|
182
|
-
"""
|
|
183
|
-
acct = get_dispenser_account(self._client_manager.algod)
|
|
184
|
-
|
|
185
|
-
self.set_signer(acct.address, acct.signer)
|
|
186
|
-
|
|
187
|
-
return AddressAndSigner(address=acct.address, signer=acct.signer)
|
|
188
|
-
|
|
189
|
-
def localnet_dispenser(self) -> AddressAndSigner:
|
|
190
|
-
"""
|
|
191
|
-
Returns an Algorand account with private key loaded for the default LocalNet dispenser account (that can be used to fund other accounts).
|
|
192
|
-
|
|
193
|
-
Example:
|
|
194
|
-
account = account.localnet_dispenser()
|
|
195
|
-
|
|
196
|
-
:return: The account
|
|
197
|
-
"""
|
|
198
|
-
acct = get_localnet_default_account(self._client_manager.algod)
|
|
199
|
-
self.set_signer(acct.address, acct.signer)
|
|
200
|
-
return AddressAndSigner(address=acct.address, signer=acct.signer)
|
|
9
|
+
handle_getattr(name)
|
|
@@ -1,319 +1,9 @@
|
|
|
1
|
-
import copy
|
|
2
|
-
import time
|
|
3
|
-
from collections.abc import Callable
|
|
4
|
-
from dataclasses import dataclass
|
|
5
1
|
from typing import Any
|
|
6
2
|
|
|
7
|
-
from algokit_utils.beta.
|
|
8
|
-
from algokit_utils.beta.client_manager import AlgoSdkClients, ClientManager
|
|
9
|
-
from algokit_utils.beta.composer import (
|
|
10
|
-
AlgokitComposer,
|
|
11
|
-
AppCallParams,
|
|
12
|
-
AssetConfigParams,
|
|
13
|
-
AssetCreateParams,
|
|
14
|
-
AssetDestroyParams,
|
|
15
|
-
AssetFreezeParams,
|
|
16
|
-
AssetOptInParams,
|
|
17
|
-
AssetTransferParams,
|
|
18
|
-
MethodCallParams,
|
|
19
|
-
OnlineKeyRegParams,
|
|
20
|
-
PayParams,
|
|
21
|
-
)
|
|
22
|
-
from algokit_utils.network_clients import (
|
|
23
|
-
AlgoClientConfigs,
|
|
24
|
-
get_algod_client,
|
|
25
|
-
get_algonode_config,
|
|
26
|
-
get_default_localnet_config,
|
|
27
|
-
get_indexer_client,
|
|
28
|
-
get_kmd_client,
|
|
29
|
-
)
|
|
30
|
-
from algosdk.atomic_transaction_composer import AtomicTransactionResponse, TransactionSigner
|
|
31
|
-
from algosdk.transaction import SuggestedParams, Transaction, wait_for_confirmation
|
|
32
|
-
from typing_extensions import Self
|
|
3
|
+
from algokit_utils.beta._utils import handle_getattr
|
|
33
4
|
|
|
34
|
-
__all__ = [
|
|
35
|
-
"AlgorandClient",
|
|
36
|
-
"AssetCreateParams",
|
|
37
|
-
"AssetOptInParams",
|
|
38
|
-
"MethodCallParams",
|
|
39
|
-
"PayParams",
|
|
40
|
-
"AssetFreezeParams",
|
|
41
|
-
"AssetConfigParams",
|
|
42
|
-
"AssetDestroyParams",
|
|
43
|
-
"AppCallParams",
|
|
44
|
-
"OnlineKeyRegParams",
|
|
45
|
-
"AssetTransferParams",
|
|
46
|
-
]
|
|
47
5
|
|
|
6
|
+
def __getattr__(name: str) -> Any: # noqa: ANN401
|
|
7
|
+
"""Handle deprecated imports of parameter classes"""
|
|
48
8
|
|
|
49
|
-
|
|
50
|
-
class AlgorandClientSendMethods:
|
|
51
|
-
"""
|
|
52
|
-
Methods used to send a transaction to the network and wait for confirmation
|
|
53
|
-
"""
|
|
54
|
-
|
|
55
|
-
payment: Callable[[PayParams], dict[str, Any]]
|
|
56
|
-
asset_create: Callable[[AssetCreateParams], dict[str, Any]]
|
|
57
|
-
asset_config: Callable[[AssetConfigParams], dict[str, Any]]
|
|
58
|
-
asset_freeze: Callable[[AssetFreezeParams], dict[str, Any]]
|
|
59
|
-
asset_destroy: Callable[[AssetDestroyParams], dict[str, Any]]
|
|
60
|
-
asset_transfer: Callable[[AssetTransferParams], dict[str, Any]]
|
|
61
|
-
app_call: Callable[[AppCallParams], dict[str, Any]]
|
|
62
|
-
online_key_reg: Callable[[OnlineKeyRegParams], dict[str, Any]]
|
|
63
|
-
method_call: Callable[[MethodCallParams], dict[str, Any]]
|
|
64
|
-
asset_opt_in: Callable[[AssetOptInParams], dict[str, Any]]
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@dataclass
|
|
68
|
-
class AlgorandClientTransactionMethods:
|
|
69
|
-
"""
|
|
70
|
-
Methods used to form a transaction without signing or sending to the network
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
payment: Callable[[PayParams], Transaction]
|
|
74
|
-
asset_create: Callable[[AssetCreateParams], Transaction]
|
|
75
|
-
asset_config: Callable[[AssetConfigParams], Transaction]
|
|
76
|
-
asset_freeze: Callable[[AssetFreezeParams], Transaction]
|
|
77
|
-
asset_destroy: Callable[[AssetDestroyParams], Transaction]
|
|
78
|
-
asset_transfer: Callable[[AssetTransferParams], Transaction]
|
|
79
|
-
app_call: Callable[[AppCallParams], Transaction]
|
|
80
|
-
online_key_reg: Callable[[OnlineKeyRegParams], Transaction]
|
|
81
|
-
method_call: Callable[[MethodCallParams], list[Transaction]]
|
|
82
|
-
asset_opt_in: Callable[[AssetOptInParams], Transaction]
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class AlgorandClient:
|
|
86
|
-
"""A client that brokers easy access to Algorand functionality."""
|
|
87
|
-
|
|
88
|
-
def __init__(self, config: AlgoClientConfigs | AlgoSdkClients):
|
|
89
|
-
self._client_manager: ClientManager = ClientManager(config)
|
|
90
|
-
self._account_manager: AccountManager = AccountManager(self._client_manager)
|
|
91
|
-
|
|
92
|
-
self._cached_suggested_params: SuggestedParams | None = None
|
|
93
|
-
self._cached_suggested_params_expiry: float | None = None
|
|
94
|
-
self._cached_suggested_params_timeout: int = 3_000 # three seconds
|
|
95
|
-
|
|
96
|
-
self._default_validity_window: int = 10
|
|
97
|
-
|
|
98
|
-
def _unwrap_single_send_result(self, results: AtomicTransactionResponse) -> dict[str, Any]:
|
|
99
|
-
return {
|
|
100
|
-
"confirmation": wait_for_confirmation(self._client_manager.algod, results.tx_ids[0]),
|
|
101
|
-
"tx_id": results.tx_ids[0],
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
def set_default_validity_window(self, validity_window: int) -> Self:
|
|
105
|
-
"""
|
|
106
|
-
Sets the default validity window for transactions.
|
|
107
|
-
|
|
108
|
-
:param validity_window: The number of rounds between the first and last valid rounds
|
|
109
|
-
:return: The `AlgorandClient` so method calls can be chained
|
|
110
|
-
"""
|
|
111
|
-
self._default_validity_window = validity_window
|
|
112
|
-
return self
|
|
113
|
-
|
|
114
|
-
def set_default_signer(self, signer: TransactionSigner) -> Self:
|
|
115
|
-
"""
|
|
116
|
-
Sets the default signer to use if no other signer is specified.
|
|
117
|
-
|
|
118
|
-
:param signer: The signer to use, either a `TransactionSigner` or a `TransactionSignerAccount`
|
|
119
|
-
:return: The `AlgorandClient` so method calls can be chained
|
|
120
|
-
"""
|
|
121
|
-
self._account_manager.set_default_signer(signer)
|
|
122
|
-
return self
|
|
123
|
-
|
|
124
|
-
def set_signer(self, sender: str, signer: TransactionSigner) -> Self:
|
|
125
|
-
"""
|
|
126
|
-
Tracks the given account for later signing.
|
|
127
|
-
|
|
128
|
-
:param sender: The sender address to use this signer for
|
|
129
|
-
:param signer: The signer to sign transactions with for the given sender
|
|
130
|
-
:return: The `AlgorandClient` so method calls can be chained
|
|
131
|
-
"""
|
|
132
|
-
self._account_manager.set_signer(sender, signer)
|
|
133
|
-
return self
|
|
134
|
-
|
|
135
|
-
def set_suggested_params(self, suggested_params: SuggestedParams, until: float | None = None) -> Self:
|
|
136
|
-
"""
|
|
137
|
-
Sets a cache value to use for suggested params.
|
|
138
|
-
|
|
139
|
-
:param suggested_params: The suggested params to use
|
|
140
|
-
:param until: A timestamp until which to cache, or if not specified then the timeout is used
|
|
141
|
-
:return: The `AlgorandClient` so method calls can be chained
|
|
142
|
-
"""
|
|
143
|
-
self._cached_suggested_params = suggested_params
|
|
144
|
-
self._cached_suggested_params_expiry = until or time.time() + self._cached_suggested_params_timeout
|
|
145
|
-
return self
|
|
146
|
-
|
|
147
|
-
def set_suggested_params_timeout(self, timeout: int) -> Self:
|
|
148
|
-
"""
|
|
149
|
-
Sets the timeout for caching suggested params.
|
|
150
|
-
|
|
151
|
-
:param timeout: The timeout in milliseconds
|
|
152
|
-
:return: The `AlgorandClient` so method calls can be chained
|
|
153
|
-
"""
|
|
154
|
-
self._cached_suggested_params_timeout = timeout
|
|
155
|
-
return self
|
|
156
|
-
|
|
157
|
-
def get_suggested_params(self) -> SuggestedParams:
|
|
158
|
-
"""Get suggested params for a transaction (either cached or from algod if the cache is stale or empty)"""
|
|
159
|
-
if self._cached_suggested_params and (
|
|
160
|
-
self._cached_suggested_params_expiry is None or self._cached_suggested_params_expiry > time.time()
|
|
161
|
-
):
|
|
162
|
-
return copy.deepcopy(self._cached_suggested_params)
|
|
163
|
-
|
|
164
|
-
self._cached_suggested_params = self._client_manager.algod.suggested_params()
|
|
165
|
-
self._cached_suggested_params_expiry = time.time() + self._cached_suggested_params_timeout
|
|
166
|
-
|
|
167
|
-
return copy.deepcopy(self._cached_suggested_params)
|
|
168
|
-
|
|
169
|
-
@property
|
|
170
|
-
def client(self) -> ClientManager:
|
|
171
|
-
"""Get clients, including algosdk clients and app clients."""
|
|
172
|
-
return self._client_manager
|
|
173
|
-
|
|
174
|
-
@property
|
|
175
|
-
def account(self) -> AccountManager:
|
|
176
|
-
"""Get or create accounts that can sign transactions."""
|
|
177
|
-
return self._account_manager
|
|
178
|
-
|
|
179
|
-
def new_group(self) -> AlgokitComposer:
|
|
180
|
-
"""Start a new `AlgokitComposer` transaction group"""
|
|
181
|
-
return AlgokitComposer(
|
|
182
|
-
algod=self.client.algod,
|
|
183
|
-
get_signer=lambda addr: self.account.get_signer(addr),
|
|
184
|
-
get_suggested_params=self.get_suggested_params,
|
|
185
|
-
default_validity_window=self._default_validity_window,
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
@property
|
|
189
|
-
def send(self) -> AlgorandClientSendMethods:
|
|
190
|
-
"""Methods for sending a transaction and waiting for confirmation"""
|
|
191
|
-
return AlgorandClientSendMethods(
|
|
192
|
-
payment=lambda params: self._unwrap_single_send_result(self.new_group().add_payment(params).execute()),
|
|
193
|
-
asset_create=lambda params: self._unwrap_single_send_result(
|
|
194
|
-
self.new_group().add_asset_create(params).execute()
|
|
195
|
-
),
|
|
196
|
-
asset_config=lambda params: self._unwrap_single_send_result(
|
|
197
|
-
self.new_group().add_asset_config(params).execute()
|
|
198
|
-
),
|
|
199
|
-
asset_freeze=lambda params: self._unwrap_single_send_result(
|
|
200
|
-
self.new_group().add_asset_freeze(params).execute()
|
|
201
|
-
),
|
|
202
|
-
asset_destroy=lambda params: self._unwrap_single_send_result(
|
|
203
|
-
self.new_group().add_asset_destroy(params).execute()
|
|
204
|
-
),
|
|
205
|
-
asset_transfer=lambda params: self._unwrap_single_send_result(
|
|
206
|
-
self.new_group().add_asset_transfer(params).execute()
|
|
207
|
-
),
|
|
208
|
-
app_call=lambda params: self._unwrap_single_send_result(self.new_group().add_app_call(params).execute()),
|
|
209
|
-
online_key_reg=lambda params: self._unwrap_single_send_result(
|
|
210
|
-
self.new_group().add_online_key_reg(params).execute()
|
|
211
|
-
),
|
|
212
|
-
method_call=lambda params: self._unwrap_single_send_result(
|
|
213
|
-
self.new_group().add_method_call(params).execute()
|
|
214
|
-
),
|
|
215
|
-
asset_opt_in=lambda params: self._unwrap_single_send_result(
|
|
216
|
-
self.new_group().add_asset_opt_in(params).execute()
|
|
217
|
-
),
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
@property
|
|
221
|
-
def transactions(self) -> AlgorandClientTransactionMethods:
|
|
222
|
-
"""Methods for building transactions"""
|
|
223
|
-
|
|
224
|
-
return AlgorandClientTransactionMethods(
|
|
225
|
-
payment=lambda params: self.new_group().add_payment(params).build_group()[0].txn,
|
|
226
|
-
asset_create=lambda params: self.new_group().add_asset_create(params).build_group()[0].txn,
|
|
227
|
-
asset_config=lambda params: self.new_group().add_asset_config(params).build_group()[0].txn,
|
|
228
|
-
asset_freeze=lambda params: self.new_group().add_asset_freeze(params).build_group()[0].txn,
|
|
229
|
-
asset_destroy=lambda params: self.new_group().add_asset_destroy(params).build_group()[0].txn,
|
|
230
|
-
asset_transfer=lambda params: self.new_group().add_asset_transfer(params).build_group()[0].txn,
|
|
231
|
-
app_call=lambda params: self.new_group().add_app_call(params).build_group()[0].txn,
|
|
232
|
-
online_key_reg=lambda params: self.new_group().add_online_key_reg(params).build_group()[0].txn,
|
|
233
|
-
method_call=lambda params: [txn.txn for txn in self.new_group().add_method_call(params).build_group()],
|
|
234
|
-
asset_opt_in=lambda params: self.new_group().add_asset_opt_in(params).build_group()[0].txn,
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
@staticmethod
|
|
238
|
-
def default_local_net() -> "AlgorandClient":
|
|
239
|
-
"""
|
|
240
|
-
Returns an `AlgorandClient` pointing at default LocalNet ports and API token.
|
|
241
|
-
|
|
242
|
-
:return: The `AlgorandClient`
|
|
243
|
-
"""
|
|
244
|
-
return AlgorandClient(
|
|
245
|
-
AlgoClientConfigs(
|
|
246
|
-
algod_config=get_default_localnet_config("algod"),
|
|
247
|
-
indexer_config=get_default_localnet_config("indexer"),
|
|
248
|
-
kmd_config=get_default_localnet_config("kmd"),
|
|
249
|
-
)
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
@staticmethod
|
|
253
|
-
def test_net() -> "AlgorandClient":
|
|
254
|
-
"""
|
|
255
|
-
Returns an `AlgorandClient` pointing at TestNet using AlgoNode.
|
|
256
|
-
|
|
257
|
-
:return: The `AlgorandClient`
|
|
258
|
-
"""
|
|
259
|
-
return AlgorandClient(
|
|
260
|
-
AlgoClientConfigs(
|
|
261
|
-
algod_config=get_algonode_config("testnet", "algod", ""),
|
|
262
|
-
indexer_config=get_algonode_config("testnet", "indexer", ""),
|
|
263
|
-
kmd_config=None,
|
|
264
|
-
)
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
@staticmethod
|
|
268
|
-
def main_net() -> "AlgorandClient":
|
|
269
|
-
"""
|
|
270
|
-
Returns an `AlgorandClient` pointing at MainNet using AlgoNode.
|
|
271
|
-
|
|
272
|
-
:return: The `AlgorandClient`
|
|
273
|
-
"""
|
|
274
|
-
return AlgorandClient(
|
|
275
|
-
AlgoClientConfigs(
|
|
276
|
-
algod_config=get_algonode_config("mainnet", "algod", ""),
|
|
277
|
-
indexer_config=get_algonode_config("mainnet", "indexer", ""),
|
|
278
|
-
kmd_config=None,
|
|
279
|
-
)
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
@staticmethod
|
|
283
|
-
def from_clients(clients: AlgoSdkClients) -> "AlgorandClient":
|
|
284
|
-
"""
|
|
285
|
-
Returns an `AlgorandClient` pointing to the given client(s).
|
|
286
|
-
|
|
287
|
-
:param clients: The clients to use
|
|
288
|
-
:return: The `AlgorandClient`
|
|
289
|
-
"""
|
|
290
|
-
return AlgorandClient(clients)
|
|
291
|
-
|
|
292
|
-
@staticmethod
|
|
293
|
-
def from_environment() -> "AlgorandClient":
|
|
294
|
-
"""
|
|
295
|
-
Returns an `AlgorandClient` loading the configuration from environment variables.
|
|
296
|
-
|
|
297
|
-
Retrieve configurations from environment variables when defined or get defaults.
|
|
298
|
-
|
|
299
|
-
Expects to be called from a Python environment.
|
|
300
|
-
|
|
301
|
-
:return: The `AlgorandClient`
|
|
302
|
-
"""
|
|
303
|
-
return AlgorandClient(
|
|
304
|
-
AlgoSdkClients(
|
|
305
|
-
algod=get_algod_client(),
|
|
306
|
-
kmd=get_kmd_client(),
|
|
307
|
-
indexer=get_indexer_client(),
|
|
308
|
-
)
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
@staticmethod
|
|
312
|
-
def from_config(config: AlgoClientConfigs) -> "AlgorandClient":
|
|
313
|
-
"""
|
|
314
|
-
Returns an `AlgorandClient` from the given config.
|
|
315
|
-
|
|
316
|
-
:param config: The config to use
|
|
317
|
-
:return: The `AlgorandClient`
|
|
318
|
-
"""
|
|
319
|
-
return AlgorandClient(config)
|
|
9
|
+
handle_getattr(name)
|
|
@@ -1,78 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
from algokit_utils.dispenser_api import TestNetDispenserApiClient
|
|
3
|
-
from algokit_utils.network_clients import AlgoClientConfigs, get_algod_client, get_indexer_client, get_kmd_client
|
|
4
|
-
from algosdk.kmd import KMDClient
|
|
5
|
-
from algosdk.v2client.algod import AlgodClient
|
|
6
|
-
from algosdk.v2client.indexer import IndexerClient
|
|
1
|
+
from typing import Any
|
|
7
2
|
|
|
3
|
+
from algokit_utils.beta._utils import handle_getattr
|
|
8
4
|
|
|
9
|
-
class AlgoSdkClients:
|
|
10
|
-
"""
|
|
11
|
-
Clients from algosdk that interact with the official Algorand APIs.
|
|
12
5
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
indexer (Optional[IndexerClient]): Optional indexer client, see https://developer.algorand.org/docs/rest-apis/indexer/
|
|
16
|
-
kmd (Optional[KMDClient]): Optional KMD client, see https://developer.algorand.org/docs/rest-apis/kmd/
|
|
17
|
-
"""
|
|
6
|
+
def __getattr__(name: str) -> Any: # noqa: ANN401
|
|
7
|
+
"""Handle deprecated imports of parameter classes"""
|
|
18
8
|
|
|
19
|
-
|
|
20
|
-
self,
|
|
21
|
-
algod: algosdk.v2client.algod.AlgodClient,
|
|
22
|
-
indexer: IndexerClient | None = None,
|
|
23
|
-
kmd: KMDClient | None = None,
|
|
24
|
-
):
|
|
25
|
-
self.algod = algod
|
|
26
|
-
self.indexer = indexer
|
|
27
|
-
self.kmd = kmd
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class ClientManager:
|
|
31
|
-
"""
|
|
32
|
-
Exposes access to various API clients.
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
clients_or_config (Union[AlgoConfig, AlgoSdkClients]): algosdk clients or config for interacting with the official Algorand APIs.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
def __init__(self, clients_or_configs: AlgoClientConfigs | AlgoSdkClients):
|
|
39
|
-
if isinstance(clients_or_configs, AlgoSdkClients):
|
|
40
|
-
_clients = clients_or_configs
|
|
41
|
-
elif isinstance(clients_or_configs, AlgoClientConfigs):
|
|
42
|
-
_clients = AlgoSdkClients(
|
|
43
|
-
algod=get_algod_client(clients_or_configs.algod_config),
|
|
44
|
-
indexer=get_indexer_client(clients_or_configs.indexer_config)
|
|
45
|
-
if clients_or_configs.indexer_config
|
|
46
|
-
else None,
|
|
47
|
-
kmd=get_kmd_client(clients_or_configs.kmd_config) if clients_or_configs.kmd_config else None,
|
|
48
|
-
)
|
|
49
|
-
self._algod = _clients.algod
|
|
50
|
-
self._indexer = _clients.indexer
|
|
51
|
-
self._kmd = _clients.kmd
|
|
52
|
-
|
|
53
|
-
@property
|
|
54
|
-
def algod(self) -> AlgodClient:
|
|
55
|
-
"""Returns an algosdk Algod API client."""
|
|
56
|
-
return self._algod
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def indexer(self) -> IndexerClient:
|
|
60
|
-
"""Returns an algosdk Indexer API client or raises an error if it's not been provided."""
|
|
61
|
-
if not self._indexer:
|
|
62
|
-
raise ValueError("Attempt to use Indexer client in AlgoKit instance with no Indexer configured")
|
|
63
|
-
return self._indexer
|
|
64
|
-
|
|
65
|
-
@property
|
|
66
|
-
def kmd(self) -> KMDClient:
|
|
67
|
-
"""Returns an algosdk KMD API client or raises an error if it's not been provided."""
|
|
68
|
-
if not self._kmd:
|
|
69
|
-
raise ValueError("Attempt to use Kmd client in AlgoKit instance with no Kmd configured")
|
|
70
|
-
return self._kmd
|
|
71
|
-
|
|
72
|
-
def get_testnet_dispenser(
|
|
73
|
-
self, auth_token: str | None = None, request_timeout: int | None = None
|
|
74
|
-
) -> TestNetDispenserApiClient:
|
|
75
|
-
if request_timeout:
|
|
76
|
-
return TestNetDispenserApiClient(auth_token=auth_token, request_timeout=request_timeout)
|
|
77
|
-
|
|
78
|
-
return TestNetDispenserApiClient(auth_token=auth_token)
|
|
9
|
+
handle_getattr(name)
|