algokit-utils 3.0.0b4__py3-none-any.whl → 3.0.0b5__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/_legacy_v2/account.py +4 -4
- algokit_utils/accounts/account_manager.py +98 -98
- algokit_utils/accounts/kmd_account_manager.py +2 -0
- algokit_utils/applications/app_client.py +38 -14
- algokit_utils/assets/asset_manager.py +5 -5
- algokit_utils/clients/client_manager.py +17 -12
- algokit_utils/models/amount.py +25 -81
- algokit_utils/models/network.py +6 -2
- algokit_utils/transactions/transaction_composer.py +19 -15
- {algokit_utils-3.0.0b4.dist-info → algokit_utils-3.0.0b5.dist-info}/METADATA +1 -1
- {algokit_utils-3.0.0b4.dist-info → algokit_utils-3.0.0b5.dist-info}/RECORD +13 -13
- {algokit_utils-3.0.0b4.dist-info → algokit_utils-3.0.0b5.dist-info}/LICENSE +0 -0
- {algokit_utils-3.0.0b4.dist-info → algokit_utils-3.0.0b5.dist-info}/WHEEL +0 -0
|
@@ -177,10 +177,10 @@ def get_account(
|
|
|
177
177
|
For LocalNet environments, loads or creates an account from a KMD wallet named {name}.
|
|
178
178
|
|
|
179
179
|
:example:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
184
|
|
|
185
185
|
:param client: The Algorand client to use
|
|
186
186
|
:param name: The name identifier to use for loading/creating the account
|
|
@@ -148,7 +148,7 @@ class AccountManager:
|
|
|
148
148
|
:param client_manager: The ClientManager client to use for algod and kmd clients
|
|
149
149
|
|
|
150
150
|
:example:
|
|
151
|
-
|
|
151
|
+
>>> account_manager = AccountManager(client_manager)
|
|
152
152
|
"""
|
|
153
153
|
|
|
154
154
|
def __init__(self, client_manager: ClientManager):
|
|
@@ -172,11 +172,11 @@ class AccountManager:
|
|
|
172
172
|
:returns: The `AccountManager` so method calls can be chained
|
|
173
173
|
|
|
174
174
|
:example:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
>>> signer_account = account_manager.random()
|
|
176
|
+
>>> account_manager.set_default_signer(signer_account.signer)
|
|
177
|
+
>>> # When signing a transaction, if there is no signer registered for the sender
|
|
178
|
+
>>> # then the default signer will be used
|
|
179
|
+
>>> signer = account_manager.get_signer("{SENDERADDRESS}")
|
|
180
180
|
"""
|
|
181
181
|
self._default_signer = signer if isinstance(signer, TransactionSigner) else signer.signer
|
|
182
182
|
return self
|
|
@@ -190,7 +190,7 @@ class AccountManager:
|
|
|
190
190
|
:returns: The `AccountManager` instance for method chaining
|
|
191
191
|
|
|
192
192
|
:example:
|
|
193
|
-
|
|
193
|
+
>>> account_manager.set_signer("SENDERADDRESS", transaction_signer)
|
|
194
194
|
"""
|
|
195
195
|
self._accounts[sender] = TransactionSignerAccount(address=sender, signer=signer)
|
|
196
196
|
return self
|
|
@@ -221,11 +221,11 @@ class AccountManager:
|
|
|
221
221
|
:returns: The `AccountManager` instance for method chaining
|
|
222
222
|
|
|
223
223
|
:example:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
"""
|
|
224
|
+
>>> account_manager = AccountManager(client_manager)
|
|
225
|
+
>>> account_manager.set_signer_from_account(SigningAccount(private_key=algosdk.account.generate_account()[0]))
|
|
226
|
+
>>> account_manager.set_signer_from_account(LogicSigAccount(AlgosdkLogicSigAccount(program, args)))
|
|
227
|
+
>>> account_manager.set_signer_from_account(MultiSigAccount(multisig_params, [account1, account2]))
|
|
228
|
+
""" # noqa: E501
|
|
229
229
|
self._accounts[account.address] = account
|
|
230
230
|
return self
|
|
231
231
|
|
|
@@ -240,7 +240,7 @@ class AccountManager:
|
|
|
240
240
|
:raises ValueError: If no signer is found and no default signer is set
|
|
241
241
|
|
|
242
242
|
:example:
|
|
243
|
-
|
|
243
|
+
>>> signer = account_manager.get_signer("SENDERADDRESS")
|
|
244
244
|
"""
|
|
245
245
|
signer = self._accounts.get(self._get_address(sender)) or self._default_signer
|
|
246
246
|
if not signer:
|
|
@@ -256,10 +256,10 @@ class AccountManager:
|
|
|
256
256
|
:raises ValueError: If no account is found or if the account is not a regular account
|
|
257
257
|
|
|
258
258
|
:example:
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
259
|
+
>>> sender = account_manager.random().address
|
|
260
|
+
>>> # ...
|
|
261
|
+
>>> # Returns the `TransactionSignerAccountProtocol` for `sender` that has previously been registered
|
|
262
|
+
>>> account = account_manager.get_account(sender)
|
|
263
263
|
"""
|
|
264
264
|
account = self._accounts.get(sender)
|
|
265
265
|
if not account:
|
|
@@ -279,8 +279,8 @@ class AccountManager:
|
|
|
279
279
|
:returns: The account information
|
|
280
280
|
|
|
281
281
|
:example:
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
>>> address = "XBYLS2E6YI6XXL5BWCAMOA4GTWHXWENZMX5UHXMRNWWUQ7BXCY5WC5TEPA"
|
|
283
|
+
>>> account_info = account_manager.get_information(address)
|
|
284
284
|
"""
|
|
285
285
|
info = self._client_manager.algod.account_info(self._get_address(sender))
|
|
286
286
|
assert isinstance(info, dict)
|
|
@@ -342,7 +342,7 @@ class AccountManager:
|
|
|
342
342
|
from the environment (ideally via a secret storage service) rather than the file system.
|
|
343
343
|
|
|
344
344
|
:example:
|
|
345
|
-
|
|
345
|
+
>>> account = account_manager.from_mnemonic("mnemonic secret ...")
|
|
346
346
|
"""
|
|
347
347
|
return self._register_account(to_private_key(mnemonic), sender)
|
|
348
348
|
|
|
@@ -355,7 +355,7 @@ class AccountManager:
|
|
|
355
355
|
|
|
356
356
|
:param name: The name identifier of the account
|
|
357
357
|
:param fund_with: Optional amount to fund the account with when it gets created
|
|
358
|
-
|
|
358
|
+
(when targeting LocalNet)
|
|
359
359
|
:returns: The account
|
|
360
360
|
:raises ValueError: If environment variable {NAME}_MNEMONIC is missing when looking for account {NAME}
|
|
361
361
|
|
|
@@ -368,10 +368,10 @@ class AccountManager:
|
|
|
368
368
|
it will create it and fund the account for you
|
|
369
369
|
|
|
370
370
|
:example:
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
371
|
+
>>> # If you have a mnemonic secret loaded into `MY_ACCOUNT_MNEMONIC` then you can call:
|
|
372
|
+
>>> account = account_manager.from_environment('MY_ACCOUNT')
|
|
373
|
+
>>> # If that code runs against LocalNet then a wallet called `MY_ACCOUNT` will automatically be created
|
|
374
|
+
>>> # with an account that is automatically funded with the specified amount from the LocalNet dispenser
|
|
375
375
|
"""
|
|
376
376
|
account_mnemonic = os.getenv(f"{name.upper()}_MNEMONIC")
|
|
377
377
|
|
|
@@ -398,10 +398,10 @@ class AccountManager:
|
|
|
398
398
|
:raises ValueError: If unable to find KMD account with given name and predicate
|
|
399
399
|
|
|
400
400
|
:example:
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
401
|
+
>>> # Get default funded account in a LocalNet:
|
|
402
|
+
>>> defaultDispenserAccount = account.from_kmd('unencrypted-default-wallet',
|
|
403
|
+
... lambda a: a.status != 'Offline' and a.amount > 1_000_000_000
|
|
404
|
+
... )
|
|
405
405
|
"""
|
|
406
406
|
kmd_account = self._kmd_account_manager.get_wallet_account(name, predicate, sender)
|
|
407
407
|
if not kmd_account:
|
|
@@ -418,7 +418,7 @@ class AccountManager:
|
|
|
418
418
|
:returns: A logic signature account wrapper
|
|
419
419
|
|
|
420
420
|
:example:
|
|
421
|
-
|
|
421
|
+
>>> account = account.logic_sig(program, [new Uint8Array(3, ...)])
|
|
422
422
|
"""
|
|
423
423
|
return self._register_logicsig(program, args)
|
|
424
424
|
|
|
@@ -431,12 +431,12 @@ class AccountManager:
|
|
|
431
431
|
:returns: A multisig account wrapper
|
|
432
432
|
|
|
433
433
|
:example:
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
434
|
+
>>> account = account_manager.multi_sig(
|
|
435
|
+
... version=1,
|
|
436
|
+
... threshold=1,
|
|
437
|
+
... addrs=["ADDRESS1...", "ADDRESS2..."],
|
|
438
|
+
... signing_accounts=[account1, account2]
|
|
439
|
+
... )
|
|
440
440
|
"""
|
|
441
441
|
return self._register_multisig(metadata, signing_accounts)
|
|
442
442
|
|
|
@@ -447,7 +447,7 @@ class AccountManager:
|
|
|
447
447
|
:returns: The account
|
|
448
448
|
|
|
449
449
|
:example:
|
|
450
|
-
|
|
450
|
+
>>> account = account_manager.random()
|
|
451
451
|
"""
|
|
452
452
|
private_key, _ = algosdk.account.generate_account()
|
|
453
453
|
return self._register_account(private_key)
|
|
@@ -461,7 +461,7 @@ class AccountManager:
|
|
|
461
461
|
:returns: The account
|
|
462
462
|
|
|
463
463
|
:example:
|
|
464
|
-
|
|
464
|
+
>>> account = account_manager.localnet_dispenser()
|
|
465
465
|
"""
|
|
466
466
|
kmd_account = self._kmd_account_manager.get_localnet_dispenser_account()
|
|
467
467
|
return self._register_account(kmd_account.private_key)
|
|
@@ -475,7 +475,7 @@ class AccountManager:
|
|
|
475
475
|
:returns: The account
|
|
476
476
|
|
|
477
477
|
:example:
|
|
478
|
-
|
|
478
|
+
>>> account = account_manager.dispenser_from_environment()
|
|
479
479
|
"""
|
|
480
480
|
name = os.getenv(f"{DISPENSER_ACCOUNT_NAME}_MNEMONIC")
|
|
481
481
|
if name:
|
|
@@ -493,8 +493,8 @@ class AccountManager:
|
|
|
493
493
|
:returns: The rekeyed account
|
|
494
494
|
|
|
495
495
|
:example:
|
|
496
|
-
|
|
497
|
-
|
|
496
|
+
>>> account = account.from_mnemonic("mnemonic secret ...")
|
|
497
|
+
>>> rekeyed_account = account_manager.rekeyed(account, "SENDERADDRESS...")
|
|
498
498
|
"""
|
|
499
499
|
sender_address = sender.address if isinstance(sender, SigningAccount) else sender
|
|
500
500
|
self._accounts[sender_address] = TransactionSignerAccount(address=sender_address, signer=account.signer)
|
|
@@ -540,23 +540,23 @@ class AccountManager:
|
|
|
540
540
|
`official rekey guidance <https://developer.algorand.org/docs/get-details/accounts/rekey/>`_.
|
|
541
541
|
|
|
542
542
|
:example:
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
543
|
+
>>> # Basic example (with string addresses):
|
|
544
|
+
>>> algorand.account.rekey_account({account: "ACCOUNTADDRESS", rekey_to: "NEWADDRESS"})
|
|
545
|
+
>>> # Basic example (with signer accounts):
|
|
546
|
+
>>> algorand.account.rekey_account({account: account1, rekey_to: newSignerAccount})
|
|
547
|
+
>>> # Advanced example:
|
|
548
|
+
>>> algorand.account.rekey_account({
|
|
549
|
+
... account: "ACCOUNTADDRESS",
|
|
550
|
+
... rekey_to: "NEWADDRESS",
|
|
551
|
+
... lease: 'lease',
|
|
552
|
+
... note: 'note',
|
|
553
|
+
... first_valid_round: 1000,
|
|
554
|
+
... validity_window: 10,
|
|
555
|
+
... extra_fee: AlgoAmount.from_micro_algo(1000),
|
|
556
|
+
... static_fee: AlgoAmount.from_micro_algo(1000),
|
|
557
|
+
... max_fee: AlgoAmount.from_micro_algo(3000),
|
|
558
|
+
... suppress_log: True,
|
|
559
|
+
... })
|
|
560
560
|
"""
|
|
561
561
|
sender_address = self._get_address(account)
|
|
562
562
|
rekey_address = self._get_address(rekey_to)
|
|
@@ -623,7 +623,7 @@ class AccountManager:
|
|
|
623
623
|
:param account_to_fund: The account to fund
|
|
624
624
|
:param dispenser_account: The account to use as a dispenser funding source
|
|
625
625
|
:param min_spending_balance: The minimum balance of Algo that the account
|
|
626
|
-
|
|
626
|
+
should have available to spend
|
|
627
627
|
:param min_funding_increment: Optional minimum funding increment
|
|
628
628
|
:param send_params: Parameters for the send operation, defaults to None
|
|
629
629
|
:param signer: Optional transaction signer
|
|
@@ -637,20 +637,20 @@ class AccountManager:
|
|
|
637
637
|
:param first_valid_round: Optional first valid round
|
|
638
638
|
:param last_valid_round: Optional last valid round
|
|
639
639
|
:returns: The result of executing the dispensing transaction and the `amountFunded` if funds were needed,
|
|
640
|
-
|
|
640
|
+
or None if no funds were needed
|
|
641
641
|
|
|
642
642
|
:example:
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
643
|
+
>>> # Basic example:
|
|
644
|
+
>>> algorand.account.ensure_funded("ACCOUNTADDRESS", "DISPENSERADDRESS", algokit.algo(1))
|
|
645
|
+
>>> # With configuration:
|
|
646
|
+
>>> algorand.account.ensure_funded(
|
|
647
|
+
... "ACCOUNTADDRESS",
|
|
648
|
+
... "DISPENSERADDRESS",
|
|
649
|
+
... algokit.algo(1),
|
|
650
|
+
... min_funding_increment=algokit.algo(2),
|
|
651
|
+
... fee=AlgoAmount.from_micro_algo(1000),
|
|
652
|
+
... suppress_log=True
|
|
653
|
+
... )
|
|
654
654
|
"""
|
|
655
655
|
account_to_fund = self._get_address(account_to_fund)
|
|
656
656
|
dispenser_account = self._get_address(dispenser_account)
|
|
@@ -724,7 +724,7 @@ class AccountManager:
|
|
|
724
724
|
|
|
725
725
|
:param account_to_fund: The account to fund
|
|
726
726
|
:param min_spending_balance: The minimum balance of Algo that the account should have available to
|
|
727
|
-
|
|
727
|
+
spend
|
|
728
728
|
:param min_funding_increment: Optional minimum funding increment
|
|
729
729
|
:param send_params: Parameters for the send operation, defaults to None
|
|
730
730
|
:param signer: Optional transaction signer
|
|
@@ -738,7 +738,7 @@ class AccountManager:
|
|
|
738
738
|
:param first_valid_round: Optional first valid round
|
|
739
739
|
:param last_valid_round: Optional last valid round
|
|
740
740
|
:returns: The result of executing the dispensing transaction and the `amountFunded` if funds were needed, or
|
|
741
|
-
|
|
741
|
+
None if no funds were needed
|
|
742
742
|
|
|
743
743
|
.. note::
|
|
744
744
|
The dispenser account is retrieved from the account mnemonic stored in
|
|
@@ -746,16 +746,16 @@ class AccountManager:
|
|
|
746
746
|
if it's a rekeyed account, or against default LocalNet if no environment variables present.
|
|
747
747
|
|
|
748
748
|
:example:
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
749
|
+
>>> # Basic example:
|
|
750
|
+
>>> algorand.account.ensure_funded_from_environment("ACCOUNTADDRESS", algokit.algo(1))
|
|
751
|
+
>>> # With configuration:
|
|
752
|
+
>>> algorand.account.ensure_funded_from_environment(
|
|
753
|
+
... "ACCOUNTADDRESS",
|
|
754
|
+
... algokit.algo(1),
|
|
755
|
+
... min_funding_increment=algokit.algo(2),
|
|
756
|
+
... fee=AlgoAmount.from_micro_algo(1000),
|
|
757
|
+
... suppress_log=True
|
|
758
|
+
... )
|
|
759
759
|
"""
|
|
760
760
|
account_to_fund = self._get_address(account_to_fund)
|
|
761
761
|
dispenser_account = self.dispenser_from_environment()
|
|
@@ -818,26 +818,26 @@ class AccountManager:
|
|
|
818
818
|
:param account_to_fund: The account to fund
|
|
819
819
|
:param dispenser_client: The TestNet dispenser funding client
|
|
820
820
|
:param min_spending_balance: The minimum balance of Algo that the account should have
|
|
821
|
-
|
|
821
|
+
available to spend
|
|
822
822
|
:param min_funding_increment: Optional minimum funding increment
|
|
823
823
|
:returns: The result of executing the dispensing transaction and the `amountFunded` if funds were needed, or
|
|
824
|
-
|
|
824
|
+
None if no funds were needed
|
|
825
825
|
:raises ValueError: If attempting to fund on non-TestNet network
|
|
826
826
|
|
|
827
827
|
:example:
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
828
|
+
>>> # Basic example:
|
|
829
|
+
>>> algorand.account.ensure_funded_from_testnet_dispenser_api(
|
|
830
|
+
... "ACCOUNTADDRESS",
|
|
831
|
+
... algorand.client.get_testnet_dispenser_from_environment(),
|
|
832
|
+
... algokit.algo(1)
|
|
833
|
+
... )
|
|
834
|
+
>>> # With configuration:
|
|
835
|
+
>>> algorand.account.ensure_funded_from_testnet_dispenser_api(
|
|
836
|
+
... "ACCOUNTADDRESS",
|
|
837
|
+
... algorand.client.get_testnet_dispenser_from_environment(),
|
|
838
|
+
... algokit.algo(1),
|
|
839
|
+
... min_funding_increment=algokit.algo(2)
|
|
840
|
+
... )
|
|
841
841
|
"""
|
|
842
842
|
account_to_fund = self._get_address(account_to_fund)
|
|
843
843
|
|
|
@@ -48,6 +48,8 @@ class KmdAccountManager:
|
|
|
48
48
|
if self._kmd is None:
|
|
49
49
|
if self._client_manager.is_localnet():
|
|
50
50
|
kmd_config = ClientManager.get_config_from_environment_or_localnet()
|
|
51
|
+
if not kmd_config.kmd_config:
|
|
52
|
+
raise Exception("Attempt to use KMD client with no KMD configured")
|
|
51
53
|
self._kmd = ClientManager.get_kmd_client(kmd_config.kmd_config)
|
|
52
54
|
return self._kmd
|
|
53
55
|
raise Exception("Attempt to use KMD client with no KMD configured")
|
|
@@ -5,7 +5,7 @@ import copy
|
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
7
|
from collections.abc import Sequence
|
|
8
|
-
from dataclasses import asdict, dataclass, fields
|
|
8
|
+
from dataclasses import asdict, dataclass, fields, replace
|
|
9
9
|
from typing import TYPE_CHECKING, Any, Generic, Literal, TypedDict, TypeVar
|
|
10
10
|
|
|
11
11
|
import algosdk
|
|
@@ -54,6 +54,7 @@ from algokit_utils.transactions.transaction_composer import (
|
|
|
54
54
|
AppUpdateParams,
|
|
55
55
|
BuiltTransactions,
|
|
56
56
|
PaymentParams,
|
|
57
|
+
SendAtomicTransactionComposerResults,
|
|
57
58
|
)
|
|
58
59
|
from algokit_utils.transactions.transaction_sender import (
|
|
59
60
|
SendAppTransactionResult,
|
|
@@ -1189,28 +1190,51 @@ class _TransactionSender:
|
|
|
1189
1190
|
:param params: Parameters for the application call including method and transaction options
|
|
1190
1191
|
:param send_params: Send parameters
|
|
1191
1192
|
:return: The result of sending or simulating the transaction, including ABI return value if applicable
|
|
1193
|
+
:raises ValueError: If the transaction is read-only and `max_fee` is not provided
|
|
1192
1194
|
"""
|
|
1193
1195
|
is_read_only_call = (
|
|
1194
1196
|
params.on_complete == algosdk.transaction.OnComplete.NoOpOC or params.on_complete is None
|
|
1195
1197
|
) and self._app_spec.get_arc56_method(params.method).readonly
|
|
1196
1198
|
|
|
1197
1199
|
if is_read_only_call:
|
|
1200
|
+
readonly_params = params
|
|
1201
|
+
readonly_send_params = send_params or SendParams()
|
|
1202
|
+
|
|
1203
|
+
# Read-only calls do not require fees to be paid, as they are only simulated on the network.
|
|
1204
|
+
# Therefore there is no value in calculating the minimum fee needed for a successful app call with inners.
|
|
1205
|
+
# As a a result we only need to send a single simulate call,
|
|
1206
|
+
# however to do this successfully we need to ensure fees for the transaction are fully covered using maxFee.
|
|
1207
|
+
if readonly_send_params.get("cover_app_call_inner_transaction_fees"):
|
|
1208
|
+
if params.max_fee is None:
|
|
1209
|
+
raise ValueError(
|
|
1210
|
+
"Please provide a `max_fee` for the transaction when `cover_app_call_inner_transaction_fees` is enabled." # noqa: E501
|
|
1211
|
+
)
|
|
1212
|
+
readonly_params = replace(readonly_params, static_fee=params.max_fee, extra_fee=None)
|
|
1213
|
+
|
|
1198
1214
|
method_call_to_simulate = self._algorand.new_group().add_app_call_method_call(
|
|
1199
|
-
self._client.params.call(
|
|
1200
|
-
)
|
|
1201
|
-
send_params = send_params or SendParams()
|
|
1202
|
-
simulate_response = self._client._handle_call_errors(
|
|
1203
|
-
lambda: method_call_to_simulate.simulate(
|
|
1204
|
-
allow_unnamed_resources=send_params.get("populate_app_call_resources") or True,
|
|
1205
|
-
skip_signatures=True,
|
|
1206
|
-
allow_more_logs=True,
|
|
1207
|
-
allow_empty_signatures=True,
|
|
1208
|
-
extra_opcode_budget=None,
|
|
1209
|
-
exec_trace_config=None,
|
|
1210
|
-
simulation_round=None,
|
|
1211
|
-
)
|
|
1215
|
+
self._client.params.call(readonly_params)
|
|
1212
1216
|
)
|
|
1213
1217
|
|
|
1218
|
+
def run_simulate() -> SendAtomicTransactionComposerResults:
|
|
1219
|
+
try:
|
|
1220
|
+
return method_call_to_simulate.simulate(
|
|
1221
|
+
allow_unnamed_resources=readonly_send_params.get("populate_app_call_resources") or True,
|
|
1222
|
+
skip_signatures=True,
|
|
1223
|
+
allow_more_logs=True,
|
|
1224
|
+
allow_empty_signatures=True,
|
|
1225
|
+
extra_opcode_budget=None,
|
|
1226
|
+
exec_trace_config=None,
|
|
1227
|
+
simulation_round=None,
|
|
1228
|
+
)
|
|
1229
|
+
except Exception as e:
|
|
1230
|
+
if readonly_send_params.get("cover_app_call_inner_transaction_fees") and "fee too small" in str(e):
|
|
1231
|
+
raise ValueError(
|
|
1232
|
+
"Fees were too small. You may need to increase the transaction `maxFee`."
|
|
1233
|
+
) from e
|
|
1234
|
+
raise
|
|
1235
|
+
|
|
1236
|
+
simulate_response = self._client._handle_call_errors(run_simulate)
|
|
1237
|
+
|
|
1214
1238
|
return SendAppTransactionResult[Arc56ReturnValueType](
|
|
1215
1239
|
tx_ids=simulate_response.tx_ids,
|
|
1216
1240
|
transactions=simulate_response.transactions,
|
|
@@ -43,13 +43,13 @@ class AssetInformation:
|
|
|
43
43
|
:ivar decimals: The amount of decimal places the asset was created with
|
|
44
44
|
:ivar default_frozen: Whether the asset was frozen by default for all accounts, defaults to None
|
|
45
45
|
:ivar manager: The address of the optional account that can manage the configuration of the asset and destroy it,
|
|
46
|
-
|
|
46
|
+
defaults to None
|
|
47
47
|
:ivar reserve: The address of the optional account that holds the reserve (uncirculated supply) units of the asset,
|
|
48
|
-
|
|
48
|
+
defaults to None
|
|
49
49
|
:ivar freeze: The address of the optional account that can be used to freeze or unfreeze holdings of this asset,
|
|
50
|
-
|
|
50
|
+
defaults to None
|
|
51
51
|
:ivar clawback: The address of the optional account that can clawback holdings of this asset from any account,
|
|
52
|
-
|
|
52
|
+
defaults to None
|
|
53
53
|
:ivar unit_name: The optional name of the unit of this asset (e.g. ticker name), defaults to None
|
|
54
54
|
:ivar unit_name_b64: The optional name of the unit of this asset as bytes, defaults to None
|
|
55
55
|
:ivar asset_name: The optional name of the asset, defaults to None
|
|
@@ -57,7 +57,7 @@ class AssetInformation:
|
|
|
57
57
|
:ivar url: Optional URL where more information about the asset can be retrieved, defaults to None
|
|
58
58
|
:ivar url_b64: Optional URL where more information about the asset can be retrieved as bytes, defaults to None
|
|
59
59
|
:ivar metadata_hash: 32-byte hash of some metadata that is relevant to the asset and/or asset holders,
|
|
60
|
-
|
|
60
|
+
defaults to None
|
|
61
61
|
"""
|
|
62
62
|
|
|
63
63
|
asset_id: int
|
|
@@ -77,8 +77,8 @@ def _get_config_from_environment(environment_prefix: str) -> AlgoClientNetworkCo
|
|
|
77
77
|
port = os.getenv(f"{environment_prefix}_PORT")
|
|
78
78
|
if port:
|
|
79
79
|
parsed = parse.urlparse(server)
|
|
80
|
-
server = parsed._replace(netloc=f"{parsed.hostname}
|
|
81
|
-
return AlgoClientNetworkConfig(server, os.getenv(f"{environment_prefix}_TOKEN", ""))
|
|
80
|
+
server = parsed._replace(netloc=f"{parsed.hostname}").geturl()
|
|
81
|
+
return AlgoClientNetworkConfig(server, os.getenv(f"{environment_prefix}_TOKEN", ""), port=port)
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
class ClientManager:
|
|
@@ -351,15 +351,18 @@ class ClientManager:
|
|
|
351
351
|
)
|
|
352
352
|
|
|
353
353
|
@staticmethod
|
|
354
|
-
def get_algod_client(config: AlgoClientNetworkConfig
|
|
354
|
+
def get_algod_client(config: AlgoClientNetworkConfig) -> AlgodClient:
|
|
355
355
|
"""Get an Algod client from config or environment.
|
|
356
356
|
|
|
357
357
|
:param config: Optional client configuration
|
|
358
358
|
:return: Algod client instance
|
|
359
359
|
"""
|
|
360
|
-
config = config or _get_config_from_environment("ALGOD")
|
|
361
360
|
headers = {"X-Algo-API-Token": config.token or ""}
|
|
362
|
-
return AlgodClient(
|
|
361
|
+
return AlgodClient(
|
|
362
|
+
algod_token=config.token or "",
|
|
363
|
+
algod_address=config.full_url(),
|
|
364
|
+
headers=headers,
|
|
365
|
+
)
|
|
363
366
|
|
|
364
367
|
@staticmethod
|
|
365
368
|
def get_algod_client_from_environment() -> AlgodClient:
|
|
@@ -370,14 +373,13 @@ class ClientManager:
|
|
|
370
373
|
return ClientManager.get_algod_client(ClientManager.get_algod_config_from_environment())
|
|
371
374
|
|
|
372
375
|
@staticmethod
|
|
373
|
-
def get_kmd_client(config: AlgoClientNetworkConfig
|
|
376
|
+
def get_kmd_client(config: AlgoClientNetworkConfig) -> KMDClient:
|
|
374
377
|
"""Get a KMD client from config or environment.
|
|
375
378
|
|
|
376
379
|
:param config: Optional client configuration
|
|
377
380
|
:return: KMD client instance
|
|
378
381
|
"""
|
|
379
|
-
config
|
|
380
|
-
return KMDClient(config.token, config.server)
|
|
382
|
+
return KMDClient(config.token, config.full_url())
|
|
381
383
|
|
|
382
384
|
@staticmethod
|
|
383
385
|
def get_kmd_client_from_environment() -> KMDClient:
|
|
@@ -388,15 +390,18 @@ class ClientManager:
|
|
|
388
390
|
return ClientManager.get_kmd_client(ClientManager.get_kmd_config_from_environment())
|
|
389
391
|
|
|
390
392
|
@staticmethod
|
|
391
|
-
def get_indexer_client(config: AlgoClientNetworkConfig
|
|
393
|
+
def get_indexer_client(config: AlgoClientNetworkConfig) -> IndexerClient:
|
|
392
394
|
"""Get an Indexer client from config or environment.
|
|
393
395
|
|
|
394
396
|
:param config: Optional client configuration
|
|
395
397
|
:return: Indexer client instance
|
|
396
398
|
"""
|
|
397
|
-
config = config or _get_config_from_environment("INDEXER")
|
|
398
399
|
headers = {"X-Indexer-API-Token": config.token}
|
|
399
|
-
return IndexerClient(
|
|
400
|
+
return IndexerClient(
|
|
401
|
+
indexer_token=config.token,
|
|
402
|
+
indexer_address=config.full_url(),
|
|
403
|
+
headers=headers,
|
|
404
|
+
)
|
|
400
405
|
|
|
401
406
|
@staticmethod
|
|
402
407
|
def get_indexer_client_from_environment() -> IndexerClient:
|
|
@@ -611,7 +616,7 @@ class ClientManager:
|
|
|
611
616
|
else {"algod": 4001, "indexer": 8980, "kmd": 4002}[config_or_port]
|
|
612
617
|
)
|
|
613
618
|
|
|
614
|
-
return AlgoClientNetworkConfig(server=
|
|
619
|
+
return AlgoClientNetworkConfig(server="http://localhost", token="a" * 64, port=port)
|
|
615
620
|
|
|
616
621
|
@staticmethod
|
|
617
622
|
def get_algod_config_from_environment() -> AlgoClientNetworkConfig:
|
algokit_utils/models/amount.py
CHANGED
|
@@ -13,58 +13,34 @@ class AlgoAmount:
|
|
|
13
13
|
"""Wrapper class to ensure safe, explicit conversion between µAlgo, Algo and numbers.
|
|
14
14
|
|
|
15
15
|
:example:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
>>> amount = AlgoAmount(micro_algos=1_000_000)
|
|
21
|
-
>>> amount = AlgoAmount(micro_algo=1_000_000)
|
|
22
|
-
>>> amount = AlgoAmount.from_micro_algos(1_000_000)
|
|
23
|
-
>>> amount = AlgoAmount.from_micro_algo(1_000_000)
|
|
16
|
+
>>> amount = AlgoAmount(algo=1)
|
|
17
|
+
>>> amount = AlgoAmount.from_algo(1)
|
|
18
|
+
>>> amount = AlgoAmount(micro_algo=1_000_000)
|
|
19
|
+
>>> amount = AlgoAmount.from_micro_algo(1_000_000)
|
|
24
20
|
"""
|
|
25
21
|
|
|
26
|
-
@overload
|
|
27
|
-
def __init__(self, *, micro_algos: int) -> None: ...
|
|
28
|
-
|
|
29
22
|
@overload
|
|
30
23
|
def __init__(self, *, micro_algo: int) -> None: ...
|
|
31
24
|
|
|
32
|
-
@overload
|
|
33
|
-
def __init__(self, *, algos: int | Decimal) -> None: ...
|
|
34
|
-
|
|
35
25
|
@overload
|
|
36
26
|
def __init__(self, *, algo: int | Decimal) -> None: ...
|
|
37
27
|
|
|
38
28
|
def __init__(
|
|
39
29
|
self,
|
|
40
30
|
*,
|
|
41
|
-
micro_algos: int | None = None,
|
|
42
31
|
micro_algo: int | None = None,
|
|
43
|
-
algos: int | Decimal | None = None,
|
|
44
32
|
algo: int | Decimal | None = None,
|
|
45
33
|
):
|
|
46
|
-
if
|
|
34
|
+
if micro_algo is None and algo is None:
|
|
47
35
|
raise ValueError("No amount provided")
|
|
48
36
|
|
|
49
|
-
if
|
|
50
|
-
self.amount_in_micro_algo = int(micro_algos)
|
|
51
|
-
elif micro_algo is not None:
|
|
37
|
+
if micro_algo is not None:
|
|
52
38
|
self.amount_in_micro_algo = int(micro_algo)
|
|
53
|
-
elif algos is not None:
|
|
54
|
-
self.amount_in_micro_algo = int(algos * algosdk.constants.MICROALGOS_TO_ALGOS_RATIO)
|
|
55
39
|
elif algo is not None:
|
|
56
40
|
self.amount_in_micro_algo = int(algo * algosdk.constants.MICROALGOS_TO_ALGOS_RATIO)
|
|
57
41
|
else:
|
|
58
42
|
raise ValueError("Invalid amount provided")
|
|
59
43
|
|
|
60
|
-
@property
|
|
61
|
-
def micro_algos(self) -> int:
|
|
62
|
-
"""Return the amount as a number in µAlgo.
|
|
63
|
-
|
|
64
|
-
:returns: The amount in µAlgo.
|
|
65
|
-
"""
|
|
66
|
-
return self.amount_in_micro_algo
|
|
67
|
-
|
|
68
44
|
@property
|
|
69
45
|
def micro_algo(self) -> int:
|
|
70
46
|
"""Return the amount as a number in µAlgo.
|
|
@@ -73,14 +49,6 @@ class AlgoAmount:
|
|
|
73
49
|
"""
|
|
74
50
|
return self.amount_in_micro_algo
|
|
75
51
|
|
|
76
|
-
@property
|
|
77
|
-
def algos(self) -> Decimal:
|
|
78
|
-
"""Return the amount as a number in Algo.
|
|
79
|
-
|
|
80
|
-
:returns: The amount in Algo.
|
|
81
|
-
"""
|
|
82
|
-
return algosdk.util.microalgos_to_algos(self.amount_in_micro_algo) # type: ignore[no-any-return]
|
|
83
|
-
|
|
84
52
|
@property
|
|
85
53
|
def algo(self) -> Decimal:
|
|
86
54
|
"""Return the amount as a number in Algo.
|
|
@@ -89,18 +57,6 @@ class AlgoAmount:
|
|
|
89
57
|
"""
|
|
90
58
|
return algosdk.util.microalgos_to_algos(self.amount_in_micro_algo) # type: ignore[no-any-return]
|
|
91
59
|
|
|
92
|
-
@staticmethod
|
|
93
|
-
def from_algos(amount: int | Decimal) -> AlgoAmount:
|
|
94
|
-
"""Create an AlgoAmount object representing the given number of Algo.
|
|
95
|
-
|
|
96
|
-
:param amount: The amount in Algo.
|
|
97
|
-
:returns: An AlgoAmount instance.
|
|
98
|
-
|
|
99
|
-
:example:
|
|
100
|
-
>>> amount = AlgoAmount.from_algos(1)
|
|
101
|
-
"""
|
|
102
|
-
return AlgoAmount(algos=amount)
|
|
103
|
-
|
|
104
60
|
@staticmethod
|
|
105
61
|
def from_algo(amount: int | Decimal) -> AlgoAmount:
|
|
106
62
|
"""Create an AlgoAmount object representing the given number of Algo.
|
|
@@ -109,22 +65,10 @@ class AlgoAmount:
|
|
|
109
65
|
:returns: An AlgoAmount instance.
|
|
110
66
|
|
|
111
67
|
:example:
|
|
112
|
-
|
|
68
|
+
>>> amount = AlgoAmount.from_algo(1)
|
|
113
69
|
"""
|
|
114
70
|
return AlgoAmount(algo=amount)
|
|
115
71
|
|
|
116
|
-
@staticmethod
|
|
117
|
-
def from_micro_algos(amount: int) -> AlgoAmount:
|
|
118
|
-
"""Create an AlgoAmount object representing the given number of µAlgo.
|
|
119
|
-
|
|
120
|
-
:param amount: The amount in µAlgo.
|
|
121
|
-
:returns: An AlgoAmount instance.
|
|
122
|
-
|
|
123
|
-
:example:
|
|
124
|
-
>>> amount = AlgoAmount.from_micro_algos(1_000_000)
|
|
125
|
-
"""
|
|
126
|
-
return AlgoAmount(micro_algos=amount)
|
|
127
|
-
|
|
128
72
|
@staticmethod
|
|
129
73
|
def from_micro_algo(amount: int) -> AlgoAmount:
|
|
130
74
|
"""Create an AlgoAmount object representing the given number of µAlgo.
|
|
@@ -133,7 +77,7 @@ class AlgoAmount:
|
|
|
133
77
|
:returns: An AlgoAmount instance.
|
|
134
78
|
|
|
135
79
|
:example:
|
|
136
|
-
|
|
80
|
+
>>> amount = AlgoAmount.from_micro_algo(1_000_000)
|
|
137
81
|
"""
|
|
138
82
|
return AlgoAmount(micro_algo=amount)
|
|
139
83
|
|
|
@@ -141,21 +85,21 @@ class AlgoAmount:
|
|
|
141
85
|
return f"{self.micro_algo:,} µALGO"
|
|
142
86
|
|
|
143
87
|
def __int__(self) -> int:
|
|
144
|
-
return self.
|
|
88
|
+
return self.micro_algo
|
|
145
89
|
|
|
146
90
|
def __add__(self, other: AlgoAmount) -> AlgoAmount:
|
|
147
91
|
if isinstance(other, AlgoAmount):
|
|
148
|
-
total_micro_algos = self.
|
|
92
|
+
total_micro_algos = self.micro_algo + other.micro_algo
|
|
149
93
|
else:
|
|
150
94
|
raise TypeError(f"Unsupported operand type(s) for +: 'AlgoAmount' and '{type(other).__name__}'")
|
|
151
|
-
return AlgoAmount.
|
|
95
|
+
return AlgoAmount.from_micro_algo(total_micro_algos)
|
|
152
96
|
|
|
153
97
|
def __radd__(self, other: AlgoAmount) -> AlgoAmount:
|
|
154
98
|
return self.__add__(other)
|
|
155
99
|
|
|
156
100
|
def __iadd__(self, other: AlgoAmount) -> Self:
|
|
157
101
|
if isinstance(other, AlgoAmount):
|
|
158
|
-
self.amount_in_micro_algo += other.
|
|
102
|
+
self.amount_in_micro_algo += other.micro_algo
|
|
159
103
|
else:
|
|
160
104
|
raise TypeError(f"Unsupported operand type(s) for +: 'AlgoAmount' and '{type(other).__name__}'")
|
|
161
105
|
return self
|
|
@@ -204,42 +148,42 @@ class AlgoAmount:
|
|
|
204
148
|
|
|
205
149
|
def __sub__(self, other: AlgoAmount) -> AlgoAmount:
|
|
206
150
|
if isinstance(other, AlgoAmount):
|
|
207
|
-
total_micro_algos = self.
|
|
151
|
+
total_micro_algos = self.micro_algo - other.micro_algo
|
|
208
152
|
else:
|
|
209
153
|
raise TypeError(f"Unsupported operand type(s) for -: 'AlgoAmount' and '{type(other).__name__}'")
|
|
210
|
-
return AlgoAmount.
|
|
154
|
+
return AlgoAmount.from_micro_algo(total_micro_algos)
|
|
211
155
|
|
|
212
156
|
def __rsub__(self, other: int) -> AlgoAmount:
|
|
213
157
|
if isinstance(other, (int)):
|
|
214
|
-
total_micro_algos = int(other) - self.
|
|
215
|
-
return AlgoAmount.
|
|
158
|
+
total_micro_algos = int(other) - self.micro_algo
|
|
159
|
+
return AlgoAmount.from_micro_algo(total_micro_algos)
|
|
216
160
|
raise TypeError(f"Unsupported operand type(s) for -: '{type(other).__name__}' and 'AlgoAmount'")
|
|
217
161
|
|
|
218
162
|
def __isub__(self, other: AlgoAmount) -> Self:
|
|
219
163
|
if isinstance(other, AlgoAmount):
|
|
220
|
-
self.amount_in_micro_algo -= other.
|
|
164
|
+
self.amount_in_micro_algo -= other.micro_algo
|
|
221
165
|
else:
|
|
222
166
|
raise TypeError(f"Unsupported operand type(s) for -: 'AlgoAmount' and '{type(other).__name__}'")
|
|
223
167
|
return self
|
|
224
168
|
|
|
225
169
|
|
|
226
170
|
# Helper functions
|
|
227
|
-
def algo(
|
|
171
|
+
def algo(algo: int) -> AlgoAmount:
|
|
228
172
|
"""Create an AlgoAmount object representing the given number of Algo.
|
|
229
173
|
|
|
230
|
-
:param
|
|
174
|
+
:param algo: The number of Algo to create an AlgoAmount object for.
|
|
231
175
|
:return: An AlgoAmount object representing the given number of Algo.
|
|
232
176
|
"""
|
|
233
|
-
return AlgoAmount.
|
|
177
|
+
return AlgoAmount.from_algo(algo)
|
|
234
178
|
|
|
235
179
|
|
|
236
|
-
def micro_algo(
|
|
180
|
+
def micro_algo(micro_algo: int) -> AlgoAmount:
|
|
237
181
|
"""Create an AlgoAmount object representing the given number of µAlgo.
|
|
238
182
|
|
|
239
|
-
:param
|
|
183
|
+
:param micro_algo: The number of µAlgo to create an AlgoAmount object for.
|
|
240
184
|
:return: An AlgoAmount object representing the given number of µAlgo.
|
|
241
185
|
"""
|
|
242
|
-
return AlgoAmount.
|
|
186
|
+
return AlgoAmount.from_micro_algo(micro_algo)
|
|
243
187
|
|
|
244
188
|
|
|
245
189
|
ALGORAND_MIN_TX_FEE = micro_algo(1_000)
|
|
@@ -252,5 +196,5 @@ def transaction_fees(number_of_transactions: int) -> AlgoAmount:
|
|
|
252
196
|
:return: The total transaction fees.
|
|
253
197
|
"""
|
|
254
198
|
|
|
255
|
-
total_micro_algos = number_of_transactions * ALGORAND_MIN_TX_FEE.
|
|
256
|
-
return
|
|
199
|
+
total_micro_algos = number_of_transactions * ALGORAND_MIN_TX_FEE.micro_algo
|
|
200
|
+
return AlgoAmount.from_micro_algo(total_micro_algos)
|
algokit_utils/models/network.py
CHANGED
|
@@ -12,11 +12,15 @@ class AlgoClientNetworkConfig:
|
|
|
12
12
|
{py:class}`algosdk.v2client.indexer.IndexerClient`"""
|
|
13
13
|
|
|
14
14
|
server: str
|
|
15
|
-
"""URL for the service e.g. `http://localhost
|
|
15
|
+
"""URL for the service e.g. `http://localhost` or `https://testnet-api.algonode.cloud`"""
|
|
16
16
|
token: str | None = None
|
|
17
|
-
"""API Token to authenticate with the service"""
|
|
17
|
+
"""API Token to authenticate with the service e.g '4001' or '8980'"""
|
|
18
18
|
port: str | int | None = None
|
|
19
19
|
|
|
20
|
+
def full_url(self) -> str:
|
|
21
|
+
"""Returns the full URL for the service"""
|
|
22
|
+
return f"{self.server.rstrip('/')}{f':{self.port}' if self.port else ''}"
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
@dataclasses.dataclass
|
|
22
26
|
class AlgoClientConfigs:
|
|
@@ -68,6 +68,8 @@ __all__ = [
|
|
|
68
68
|
"TransactionComposer",
|
|
69
69
|
"TransactionComposerBuildResult",
|
|
70
70
|
"TxnParams",
|
|
71
|
+
"populate_app_call_resources",
|
|
72
|
+
"prepare_group_for_sending",
|
|
71
73
|
"send_atomic_transaction_composer",
|
|
72
74
|
]
|
|
73
75
|
|
|
@@ -107,7 +109,7 @@ class PaymentParams(_CommonTxnParams):
|
|
|
107
109
|
:ivar receiver: The account that will receive the ALGO
|
|
108
110
|
:ivar amount: Amount to send
|
|
109
111
|
:ivar close_remainder_to: If given, close the sender account and send the remaining balance to this address,
|
|
110
|
-
|
|
112
|
+
defaults to None
|
|
111
113
|
"""
|
|
112
114
|
|
|
113
115
|
receiver: str
|
|
@@ -299,9 +301,9 @@ class AppCreateParams(_CommonTxnParams):
|
|
|
299
301
|
"""Parameters for creating an application.
|
|
300
302
|
|
|
301
303
|
:ivar approval_program: The program to execute for all OnCompletes other than ClearState as raw teal (string)
|
|
302
|
-
|
|
304
|
+
or compiled teal (bytes)
|
|
303
305
|
:ivar clear_state_program: The program to execute for ClearState OnComplete as raw teal (string)
|
|
304
|
-
|
|
306
|
+
or compiled teal (bytes)
|
|
305
307
|
:ivar schema: The state schema for the app. This is immutable, defaults to None
|
|
306
308
|
:ivar on_complete: The OnComplete action (cannot be ClearState), defaults to None
|
|
307
309
|
:ivar args: Application arguments, defaults to None
|
|
@@ -330,9 +332,9 @@ class AppUpdateParams(_CommonTxnParams):
|
|
|
330
332
|
|
|
331
333
|
:ivar app_id: ID of the application
|
|
332
334
|
:ivar approval_program: The program to execute for all OnCompletes other than ClearState as raw teal (string)
|
|
333
|
-
|
|
335
|
+
or compiled teal (bytes)
|
|
334
336
|
:ivar clear_state_program: The program to execute for ClearState OnComplete as raw teal (string)
|
|
335
|
-
|
|
337
|
+
or compiled teal (bytes)
|
|
336
338
|
:ivar args: Application arguments, defaults to None
|
|
337
339
|
:ivar account_references: Account references, defaults to None
|
|
338
340
|
:ivar app_references: App references, defaults to None
|
|
@@ -417,7 +419,7 @@ class AppCallMethodCallParams(_BaseAppMethodCall):
|
|
|
417
419
|
:ivar app_id: ID of the application
|
|
418
420
|
:ivar method: The ABI method to call
|
|
419
421
|
:ivar args: Arguments to the ABI method, either an ABI value, transaction with explicit signer,
|
|
420
|
-
|
|
422
|
+
transaction, another method call, or None
|
|
421
423
|
:ivar on_complete: The OnComplete action (cannot be UpdateApplication or ClearState), defaults to None
|
|
422
424
|
"""
|
|
423
425
|
|
|
@@ -673,7 +675,7 @@ def _get_group_execution_info( # noqa: C901, PLR0912
|
|
|
673
675
|
if not suggested_params:
|
|
674
676
|
raise ValueError("suggested_params required when cover_app_call_inner_transaction_fees enabled")
|
|
675
677
|
|
|
676
|
-
max_fee = max_fees.get(i).
|
|
678
|
+
max_fee = max_fees.get(i).micro_algo if max_fees and i in max_fees else None # type: ignore[union-attr]
|
|
677
679
|
if max_fee is None:
|
|
678
680
|
app_call_indexes_without_max_fees.append(i)
|
|
679
681
|
else:
|
|
@@ -843,7 +845,7 @@ def prepare_group_for_sending( # noqa: C901, PLR0912, PLR0915
|
|
|
843
845
|
if not txn_info:
|
|
844
846
|
continue
|
|
845
847
|
txn = group[i].txn
|
|
846
|
-
max_fee = max_fees.get(i).
|
|
848
|
+
max_fee = max_fees.get(i).micro_algo if max_fees and i in max_fees else None # type: ignore[union-attr]
|
|
847
849
|
immutable_fee = max_fee is not None and max_fee == txn.fee
|
|
848
850
|
priority_multiplier = (
|
|
849
851
|
1000
|
|
@@ -1096,7 +1098,7 @@ def prepare_group_for_sending( # noqa: C901, PLR0912, PLR0915
|
|
|
1096
1098
|
)
|
|
1097
1099
|
|
|
1098
1100
|
transaction_fee = cur_txn.fee + additional_fee
|
|
1099
|
-
max_fee = max_fees.get(i).
|
|
1101
|
+
max_fee = max_fees.get(i).micro_algo if max_fees and i in max_fees else None # type: ignore[union-attr]
|
|
1100
1102
|
|
|
1101
1103
|
if max_fee is None or transaction_fee > max_fee:
|
|
1102
1104
|
raise ValueError(
|
|
@@ -1324,7 +1326,7 @@ class TransactionComposer:
|
|
|
1324
1326
|
:param algod: An instance of AlgodClient used to get suggested params and send transactions
|
|
1325
1327
|
:param get_signer: A function that takes an address and returns a TransactionSigner for that address
|
|
1326
1328
|
:param get_suggested_params: Optional function to get suggested transaction parameters,
|
|
1327
|
-
|
|
1329
|
+
defaults to using algod.suggested_params()
|
|
1328
1330
|
:param default_validity_window: Optional default validity window for transactions in rounds, defaults to 10
|
|
1329
1331
|
:param app_manager: Optional AppManager instance for compiling TEAL programs, defaults to None
|
|
1330
1332
|
"""
|
|
@@ -1600,6 +1602,8 @@ class TransactionComposer:
|
|
|
1600
1602
|
signers[idx] = ts.signer
|
|
1601
1603
|
if isinstance(ts, TransactionWithSignerAndContext) and ts.context.abi_method:
|
|
1602
1604
|
method_calls[idx] = ts.context.abi_method
|
|
1605
|
+
if ts.context.max_fee:
|
|
1606
|
+
self._txn_max_fees[idx] = ts.context.max_fee
|
|
1603
1607
|
idx += 1
|
|
1604
1608
|
|
|
1605
1609
|
return BuiltTransactions(transactions=transactions, method_calls=method_calls, signers=signers)
|
|
@@ -1681,7 +1685,7 @@ class TransactionComposer:
|
|
|
1681
1685
|
|
|
1682
1686
|
:param allow_more_logs: Whether to allow more logs than the standard limit
|
|
1683
1687
|
:param allow_empty_signatures: Whether to allow transactions with empty signatures
|
|
1684
|
-
:param allow_unnamed_resources: Whether to allow unnamed resources
|
|
1688
|
+
:param allow_unnamed_resources: Whether to allow unnamed resources.
|
|
1685
1689
|
:param extra_opcode_budget: Additional opcode budget to allocate
|
|
1686
1690
|
:param exec_trace_config: Configuration for execution tracing
|
|
1687
1691
|
:param simulation_round: Round number to simulate at
|
|
@@ -1839,7 +1843,7 @@ class TransactionComposer:
|
|
|
1839
1843
|
txn_params["sp"].last = txn_params["sp"].first + window
|
|
1840
1844
|
|
|
1841
1845
|
if params.static_fee is not None and txn_params["sp"]:
|
|
1842
|
-
txn_params["sp"].fee = params.static_fee.
|
|
1846
|
+
txn_params["sp"].fee = params.static_fee.micro_algo
|
|
1843
1847
|
txn_params["sp"].flat_fee = True
|
|
1844
1848
|
|
|
1845
1849
|
if isinstance(txn_params.get("method"), Arc56Method):
|
|
@@ -1848,9 +1852,9 @@ class TransactionComposer:
|
|
|
1848
1852
|
txn = build_txn(txn_params)
|
|
1849
1853
|
|
|
1850
1854
|
if params.extra_fee:
|
|
1851
|
-
txn.fee += params.extra_fee.
|
|
1855
|
+
txn.fee += params.extra_fee.micro_algo
|
|
1852
1856
|
|
|
1853
|
-
if params.max_fee and txn.fee > params.max_fee.
|
|
1857
|
+
if params.max_fee and txn.fee > params.max_fee.micro_algo:
|
|
1854
1858
|
raise ValueError(f"Transaction fee {txn.fee} is greater than max_fee {params.max_fee}")
|
|
1855
1859
|
use_max_fee = params.max_fee and params.max_fee.micro_algo > (
|
|
1856
1860
|
params.static_fee.micro_algo if params.static_fee else 0
|
|
@@ -2037,7 +2041,7 @@ class TransactionComposer:
|
|
|
2037
2041
|
"sender": params.sender,
|
|
2038
2042
|
"sp": suggested_params,
|
|
2039
2043
|
"receiver": params.receiver,
|
|
2040
|
-
"amt": params.amount.
|
|
2044
|
+
"amt": params.amount.micro_algo,
|
|
2041
2045
|
"close_remainder_to": params.close_remainder_to,
|
|
2042
2046
|
}
|
|
2043
2047
|
|
|
@@ -3,7 +3,7 @@ algokit_utils/_debugging.py,sha256=nAiC10WXiZsvc0RPWOrMLpjJQZT_ItgcMl7D9Z4DfYc,1
|
|
|
3
3
|
algokit_utils/_legacy_v2/__init__.py,sha256=WcRE30axWjGnBB09bJCeTw9NT-2_jDN_CVJITFcIDc8,4689
|
|
4
4
|
algokit_utils/_legacy_v2/_ensure_funded.py,sha256=tw4ZEcqsKBHbSCH9gPz3V2onGaj1kyv6BM9V59fLgCU,6931
|
|
5
5
|
algokit_utils/_legacy_v2/_transfer.py,sha256=FRut71CU8kDn4-FqMepwZGjFPhPtQg5Wv5_kdtVqK-8,6256
|
|
6
|
-
algokit_utils/_legacy_v2/account.py,sha256=
|
|
6
|
+
algokit_utils/_legacy_v2/account.py,sha256=_4pxTKO6y9XK4CkUb1M9Du_XVXKeU1MWXHx54KPVbMk,8240
|
|
7
7
|
algokit_utils/_legacy_v2/application_client.py,sha256=ScUalY2h2Wj_TAPYdxuucAmdwRwvO-xZ0yOMXDb9OgE,59536
|
|
8
8
|
algokit_utils/_legacy_v2/application_specification.py,sha256=wp2Y9ou2_F-bSFbDnm6AEhFexybmD7-fAT0CuWtO26g,521
|
|
9
9
|
algokit_utils/_legacy_v2/asset.py,sha256=b4GEzsPuHAbb330ZjoyY3lol0SisQGwJiOpnXvuXvJI,7594
|
|
@@ -14,14 +14,14 @@ algokit_utils/_legacy_v2/models.py,sha256=hH7aO50E4po4EgxXI9zdX5HTthn1HLfSLvkuPf
|
|
|
14
14
|
algokit_utils/_legacy_v2/network_clients.py,sha256=5nqC-47hreWvMxR-PQWs_QP44wJDAGhtS1MQv8JQ82o,5660
|
|
15
15
|
algokit_utils/account.py,sha256=gyGrBSoafUh8WV677IzYGkYoxtzzElsgxGMp4SgA4pk,410
|
|
16
16
|
algokit_utils/accounts/__init__.py,sha256=_LyY0se6TaQOes7vAcmbpt6pmG4VKlzfTt37-IjwimA,138
|
|
17
|
-
algokit_utils/accounts/account_manager.py,sha256=
|
|
18
|
-
algokit_utils/accounts/kmd_account_manager.py,sha256=
|
|
17
|
+
algokit_utils/accounts/account_manager.py,sha256=zr8NV6k9L8xESzsmbFK06T-DOmVEvHWcoHgIIX5SDcQ,39763
|
|
18
|
+
algokit_utils/accounts/kmd_account_manager.py,sha256=0flsU5T11JciyL0YvOKDHPVSm-ghV0RjJAbtm8JwrhU,6476
|
|
19
19
|
algokit_utils/algorand.py,sha256=Gtx3vspZmSxUrNWmh09NFQB24G4v4CEogYuRX_9o5Xw,10554
|
|
20
20
|
algokit_utils/application_client.py,sha256=5UIxXIBjukjRyjZPCeXmaNlAftbb3TziV7EfBolW79k,337
|
|
21
21
|
algokit_utils/application_specification.py,sha256=-ZM13Qv-AcLmwudJCq8xGPoWLvAvKBICgAdHeFozKbY,1416
|
|
22
22
|
algokit_utils/applications/__init__.py,sha256=NGjhpBeExsQZOAYCT2QUFag1xuKoFiX-Ux5SR2GNzd8,452
|
|
23
23
|
algokit_utils/applications/abi.py,sha256=ZwiLuFXx2EwWJ_cOEvNWCzt5onoasm-QmQPv9N7d49g,10087
|
|
24
|
-
algokit_utils/applications/app_client.py,sha256=
|
|
24
|
+
algokit_utils/applications/app_client.py,sha256=oAwe9_6-ETWJIdXNScDvUiVYN8JNP4kplSnr3qCQPVY,84979
|
|
25
25
|
algokit_utils/applications/app_deployer.py,sha256=RrSmIsbN84z0lNtGD8JP2FwkDmsAD_HvF8b4kHnCSmo,23099
|
|
26
26
|
algokit_utils/applications/app_factory.py,sha256=wljyXuXWaMc3KJkDeACJ5XVEfIsVxeSXqdGTJ9p3tJQ,33425
|
|
27
27
|
algokit_utils/applications/app_manager.py,sha256=EA1uRtmvPVAdKi1I5HSCpHjIDgLN7eZcEPT0Cj3C7fU,17661
|
|
@@ -31,14 +31,14 @@ algokit_utils/applications/app_spec/arc56.py,sha256=8GyQ_gDBSkHLzTL35D1r7dce5owh
|
|
|
31
31
|
algokit_utils/applications/enums.py,sha256=1MUBrPW9v0-OZk6jsa5rqSEEpC-z-6QAQIs9G7pLn1I,1257
|
|
32
32
|
algokit_utils/asset.py,sha256=ZnNo_MsDGPb8UTPxi7cmIZpbrT0x0xZjblHP01pDAC0,874
|
|
33
33
|
algokit_utils/assets/__init__.py,sha256=6igogt0eo0TEae6-rO9qPsmlrKkbnkq3aV8wtePX3yk,63
|
|
34
|
-
algokit_utils/assets/asset_manager.py,sha256=
|
|
34
|
+
algokit_utils/assets/asset_manager.py,sha256=0vs02dbXarAkVxehM4XJp_AHveZCujIPfnQVXiwhZiw,14152
|
|
35
35
|
algokit_utils/beta/_utils.py,sha256=eGgrSH5dA7Lhe7Z_9rudU7O6azZHMH0U7A3in4GpFOg,1839
|
|
36
36
|
algokit_utils/beta/account_manager.py,sha256=xDFvsMSha0Ki42BGvKvfScQWT_W9y4GeP_RWXjc3vnE,213
|
|
37
37
|
algokit_utils/beta/algorand_client.py,sha256=xDFvsMSha0Ki42BGvKvfScQWT_W9y4GeP_RWXjc3vnE,213
|
|
38
38
|
algokit_utils/beta/client_manager.py,sha256=xDFvsMSha0Ki42BGvKvfScQWT_W9y4GeP_RWXjc3vnE,213
|
|
39
39
|
algokit_utils/beta/composer.py,sha256=xDFvsMSha0Ki42BGvKvfScQWT_W9y4GeP_RWXjc3vnE,213
|
|
40
40
|
algokit_utils/clients/__init__.py,sha256=qUuKBvfLnw4z6ZU9x7mc-mLjfnnXC9UcvtoeU33ZLJ8,136
|
|
41
|
-
algokit_utils/clients/client_manager.py,sha256=
|
|
41
|
+
algokit_utils/clients/client_manager.py,sha256=Yl5k7LwlUaoHh76tNK1UxFl8xoFdaTejrhrr488E0Ww,25559
|
|
42
42
|
algokit_utils/clients/dispenser_api_client.py,sha256=lx6II3beCt7YiKO2TrW6UbsRVirf3NoWMJi8HD_W5nI,6045
|
|
43
43
|
algokit_utils/common.py,sha256=5wl83vWw91RYdEC4hTTufqaptKiFtgjKLIyONDmRSH0,300
|
|
44
44
|
algokit_utils/config.py,sha256=Fd466a33pyqmblKn3YUEoSqMSGbKDmZeaS5Uu7_CNHw,7029
|
|
@@ -49,9 +49,9 @@ algokit_utils/errors/logic_error.py,sha256=uxqUOU9-D1R5TrKturCbmmWRVlB024Ca4CfVi
|
|
|
49
49
|
algokit_utils/logic_error.py,sha256=3duw-l6tBr-DeapO0e0tYHoa9rOxP-QZZ6QWmN8L9tc,305
|
|
50
50
|
algokit_utils/models/__init__.py,sha256=0aB_c5pnkqKl1Z0hkxM9qbKn2qVdizZE2DvziN9ObqM,465
|
|
51
51
|
algokit_utils/models/account.py,sha256=TdeKjhYkppD8g0DYRGbnCsi8zfPz3zU74DaZte_CYJw,6014
|
|
52
|
-
algokit_utils/models/amount.py,sha256=
|
|
52
|
+
algokit_utils/models/amount.py,sha256=PcjzqRY5ThcUuSYHk1yeYgUooos1j2-54hBIJJcipd4,7567
|
|
53
53
|
algokit_utils/models/application.py,sha256=lM2_g5kZ18k_zyVzcbGvkvqHzksfb2sgRqowJ3pvUgo,1288
|
|
54
|
-
algokit_utils/models/network.py,sha256=
|
|
54
|
+
algokit_utils/models/network.py,sha256=3QNcZ9jVmckv3CCxrD2Y1jiwBdBGdaaziiRgOpsqhwI,904
|
|
55
55
|
algokit_utils/models/simulate.py,sha256=F9OSEfA9QGFGe5po24h8IGLor5z1ogu5Cwm3l6cHnAs,236
|
|
56
56
|
algokit_utils/models/state.py,sha256=N6jsjZiZsz-Rn1ZDnBRvVv1En-lUrh97JuaaDRZtCkg,1478
|
|
57
57
|
algokit_utils/models/transaction.py,sha256=Am0-rmfiANVq9_Zbd1zMTtaV91ZcPqtEfpp2ScQ2Ji8,3052
|
|
@@ -61,10 +61,10 @@ algokit_utils/protocols/account.py,sha256=CowaVY7ErBP84TWBHNvBjkZy18whPb8HIlMZtJ
|
|
|
61
61
|
algokit_utils/protocols/typed_clients.py,sha256=UrQrHbN2SvS8pEFJ8JQodvouoWeBrQOQGZGyBQx1KLM,3322
|
|
62
62
|
algokit_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
63
63
|
algokit_utils/transactions/__init__.py,sha256=7fYF3m6DyOGzbV36MT5svo0wSkj9AIz496kWgIWSAlk,225
|
|
64
|
-
algokit_utils/transactions/transaction_composer.py,sha256=
|
|
64
|
+
algokit_utils/transactions/transaction_composer.py,sha256=AZ4xVHH1IFSKSoxdHpvGVfa2v-e9MkZGiXilCHnjfqE,94996
|
|
65
65
|
algokit_utils/transactions/transaction_creator.py,sha256=A1YHeGC2EkR2V0HPYJiXVOAEIrfjBW2KVyYgi3exm4E,6167
|
|
66
66
|
algokit_utils/transactions/transaction_sender.py,sha256=uQmHElJgUIxLXfdklMNoabjQQzUku8CFP82wwhfr44E,22769
|
|
67
|
-
algokit_utils-3.0.
|
|
68
|
-
algokit_utils-3.0.
|
|
69
|
-
algokit_utils-3.0.
|
|
70
|
-
algokit_utils-3.0.
|
|
67
|
+
algokit_utils-3.0.0b5.dist-info/LICENSE,sha256=J5i7U1Q9Q2c7saUzlvFRmrCCFhQyXb5Juz_LO5omNUw,1076
|
|
68
|
+
algokit_utils-3.0.0b5.dist-info/METADATA,sha256=agxt079grOlLMzeM0hMFI9g-yl8PfBbVqKUVCMAF1M8,2416
|
|
69
|
+
algokit_utils-3.0.0b5.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
70
|
+
algokit_utils-3.0.0b5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|