algokit-utils 2.4.0b1__py3-none-any.whl → 3.0.0__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.

Files changed (70) hide show
  1. algokit_utils/__init__.py +23 -181
  2. algokit_utils/_debugging.py +89 -45
  3. algokit_utils/_legacy_v2/__init__.py +177 -0
  4. algokit_utils/{_ensure_funded.py → _legacy_v2/_ensure_funded.py} +21 -24
  5. algokit_utils/{_transfer.py → _legacy_v2/_transfer.py} +26 -23
  6. algokit_utils/_legacy_v2/account.py +203 -0
  7. algokit_utils/_legacy_v2/application_client.py +1472 -0
  8. algokit_utils/_legacy_v2/application_specification.py +21 -0
  9. algokit_utils/_legacy_v2/asset.py +168 -0
  10. algokit_utils/_legacy_v2/common.py +28 -0
  11. algokit_utils/_legacy_v2/deploy.py +822 -0
  12. algokit_utils/_legacy_v2/logic_error.py +14 -0
  13. algokit_utils/{models.py → _legacy_v2/models.py} +16 -45
  14. algokit_utils/_legacy_v2/network_clients.py +144 -0
  15. algokit_utils/account.py +12 -183
  16. algokit_utils/accounts/__init__.py +2 -0
  17. algokit_utils/accounts/account_manager.py +912 -0
  18. algokit_utils/accounts/kmd_account_manager.py +161 -0
  19. algokit_utils/algorand.py +359 -0
  20. algokit_utils/application_client.py +9 -1447
  21. algokit_utils/application_specification.py +39 -197
  22. algokit_utils/applications/__init__.py +7 -0
  23. algokit_utils/applications/abi.py +275 -0
  24. algokit_utils/applications/app_client.py +2108 -0
  25. algokit_utils/applications/app_deployer.py +725 -0
  26. algokit_utils/applications/app_factory.py +1134 -0
  27. algokit_utils/applications/app_manager.py +578 -0
  28. algokit_utils/applications/app_spec/__init__.py +2 -0
  29. algokit_utils/applications/app_spec/arc32.py +207 -0
  30. algokit_utils/applications/app_spec/arc56.py +989 -0
  31. algokit_utils/applications/enums.py +40 -0
  32. algokit_utils/asset.py +32 -168
  33. algokit_utils/assets/__init__.py +1 -0
  34. algokit_utils/assets/asset_manager.py +336 -0
  35. algokit_utils/beta/_utils.py +36 -0
  36. algokit_utils/beta/account_manager.py +4 -195
  37. algokit_utils/beta/algorand_client.py +4 -314
  38. algokit_utils/beta/client_manager.py +5 -74
  39. algokit_utils/beta/composer.py +5 -712
  40. algokit_utils/clients/__init__.py +2 -0
  41. algokit_utils/clients/client_manager.py +738 -0
  42. algokit_utils/clients/dispenser_api_client.py +224 -0
  43. algokit_utils/common.py +8 -26
  44. algokit_utils/config.py +76 -29
  45. algokit_utils/deploy.py +7 -894
  46. algokit_utils/dispenser_api.py +8 -176
  47. algokit_utils/errors/__init__.py +1 -0
  48. algokit_utils/errors/logic_error.py +121 -0
  49. algokit_utils/logic_error.py +7 -82
  50. algokit_utils/models/__init__.py +8 -0
  51. algokit_utils/models/account.py +217 -0
  52. algokit_utils/models/amount.py +200 -0
  53. algokit_utils/models/application.py +91 -0
  54. algokit_utils/models/network.py +29 -0
  55. algokit_utils/models/simulate.py +11 -0
  56. algokit_utils/models/state.py +68 -0
  57. algokit_utils/models/transaction.py +100 -0
  58. algokit_utils/network_clients.py +7 -128
  59. algokit_utils/protocols/__init__.py +2 -0
  60. algokit_utils/protocols/account.py +22 -0
  61. algokit_utils/protocols/typed_clients.py +108 -0
  62. algokit_utils/transactions/__init__.py +3 -0
  63. algokit_utils/transactions/transaction_composer.py +2499 -0
  64. algokit_utils/transactions/transaction_creator.py +688 -0
  65. algokit_utils/transactions/transaction_sender.py +1219 -0
  66. {algokit_utils-2.4.0b1.dist-info → algokit_utils-3.0.0.dist-info}/METADATA +11 -7
  67. algokit_utils-3.0.0.dist-info/RECORD +70 -0
  68. {algokit_utils-2.4.0b1.dist-info → algokit_utils-3.0.0.dist-info}/WHEEL +1 -1
  69. algokit_utils-2.4.0b1.dist-info/RECORD +0 -24
  70. {algokit_utils-2.4.0b1.dist-info → algokit_utils-3.0.0.dist-info}/LICENSE +0 -0
@@ -0,0 +1,207 @@
1
+ import base64
2
+ import dataclasses
3
+ import json
4
+ from enum import IntFlag
5
+ from pathlib import Path
6
+ from typing import Any, Literal, TypeAlias, TypedDict
7
+
8
+ from algosdk.abi import Contract
9
+ from algosdk.abi.method import MethodDict
10
+ from algosdk.transaction import StateSchema
11
+
12
+ __all__ = [
13
+ "AppSpecStateDict",
14
+ "Arc32Contract",
15
+ "CallConfig",
16
+ "DefaultArgumentDict",
17
+ "DefaultArgumentType",
18
+ "MethodConfigDict",
19
+ "MethodHints",
20
+ "OnCompleteActionName",
21
+ "StateDict",
22
+ "StructArgDict",
23
+ ]
24
+
25
+
26
+ AppSpecStateDict: TypeAlias = dict[str, dict[str, dict]]
27
+ """Type defining Application Specification state entries"""
28
+
29
+
30
+ class CallConfig(IntFlag):
31
+ """Describes the type of calls a method can be used for based on {py:class}`algosdk.transaction.OnComplete` type"""
32
+
33
+ NEVER = 0
34
+ """Never handle the specified on completion type"""
35
+ CALL = 1
36
+ """Only handle the specified on completion type for application calls"""
37
+ CREATE = 2
38
+ """Only handle the specified on completion type for application create calls"""
39
+ ALL = 3
40
+ """Handle the specified on completion type for both create and normal application calls"""
41
+
42
+
43
+ class StructArgDict(TypedDict):
44
+ name: str
45
+ elements: list[list[str]]
46
+
47
+
48
+ OnCompleteActionName: TypeAlias = Literal[
49
+ "no_op", "opt_in", "close_out", "clear_state", "update_application", "delete_application"
50
+ ]
51
+ """String literals representing on completion transaction types"""
52
+ MethodConfigDict: TypeAlias = dict[OnCompleteActionName, CallConfig]
53
+ """Dictionary of `dict[OnCompletionActionName, CallConfig]` representing allowed actions for each on completion type"""
54
+ DefaultArgumentType: TypeAlias = Literal["abi-method", "local-state", "global-state", "constant"]
55
+ """Literal values describing the types of default argument sources"""
56
+
57
+
58
+ class DefaultArgumentDict(TypedDict):
59
+ """
60
+ DefaultArgument is a container for any arguments that may
61
+ be resolved prior to calling some target method
62
+ """
63
+
64
+ source: DefaultArgumentType
65
+ data: int | str | bytes | MethodDict
66
+
67
+
68
+ StateDict = TypedDict( # need to use function-form of TypedDict here since "global" is a reserved keyword
69
+ "StateDict", {"global": AppSpecStateDict, "local": AppSpecStateDict}
70
+ )
71
+
72
+
73
+ @dataclasses.dataclass(kw_only=True)
74
+ class MethodHints:
75
+ """MethodHints provides hints to the caller about how to call the method"""
76
+
77
+ #: hint to indicate this method can be called through Dryrun
78
+ read_only: bool = False
79
+ #: hint to provide names for tuple argument indices
80
+ #: method_name=>param_name=>{name:str, elements:[str,str]}
81
+ structs: dict[str, StructArgDict] = dataclasses.field(default_factory=dict)
82
+ #: defaults
83
+ default_arguments: dict[str, DefaultArgumentDict] = dataclasses.field(default_factory=dict)
84
+ call_config: MethodConfigDict = dataclasses.field(default_factory=dict)
85
+
86
+ def empty(self) -> bool:
87
+ return not self.dictify()
88
+
89
+ def dictify(self) -> dict[str, Any]:
90
+ d: dict[str, Any] = {}
91
+ if self.read_only:
92
+ d["read_only"] = True
93
+ if self.default_arguments:
94
+ d["default_arguments"] = self.default_arguments
95
+ if self.structs:
96
+ d["structs"] = self.structs
97
+ if any(v for v in self.call_config.values() if v != CallConfig.NEVER):
98
+ d["call_config"] = _encode_method_config(self.call_config)
99
+ return d
100
+
101
+ @staticmethod
102
+ def undictify(data: dict[str, Any]) -> "MethodHints":
103
+ return MethodHints(
104
+ read_only=data.get("read_only", False),
105
+ default_arguments=data.get("default_arguments", {}),
106
+ structs=data.get("structs", {}),
107
+ call_config=_decode_method_config(data.get("call_config", {})),
108
+ )
109
+
110
+
111
+ def _encode_method_config(mc: MethodConfigDict) -> dict[str, str | None]:
112
+ return {k: mc[k].name for k in sorted(mc) if mc[k] != CallConfig.NEVER}
113
+
114
+
115
+ def _decode_method_config(data: dict[OnCompleteActionName, Any]) -> MethodConfigDict:
116
+ return {k: CallConfig[v] for k, v in data.items()}
117
+
118
+
119
+ def _encode_source(teal_text: str) -> str:
120
+ return base64.b64encode(teal_text.encode()).decode("utf-8")
121
+
122
+
123
+ def _decode_source(b64_text: str) -> str:
124
+ return base64.b64decode(b64_text).decode("utf-8")
125
+
126
+
127
+ def _encode_state_schema(schema: StateSchema) -> dict[str, int]:
128
+ return {
129
+ "num_byte_slices": schema.num_byte_slices,
130
+ "num_uints": schema.num_uints,
131
+ } # type: ignore[unused-ignore]
132
+
133
+
134
+ def _decode_state_schema(data: dict[str, int]) -> StateSchema:
135
+ return StateSchema(
136
+ num_byte_slices=data.get("num_byte_slices", 0),
137
+ num_uints=data.get("num_uints", 0),
138
+ )
139
+
140
+
141
+ @dataclasses.dataclass(kw_only=True)
142
+ class Arc32Contract:
143
+ """ARC-0032 application specification
144
+
145
+ See <https://github.com/algorandfoundation/ARCs/pull/150>"""
146
+
147
+ approval_program: str
148
+ clear_program: str
149
+ contract: Contract
150
+ hints: dict[str, MethodHints]
151
+ schema: StateDict
152
+ global_state_schema: StateSchema
153
+ local_state_schema: StateSchema
154
+ bare_call_config: MethodConfigDict
155
+
156
+ def dictify(self) -> dict:
157
+ return {
158
+ "hints": {k: v.dictify() for k, v in self.hints.items() if not v.empty()},
159
+ "source": {
160
+ "approval": _encode_source(self.approval_program),
161
+ "clear": _encode_source(self.clear_program),
162
+ },
163
+ "state": {
164
+ "global": _encode_state_schema(self.global_state_schema),
165
+ "local": _encode_state_schema(self.local_state_schema),
166
+ },
167
+ "schema": self.schema,
168
+ "contract": self.contract.dictify(),
169
+ "bare_call_config": _encode_method_config(self.bare_call_config),
170
+ }
171
+
172
+ def to_json(self, indent: int | None = None) -> str:
173
+ return json.dumps(self.dictify(), indent=indent)
174
+
175
+ @staticmethod
176
+ def from_json(application_spec: str) -> "Arc32Contract":
177
+ json_spec = json.loads(application_spec)
178
+ return Arc32Contract(
179
+ approval_program=_decode_source(json_spec["source"]["approval"]),
180
+ clear_program=_decode_source(json_spec["source"]["clear"]),
181
+ schema=json_spec["schema"],
182
+ global_state_schema=_decode_state_schema(json_spec["state"]["global"]),
183
+ local_state_schema=_decode_state_schema(json_spec["state"]["local"]),
184
+ contract=Contract.undictify(json_spec["contract"]),
185
+ hints={k: MethodHints.undictify(v) for k, v in json_spec["hints"].items()},
186
+ bare_call_config=_decode_method_config(json_spec.get("bare_call_config", {})),
187
+ )
188
+
189
+ def export(self, directory: Path | str | None = None) -> None:
190
+ """Write out the artifacts generated by the application to disk.
191
+
192
+ Writes the approval program, clear program, contract specification and application specification
193
+ to files in the specified directory.
194
+
195
+ :param directory: Path to the directory where the artifacts should be written. If not specified,
196
+ uses the current working directory
197
+ """
198
+ if directory is None:
199
+ output_dir = Path.cwd()
200
+ else:
201
+ output_dir = Path(directory)
202
+ output_dir.mkdir(exist_ok=True, parents=True)
203
+
204
+ (output_dir / "approval.teal").write_text(self.approval_program)
205
+ (output_dir / "clear.teal").write_text(self.clear_program)
206
+ (output_dir / "contract.json").write_text(json.dumps(self.contract.dictify(), indent=4))
207
+ (output_dir / "application.json").write_text(self.to_json())