algokit-utils 4.2.2b1__py3-none-any.whl → 4.2.3b1__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.

@@ -20,7 +20,7 @@ __all__ = [
20
20
 
21
21
 
22
22
  LOGIC_ERROR = (
23
- ".*transaction (?P<transaction_id>[A-Z0-9]+): logic eval error: (?P<message>.*). Details: .*pc=(?P<pc>[0-9]+).*"
23
+ ".*transaction (?P<transaction_id>[A-Z0-9]+): (logic eval error: )?(?P<message>.*). Details: .*pc=(?P<pc>[0-9]+).*"
24
24
  )
25
25
 
26
26
 
@@ -21,7 +21,7 @@ from algosdk.atomic_transaction_composer import (
21
21
  from algosdk.transaction import OnComplete, SuggestedParams
22
22
  from algosdk.v2client.algod import AlgodClient
23
23
  from algosdk.v2client.models.simulate_request import SimulateRequest
24
- from typing_extensions import deprecated
24
+ from typing_extensions import Never, deprecated
25
25
 
26
26
  from algokit_utils.applications.abi import ABIReturn, ABIValue
27
27
  from algokit_utils.applications.app_manager import AppManager
@@ -667,7 +667,7 @@ def _encode_lease(lease: str | bytes | None) -> bytes | None:
667
667
  raise TypeError(f"Unknown lease type received of {type(lease)}")
668
668
 
669
669
 
670
- def _get_group_execution_info( # noqa: C901, PLR0912
670
+ def _get_group_execution_info(
671
671
  atc: AtomicTransactionComposer,
672
672
  algod: AlgodClient,
673
673
  populate_app_call_resources: bool | None = None,
@@ -682,6 +682,7 @@ def _get_group_execution_info( # noqa: C901, PLR0912
682
682
  txn_groups=[],
683
683
  allow_unnamed_resources=True,
684
684
  allow_empty_signatures=True,
685
+ exec_trace_config=algosdk.v2client.models.SimulateTraceConfig(enable=True),
685
686
  )
686
687
 
687
688
  # Clone ATC with null signers
@@ -710,26 +711,14 @@ def _get_group_execution_info( # noqa: C901, PLR0912
710
711
  f"Required for transactions: {', '.join(str(i) for i in app_call_indexes_without_max_fees)}"
711
712
  )
712
713
 
713
- # Get fee parameters
714
- per_byte_txn_fee = suggested_params.fee if suggested_params else 0
715
- min_txn_fee = int(suggested_params.min_fee) if suggested_params else 1000 # type: ignore[unused-ignore]
716
-
717
714
  # Simulate transactions
718
715
  result = empty_signer_atc.simulate(algod, simulate_request)
719
716
 
720
717
  group_response = result.simulate_response["txn-groups"][0]
721
718
 
722
719
  if group_response.get("failure-message"):
723
- msg = group_response["failure-message"]
724
- if cover_app_call_inner_transaction_fees and "fee too small" in msg:
725
- raise ValueError(
726
- "Fees were too small to resolve execution info via simulate. "
727
- "You may need to increase an app call transaction maxFee."
728
- )
729
- failed_at = group_response.get("failed-at", [0])[0]
730
- raise ValueError(
731
- f"Error resolving execution info via simulate in transaction {failed_at}: "
732
- f"{group_response['failure-message']}"
720
+ _handle_simulation_error(
721
+ group_response, cover_app_call_inner_transaction_fees=cover_app_call_inner_transaction_fees
733
722
  )
734
723
 
735
724
  # Build execution info
@@ -743,27 +732,12 @@ def _get_group_execution_info( # noqa: C901, PLR0912
743
732
 
744
733
  required_fee_delta = 0
745
734
  if cover_app_call_inner_transaction_fees:
746
- # Calculate parent transaction fee
747
- parent_per_byte_fee = per_byte_txn_fee * (original_txn.estimate_size() + 75)
748
- parent_min_fee = max(parent_per_byte_fee, min_txn_fee)
749
- parent_fee_delta = parent_min_fee - original_txn.fee
750
-
751
- if isinstance(original_txn, algosdk.transaction.ApplicationCallTxn):
752
- # Calculate inner transaction fees recursively
753
- def calculate_inner_fee_delta(inner_txns: list[dict], acc: int = 0) -> int:
754
- for inner_txn in reversed(inner_txns):
755
- current_fee_delta = (
756
- calculate_inner_fee_delta(inner_txn["inner-txns"], acc)
757
- if inner_txn.get("inner-txns")
758
- else acc
759
- ) + (min_txn_fee - inner_txn["txn"]["txn"].get("fee", 0))
760
- acc = max(0, current_fee_delta)
761
- return acc
762
-
763
- inner_fee_delta = calculate_inner_fee_delta(txn_result.get("inner-txns", []))
764
- required_fee_delta = inner_fee_delta + parent_fee_delta
765
- else:
766
- required_fee_delta = parent_fee_delta
735
+ required_fee_delta = _calculate_required_fee_delta(
736
+ original_txn,
737
+ txn_result,
738
+ per_byte_txn_fee=suggested_params.fee if suggested_params else 0,
739
+ min_txn_fee=int(suggested_params.min_fee) if suggested_params else 1000,
740
+ )
767
741
 
768
742
  txn_results.append(
769
743
  ExecutionInfoTxn(
@@ -782,6 +756,64 @@ def _get_group_execution_info( # noqa: C901, PLR0912
782
756
  )
783
757
 
784
758
 
759
+ def _handle_simulation_error(
760
+ group_response: dict[str, Any], *, cover_app_call_inner_transaction_fees: bool | None
761
+ ) -> Never:
762
+ msg = group_response["failure-message"]
763
+ if cover_app_call_inner_transaction_fees and "fee too small" in msg:
764
+ raise ValueError(
765
+ "Fees were too small to resolve execution info via simulate. "
766
+ "You may need to increase an app call transaction maxFee."
767
+ )
768
+ failed_at = group_response.get("failed-at", [0])[0]
769
+ details = ""
770
+ if "logic eval error" not in msg:
771
+ # extract last pc from trace so we can format an error that can be parsed into a LogicError
772
+ try:
773
+ trace = group_response["txn-results"][failed_at]["exec-trace"]
774
+ except (KeyError, IndexError):
775
+ pass
776
+ else:
777
+ try:
778
+ program_trace = trace["approval-program-trace"]
779
+ except KeyError:
780
+ program_trace = trace["clear-program-trace"]
781
+ pc = program_trace[-1]["pc"]
782
+ details = f". Details: pc={pc}"
783
+ raise ValueError(
784
+ f"Error resolving execution info via simulate in transaction {failed_at}: "
785
+ f"{group_response['failure-message']}{details}"
786
+ )
787
+
788
+
789
+ def _calculate_required_fee_delta(
790
+ txn: transaction.Transaction, txn_result: dict[str, Any], *, per_byte_txn_fee: int, min_txn_fee: int
791
+ ) -> int:
792
+ # Calculate parent transaction fee
793
+ original_txn_size = txn.estimate_size()
794
+ assert isinstance(original_txn_size, int), "expected txn size to be an int"
795
+ parent_per_byte_fee = per_byte_txn_fee * (original_txn_size + 75)
796
+ parent_min_fee = max(parent_per_byte_fee, min_txn_fee)
797
+ original_txn_fee = txn.fee
798
+ assert isinstance(original_txn_fee, int), "expected original txn fee to be an int"
799
+ parent_fee_delta = parent_min_fee - original_txn_fee
800
+
801
+ if isinstance(txn, algosdk.transaction.ApplicationCallTxn):
802
+ # Calculate inner transaction fees recursively
803
+ def calculate_inner_fee_delta(inner_txns: list[dict], acc: int = 0) -> int:
804
+ for inner_txn in reversed(inner_txns):
805
+ current_fee_delta = (
806
+ calculate_inner_fee_delta(inner_txn["inner-txns"], acc) if inner_txn.get("inner-txns") else acc
807
+ ) + (min_txn_fee - inner_txn["txn"]["txn"].get("fee", 0))
808
+ acc = max(0, current_fee_delta)
809
+ return acc
810
+
811
+ inner_fee_delta = calculate_inner_fee_delta(txn_result.get("inner-txns", []))
812
+ return inner_fee_delta + parent_fee_delta
813
+ else:
814
+ return parent_fee_delta
815
+
816
+
785
817
  def _find_available_transaction_index(
786
818
  txns: list[TransactionWithSigner], reference_type: str, reference: str | dict[str, Any] | int
787
819
  ) -> int:
@@ -1041,13 +1073,15 @@ def prepare_group_for_sending( # noqa: C901, PLR0912, PLR0915
1041
1073
  foreign_apps.append(app_id)
1042
1074
  app_txn.foreign_apps = foreign_apps
1043
1075
  elif ref_type == "box":
1076
+ # ensure app_id is added before calling translate_box_reference
1077
+ app_id = box_ref[0]
1078
+ if app_id != 0:
1079
+ foreign_apps = list(getattr(app_txn, "foreign_apps", []) or [])
1080
+ foreign_apps.append(app_id)
1081
+ app_txn.foreign_apps = foreign_apps
1044
1082
  boxes = list(getattr(app_txn, "boxes", []) or [])
1045
1083
  boxes.append(BoxReference.translate_box_reference(box_ref, app_txn.foreign_apps or [], app_txn.index)) # type: ignore[arg-type]
1046
1084
  app_txn.boxes = boxes
1047
- if box_ref[0] != 0:
1048
- foreign_apps = list(getattr(app_txn, "foreign_apps", []) or [])
1049
- foreign_apps.append(box_ref[0])
1050
- app_txn.foreign_apps = foreign_apps
1051
1085
  elif ref_type == "asset":
1052
1086
  asset_id = int(cast(str | int, reference))
1053
1087
  foreign_assets = list(getattr(app_txn, "foreign_assets", []) or [])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: algokit-utils
3
- Version: 4.2.2b1
3
+ Version: 4.2.3b1
4
4
  Summary: Utilities for Algorand development for use by AlgoKit
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Programming Language :: Python :: 3.14
17
17
  Requires-Dist: httpx (>=0.23.1,<=0.28.1)
18
- Requires-Dist: py-algorand-sdk (>=2.4.0,<3.0.0)
18
+ Requires-Dist: py-algorand-sdk (>=2.11.0,<3.0.0)
19
19
  Requires-Dist: typing-extensions (>=4.6.0)
20
20
  Description-Content-Type: text/markdown
21
21
 
@@ -45,7 +45,7 @@ algokit_utils/config.py,sha256=CvDH5B8uPWnm6wCHHlMsl-0lONzq26vPLvwmnbw7c-k,6048
45
45
  algokit_utils/deploy.py,sha256=UUtSDI6JcBUuto62FuirhUlDcjZwQyLkiERgDMx8P7A,330
46
46
  algokit_utils/dispenser_api.py,sha256=-EO4Dq3q_v4kSMey43kXJfoX8uCBPJpjEMTlLI7xn_I,324
47
47
  algokit_utils/errors/__init__.py,sha256=CmuiLVjzMAOYxPaIIwmYCNArsso_RtS2ssFoNdp5CMs,61
48
- algokit_utils/errors/logic_error.py,sha256=uxqUOU9-D1R5TrKturCbmmWRVlB024Ca4CfVi8x_sgo,4104
48
+ algokit_utils/errors/logic_error.py,sha256=ksRsYjo7a3_8scf9UhByoQ4x3BJ7WpVYRQoiEScV3pM,4107
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=eqGJvExzd7gDm3--DBDaIq6pJarxMPHZ-UySxZ9Qznk,6778
@@ -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=fuxiDRo5OeoYSLvVuR-_MsvXkwGZe3ALRLDw_TBExKM,107196
64
+ algokit_utils/transactions/transaction_composer.py,sha256=aDYo9SGjMr-cKUEwZUJx2Cyw85rZz77n_LVe2fGINH8,108435
65
65
  algokit_utils/transactions/transaction_creator.py,sha256=cuP6Xm-fhGoCc2FNSbLiEg3iQRwW38rfdTzsqPyEcpM,29053
66
66
  algokit_utils/transactions/transaction_sender.py,sha256=Wi3ws9S-Df1JeTlaSTXmq-WS24Gsq7WGsKk1B0z23ao,50117
67
- algokit_utils-4.2.2b1.dist-info/METADATA,sha256=nikULZH7JNw6Vtht9Nw84f7Anhms0RAO9I7Rp7iBnKM,2494
68
- algokit_utils-4.2.2b1.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
69
- algokit_utils-4.2.2b1.dist-info/licenses/LICENSE,sha256=J5i7U1Q9Q2c7saUzlvFRmrCCFhQyXb5Juz_LO5omNUw,1076
70
- algokit_utils-4.2.2b1.dist-info/RECORD,,
67
+ algokit_utils-4.2.3b1.dist-info/METADATA,sha256=lfW9YW_QLOmzdPBSpFyPyQhpOVacqOn-M2S-pH72myA,2495
68
+ algokit_utils-4.2.3b1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
69
+ algokit_utils-4.2.3b1.dist-info/licenses/LICENSE,sha256=J5i7U1Q9Q2c7saUzlvFRmrCCFhQyXb5Juz_LO5omNUw,1076
70
+ algokit_utils-4.2.3b1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.2.0
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any