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.
- algokit_utils/__init__.py +23 -181
- algokit_utils/_debugging.py +89 -45
- algokit_utils/_legacy_v2/__init__.py +177 -0
- algokit_utils/{_ensure_funded.py → _legacy_v2/_ensure_funded.py} +21 -24
- algokit_utils/{_transfer.py → _legacy_v2/_transfer.py} +26 -23
- algokit_utils/_legacy_v2/account.py +203 -0
- algokit_utils/_legacy_v2/application_client.py +1472 -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} +16 -45
- algokit_utils/_legacy_v2/network_clients.py +144 -0
- algokit_utils/account.py +12 -183
- algokit_utils/accounts/__init__.py +2 -0
- algokit_utils/accounts/account_manager.py +912 -0
- algokit_utils/accounts/kmd_account_manager.py +161 -0
- algokit_utils/algorand.py +359 -0
- algokit_utils/application_client.py +9 -1447
- algokit_utils/application_specification.py +39 -197
- algokit_utils/applications/__init__.py +7 -0
- algokit_utils/applications/abi.py +275 -0
- algokit_utils/applications/app_client.py +2108 -0
- algokit_utils/applications/app_deployer.py +725 -0
- algokit_utils/applications/app_factory.py +1134 -0
- algokit_utils/applications/app_manager.py +578 -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 +989 -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 +336 -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 +738 -0
- algokit_utils/clients/dispenser_api_client.py +224 -0
- algokit_utils/common.py +8 -26
- algokit_utils/config.py +76 -29
- algokit_utils/deploy.py +7 -894
- 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 -82
- algokit_utils/models/__init__.py +8 -0
- algokit_utils/models/account.py +217 -0
- algokit_utils/models/amount.py +200 -0
- algokit_utils/models/application.py +91 -0
- algokit_utils/models/network.py +29 -0
- algokit_utils/models/simulate.py +11 -0
- algokit_utils/models/state.py +68 -0
- algokit_utils/models/transaction.py +100 -0
- algokit_utils/network_clients.py +7 -128
- 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 +2499 -0
- algokit_utils/transactions/transaction_creator.py +688 -0
- algokit_utils/transactions/transaction_sender.py +1219 -0
- {algokit_utils-2.4.0b1.dist-info → algokit_utils-3.0.0.dist-info}/METADATA +11 -7
- algokit_utils-3.0.0.dist-info/RECORD +70 -0
- {algokit_utils-2.4.0b1.dist-info → algokit_utils-3.0.0.dist-info}/WHEEL +1 -1
- algokit_utils-2.4.0b1.dist-info/RECORD +0 -24
- {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())
|