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,1219 @@
1
+ from collections.abc import Callable
2
+ from dataclasses import dataclass
3
+ from typing import Any, Generic, TypeVar
4
+
5
+ import algosdk
6
+ import algosdk.atomic_transaction_composer
7
+ from algosdk.transaction import Transaction
8
+ from typing_extensions import Self
9
+
10
+ from algokit_utils.applications.abi import ABIReturn
11
+ from algokit_utils.applications.app_manager import AppManager
12
+ from algokit_utils.assets.asset_manager import AssetManager
13
+ from algokit_utils.config import config
14
+ from algokit_utils.models.transaction import SendParams, TransactionWrapper
15
+ from algokit_utils.transactions.transaction_composer import (
16
+ AppCallMethodCallParams,
17
+ AppCallParams,
18
+ AppCreateMethodCallParams,
19
+ AppCreateParams,
20
+ AppDeleteMethodCallParams,
21
+ AppDeleteParams,
22
+ AppUpdateMethodCallParams,
23
+ AppUpdateParams,
24
+ AssetConfigParams,
25
+ AssetCreateParams,
26
+ AssetDestroyParams,
27
+ AssetFreezeParams,
28
+ AssetOptInParams,
29
+ AssetOptOutParams,
30
+ AssetTransferParams,
31
+ OfflineKeyRegistrationParams,
32
+ OnlineKeyRegistrationParams,
33
+ PaymentParams,
34
+ SendAtomicTransactionComposerResults,
35
+ TransactionComposer,
36
+ TxnParams,
37
+ )
38
+
39
+ __all__ = [
40
+ "AlgorandClientTransactionSender",
41
+ "SendAppCreateTransactionResult",
42
+ "SendAppTransactionResult",
43
+ "SendAppUpdateTransactionResult",
44
+ "SendSingleAssetCreateTransactionResult",
45
+ "SendSingleTransactionResult",
46
+ ]
47
+
48
+ logger = config.logger
49
+
50
+
51
+ TxnParamsT = TypeVar("TxnParamsT", bound=TxnParams)
52
+
53
+
54
+ @dataclass(frozen=True, kw_only=True)
55
+ class SendSingleTransactionResult:
56
+ """Base class for transaction results.
57
+
58
+ Represents the result of sending a single transaction.
59
+ """
60
+
61
+ transaction: TransactionWrapper # Last transaction
62
+ """The last transaction"""
63
+
64
+ confirmation: algosdk.v2client.algod.AlgodResponseType # Last confirmation
65
+ """The last confirmation"""
66
+
67
+ # Fields from SendAtomicTransactionComposerResults
68
+ group_id: str
69
+ """The group ID"""
70
+
71
+ tx_id: str | None = None
72
+ """The transaction ID"""
73
+
74
+ tx_ids: list[str] # Full array of transaction IDs
75
+ """The full array of transaction IDs"""
76
+ transactions: list[TransactionWrapper]
77
+ """The full array of transactions"""
78
+
79
+ confirmations: list[algosdk.v2client.algod.AlgodResponseType]
80
+ """The full array of confirmations"""
81
+
82
+ returns: list[ABIReturn] | None = None
83
+ """The ABI return value if applicable"""
84
+
85
+ @classmethod
86
+ def from_composer_result(cls, result: SendAtomicTransactionComposerResults, index: int = -1) -> Self:
87
+ # Get base parameters
88
+ base_params = {
89
+ "transaction": result.transactions[index],
90
+ "confirmation": result.confirmations[index],
91
+ "group_id": result.group_id,
92
+ "tx_id": result.tx_ids[index],
93
+ "tx_ids": result.tx_ids,
94
+ "transactions": [result.transactions[index]],
95
+ "confirmations": result.confirmations,
96
+ "returns": result.returns,
97
+ }
98
+
99
+ # For asset creation, extract asset_id from confirmation
100
+ if cls is SendSingleAssetCreateTransactionResult:
101
+ base_params["asset_id"] = result.confirmations[index]["asset-index"] # type: ignore[call-overload]
102
+ # For app creation, extract app_id and calculate app_address
103
+ elif cls is SendAppCreateTransactionResult:
104
+ app_id = result.confirmations[index]["application-index"] # type: ignore[call-overload]
105
+ base_params.update(
106
+ {
107
+ "app_id": app_id,
108
+ "app_address": algosdk.logic.get_application_address(app_id),
109
+ "abi_return": result.returns[index] if result.returns else None, # type: ignore[dict-item]
110
+ }
111
+ )
112
+ # For regular app transactions, just add abi_return
113
+ elif cls is SendAppTransactionResult:
114
+ base_params["abi_return"] = result.returns[index] if result.returns else None # type: ignore[assignment]
115
+
116
+ return cls(**base_params) # type: ignore[arg-type]
117
+
118
+
119
+ @dataclass(frozen=True, kw_only=True)
120
+ class SendSingleAssetCreateTransactionResult(SendSingleTransactionResult):
121
+ """Result of creating a new ASA (Algorand Standard Asset).
122
+
123
+ Contains the asset ID of the newly created asset.
124
+ """
125
+
126
+ asset_id: int
127
+ """The ID of the newly created asset"""
128
+
129
+
130
+ ABIReturnT = TypeVar("ABIReturnT")
131
+
132
+
133
+ @dataclass(frozen=True)
134
+ class SendAppTransactionResult(SendSingleTransactionResult, Generic[ABIReturnT]):
135
+ """Result of an application transaction.
136
+
137
+ Contains the ABI return value if applicable.
138
+ """
139
+
140
+ abi_return: ABIReturnT | None = None
141
+ """The ABI return value if applicable"""
142
+
143
+
144
+ @dataclass(frozen=True)
145
+ class SendAppUpdateTransactionResult(SendAppTransactionResult[ABIReturnT]):
146
+ """Result of updating an application.
147
+
148
+ Contains the compiled approval and clear programs.
149
+ """
150
+
151
+ compiled_approval: Any | None = None
152
+ """The compiled approval program"""
153
+
154
+ compiled_clear: Any | None = None
155
+ """The compiled clear state program"""
156
+
157
+
158
+ @dataclass(frozen=True, kw_only=True)
159
+ class SendAppCreateTransactionResult(SendAppUpdateTransactionResult[ABIReturnT]):
160
+ """Result of creating a new application.
161
+
162
+ Contains the app ID and address of the newly created application.
163
+ """
164
+
165
+ app_id: int
166
+ """The ID of the newly created application"""
167
+
168
+ app_address: str
169
+ """The address of the newly created application"""
170
+
171
+
172
+ class AlgorandClientTransactionSender:
173
+ """Orchestrates sending transactions for AlgorandClient.
174
+
175
+ Provides methods to send various types of transactions including payments,
176
+ asset operations, and application calls.
177
+ """
178
+
179
+ def __init__(
180
+ self,
181
+ new_group: Callable[[], TransactionComposer],
182
+ asset_manager: AssetManager,
183
+ app_manager: AppManager,
184
+ algod_client: algosdk.v2client.algod.AlgodClient,
185
+ ) -> None:
186
+ self._new_group = new_group
187
+ self._asset_manager = asset_manager
188
+ self._app_manager = app_manager
189
+ self._algod = algod_client
190
+
191
+ def new_group(self) -> TransactionComposer:
192
+ """Create a new transaction group.
193
+
194
+ :return: A new TransactionComposer instance
195
+
196
+ :example:
197
+ >>> sender = AlgorandClientTransactionSender(new_group, asset_manager, app_manager, algod_client)
198
+ >>> composer = sender.new_group()
199
+ >>> composer(PaymentParams(sender="sender", receiver="receiver", amount=AlgoAmount(algo=1)))
200
+ >>> composer.send()
201
+ """
202
+ return self._new_group()
203
+
204
+ def _send(
205
+ self,
206
+ c: Callable[[TransactionComposer], Callable[[TxnParamsT], TransactionComposer]],
207
+ pre_log: Callable[[TxnParamsT, Transaction], str] | None = None,
208
+ post_log: Callable[[TxnParamsT, SendSingleTransactionResult], str] | None = None,
209
+ ) -> Callable[[TxnParamsT, SendParams | None], SendSingleTransactionResult]:
210
+ def send_transaction(params: TxnParamsT, send_params: SendParams | None = None) -> SendSingleTransactionResult:
211
+ composer = self.new_group()
212
+ c(composer)(params)
213
+
214
+ if pre_log:
215
+ transaction = composer.build().transactions[-1].txn
216
+ logger.debug(pre_log(params, transaction))
217
+
218
+ raw_result = composer.send(
219
+ send_params,
220
+ )
221
+ raw_result_dict = raw_result.__dict__.copy()
222
+ raw_result_dict["transactions"] = raw_result.transactions
223
+ del raw_result_dict["simulate_response"]
224
+
225
+ result = SendSingleTransactionResult(
226
+ **raw_result_dict,
227
+ confirmation=raw_result.confirmations[-1],
228
+ transaction=raw_result_dict["transactions"][-1],
229
+ tx_id=raw_result.tx_ids[-1],
230
+ )
231
+
232
+ if post_log:
233
+ logger.debug(post_log(params, result))
234
+
235
+ return result
236
+
237
+ return send_transaction
238
+
239
+ def _send_app_call(
240
+ self,
241
+ c: Callable[[TransactionComposer], Callable[[TxnParamsT], TransactionComposer]],
242
+ pre_log: Callable[[TxnParamsT, Transaction], str] | None = None,
243
+ post_log: Callable[[TxnParamsT, SendSingleTransactionResult], str] | None = None,
244
+ ) -> Callable[[TxnParamsT, SendParams | None], SendAppTransactionResult[ABIReturn]]:
245
+ def send_app_call(
246
+ params: TxnParamsT, send_params: SendParams | None = None
247
+ ) -> SendAppTransactionResult[ABIReturn]:
248
+ result = self._send(c, pre_log, post_log)(params, send_params)
249
+ return SendAppTransactionResult[ABIReturn](
250
+ **result.__dict__,
251
+ abi_return=AppManager.get_abi_return(result.confirmation, getattr(params, "method", None)),
252
+ )
253
+
254
+ return send_app_call
255
+
256
+ def _send_app_update_call(
257
+ self,
258
+ c: Callable[[TransactionComposer], Callable[[TxnParamsT], TransactionComposer]],
259
+ pre_log: Callable[[TxnParamsT, Transaction], str] | None = None,
260
+ post_log: Callable[[TxnParamsT, SendSingleTransactionResult], str] | None = None,
261
+ ) -> Callable[[TxnParamsT, SendParams | None], SendAppUpdateTransactionResult[ABIReturn]]:
262
+ def send_app_update_call(
263
+ params: TxnParamsT, send_params: SendParams | None = None
264
+ ) -> SendAppUpdateTransactionResult[ABIReturn]:
265
+ result = self._send_app_call(c, pre_log, post_log)(params, send_params)
266
+
267
+ if not isinstance(
268
+ params, AppCreateParams | AppUpdateParams | AppCreateMethodCallParams | AppUpdateMethodCallParams
269
+ ):
270
+ raise TypeError("Invalid parameter type")
271
+
272
+ compiled_approval = (
273
+ self._app_manager.get_compilation_result(params.approval_program)
274
+ if isinstance(params.approval_program, str)
275
+ else params.approval_program
276
+ )
277
+ compiled_clear = (
278
+ self._app_manager.get_compilation_result(params.clear_state_program)
279
+ if isinstance(params.clear_state_program, str)
280
+ else params.clear_state_program
281
+ )
282
+
283
+ return SendAppUpdateTransactionResult[ABIReturn](
284
+ **result.__dict__,
285
+ compiled_approval=compiled_approval,
286
+ compiled_clear=compiled_clear,
287
+ )
288
+
289
+ return send_app_update_call
290
+
291
+ def _send_app_create_call(
292
+ self,
293
+ c: Callable[[TransactionComposer], Callable[[TxnParamsT], TransactionComposer]],
294
+ pre_log: Callable[[TxnParamsT, Transaction], str] | None = None,
295
+ post_log: Callable[[TxnParamsT, SendSingleTransactionResult], str] | None = None,
296
+ ) -> Callable[[TxnParamsT, SendParams | None], SendAppCreateTransactionResult[ABIReturn]]:
297
+ def send_app_create_call(
298
+ params: TxnParamsT, send_params: SendParams | None = None
299
+ ) -> SendAppCreateTransactionResult[ABIReturn]:
300
+ result = self._send_app_update_call(c, pre_log, post_log)(params, send_params)
301
+ app_id = int(result.confirmation["application-index"]) # type: ignore[call-overload]
302
+
303
+ return SendAppCreateTransactionResult[ABIReturn](
304
+ **result.__dict__,
305
+ app_id=app_id,
306
+ app_address=algosdk.logic.get_application_address(app_id),
307
+ )
308
+
309
+ return send_app_create_call
310
+
311
+ def _get_method_call_for_log(self, method: algosdk.abi.Method, args: list[Any]) -> str:
312
+ """Helper function to format method call logs similar to TypeScript version"""
313
+ args_str = str([str(a) if not isinstance(a, bytes | bytearray) else a.hex() for a in args])
314
+ return f"{method.name}({args_str})"
315
+
316
+ def payment(self, params: PaymentParams, send_params: SendParams | None = None) -> SendSingleTransactionResult:
317
+ """Send a payment transaction to transfer Algo between accounts.
318
+
319
+ :param params: Payment transaction parameters
320
+ :param send_params: Send parameters
321
+ :return: Result of the payment transaction
322
+
323
+ :example:
324
+ >>> result = algorand.send.payment(PaymentParams(
325
+ >>> sender="SENDERADDRESS",
326
+ >>> receiver="RECEIVERADDRESS",
327
+ >>> amount=AlgoAmount(algo=4),
328
+ >>> ))
329
+
330
+ >>> # Advanced example
331
+ >>> result = algorand.send.payment(PaymentParams(
332
+ >>> amount=AlgoAmount(algo=4),
333
+ >>> receiver="RECEIVERADDRESS",
334
+ >>> sender="SENDERADDRESS",
335
+ >>> close_remainder_to="CLOSEREMAINDERTOADDRESS",
336
+ >>> lease="lease",
337
+ >>> note="note",
338
+ >>> rekey_to="REKEYTOADDRESS",
339
+ >>> first_valid_round=1000,
340
+ >>> validity_window=10,
341
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
342
+ >>> static_fee=AlgoAmount(micro_algo=1000),
343
+ >>> max_fee=AlgoAmount(micro_algo=3000),
344
+ >>> signer=transactionSigner
345
+ >>> ), send_params=SendParams(
346
+ >>> max_rounds_to_wait_for_confirmation=5,
347
+ >>> suppress_log=True,
348
+ >>> ))
349
+ """
350
+ return self._send(
351
+ lambda c: c.add_payment,
352
+ pre_log=lambda params, transaction: (
353
+ f"Sending {params.amount} from {params.sender} to {params.receiver} "
354
+ f"via transaction {transaction.get_txid()}"
355
+ ),
356
+ )(params, send_params)
357
+
358
+ def asset_create(
359
+ self, params: AssetCreateParams, send_params: SendParams | None = None
360
+ ) -> SendSingleAssetCreateTransactionResult:
361
+ """Create a new Algorand Standard Asset.
362
+
363
+ :param params: Asset creation parameters
364
+ :param send_params: Send parameters
365
+ :return: Result containing the new asset ID
366
+
367
+ :example:
368
+ >>> result = algorand.send.asset_create(AssetCreateParams(
369
+ >>> sender="SENDERADDRESS",
370
+ >>> asset_name="ASSETNAME",
371
+ >>> unit_name="UNITNAME",
372
+ >>> total=1000,
373
+ >>> ))
374
+
375
+ >>> # Advanced example
376
+ >>> result = algorand.send.asset_create(AssetCreateParams(
377
+ >>> sender="CREATORADDRESS",
378
+ >>> total=100,
379
+ >>> decimals=2,
380
+ >>> asset_name="asset",
381
+ >>> unit_name="unit",
382
+ >>> url="url",
383
+ >>> metadata_hash="metadataHash",
384
+ >>> default_frozen=False,
385
+ >>> manager="MANAGERADDRESS",
386
+ >>> reserve="RESERVEADDRESS",
387
+ >>> freeze="FREEZEADDRESS",
388
+ >>> clawback="CLAWBACKADDRESS",
389
+ >>> lease="lease",
390
+ >>> note="note",
391
+ >>> # You wouldn't normally set this field
392
+ >>> first_valid_round=1000,
393
+ >>> validity_window=10,
394
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
395
+ >>> static_fee=AlgoAmount(micro_algo=1000),
396
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
397
+ >>> # already specified, but here for completeness
398
+ >>> max_fee=AlgoAmount(micro_algo=3000),
399
+ >>> # Signer only needed if you want to provide one,
400
+ >>> # generally you'd register it with AlgorandClient
401
+ >>> # against the sender and not need to pass it in
402
+ >>> signer=transactionSigner
403
+ >>> ), send_params=SendParams(
404
+ >>> max_rounds_to_wait_for_confirmation=5,
405
+ >>> suppress_log=True,
406
+ >>> ))
407
+ """
408
+ result = self._send(
409
+ lambda c: c.add_asset_create,
410
+ post_log=lambda params, result: (
411
+ f"Created asset{f' {params.asset_name}' if hasattr(params, 'asset_name') else ''}"
412
+ f"{f' ({params.unit_name})' if hasattr(params, 'unit_name') else ''} with "
413
+ f"{params.total} units and {getattr(params, 'decimals', 0)} decimals created by "
414
+ f"{params.sender} with ID {result.confirmation['asset-index']} via transaction " # type: ignore[call-overload]
415
+ f"{result.tx_ids[-1]}"
416
+ ),
417
+ )(params, send_params)
418
+
419
+ return SendSingleAssetCreateTransactionResult(
420
+ **result.__dict__,
421
+ asset_id=int(result.confirmation["asset-index"]), # type: ignore[call-overload]
422
+ )
423
+
424
+ def asset_config(
425
+ self, params: AssetConfigParams, send_params: SendParams | None = None
426
+ ) -> SendSingleTransactionResult:
427
+ """Configure an existing Algorand Standard Asset.
428
+
429
+ :param params: Asset configuration parameters
430
+ :param send_params: Send parameters
431
+ :return: Result of the configuration transaction
432
+
433
+ :example:
434
+ >>> result = algorand.send.asset_config(AssetConfigParams(
435
+ >>> sender="MANAGERADDRESS",
436
+ >>> asset_id=123456,
437
+ >>> manager="MANAGERADDRESS",
438
+ >>> reserve="RESERVEADDRESS",
439
+ >>> freeze="FREEZEADDRESS",
440
+ >>> clawback="CLAWBACKADDRESS",
441
+ >>> lease="lease",
442
+ >>> note="note",
443
+ >>> # You wouldn't normally set this field
444
+ >>> first_valid_round=1000,
445
+ >>> validity_window=10,
446
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
447
+ >>> static_fee=AlgoAmount(micro_algo=1000),
448
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
449
+ >>> # already specified, but here for completeness
450
+ >>> max_fee=AlgoAmount(micro_algo=3000),
451
+ >>> # Signer only needed if you want to provide one,
452
+ >>> # generally you'd register it with AlgorandClient
453
+ >>> # against the sender and not need to pass it in
454
+ >>> signer=transactionSigner
455
+ >>> ), send_params=SendParams(
456
+ >>> max_rounds_to_wait_for_confirmation=5,
457
+ >>> suppress_log=True,
458
+ >>> ))
459
+ """
460
+ return self._send(
461
+ lambda c: c.add_asset_config,
462
+ pre_log=lambda params, transaction: (
463
+ f"Configuring asset with ID {params.asset_id} via transaction {transaction.get_txid()}"
464
+ ),
465
+ )(params, send_params)
466
+
467
+ def asset_freeze(
468
+ self, params: AssetFreezeParams, send_params: SendParams | None = None
469
+ ) -> SendSingleTransactionResult:
470
+ """Freeze or unfreeze an Algorand Standard Asset for an account.
471
+
472
+ :param params: Asset freeze parameters
473
+ :param send_params: Send parameters
474
+ :return: Result of the freeze transaction
475
+
476
+ :example:
477
+ >>> result = algorand.send.asset_freeze(AssetFreezeParams(
478
+ >>> sender="MANAGERADDRESS",
479
+ >>> asset_id=123456,
480
+ >>> account="ACCOUNTADDRESS",
481
+ >>> frozen=True,
482
+ >>> ))
483
+
484
+ >>> # Advanced example
485
+ >>> result = algorand.send.asset_freeze(AssetFreezeParams(
486
+ >>> sender="MANAGERADDRESS",
487
+ >>> asset_id=123456,
488
+ >>> account="ACCOUNTADDRESS",
489
+ >>> frozen=True,
490
+ >>> lease="lease",
491
+ >>> note="note",
492
+ >>> # You wouldn't normally set this field
493
+ >>> first_valid_round=1000,
494
+ >>> validity_window=10,
495
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
496
+ >>> static_fee=AlgoAmount(micro_algo=1000),
497
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
498
+ >>> # already specified, but here for completeness
499
+ >>> max_fee=AlgoAmount(micro_algo=3000),
500
+ >>> # Signer only needed if you want to provide one,
501
+ >>> # generally you'd register it with AlgorandClient
502
+ >>> # against the sender and not need to pass it in
503
+ >>> signer=transactionSigner
504
+ >>> ), send_params=SendParams(
505
+ >>> max_rounds_to_wait_for_confirmation=5,
506
+ >>> suppress_log=True,
507
+ >>> ))
508
+ """
509
+ return self._send(
510
+ lambda c: c.add_asset_freeze,
511
+ pre_log=lambda params, transaction: (
512
+ f"Freezing asset with ID {params.asset_id} via transaction {transaction.get_txid()}"
513
+ ),
514
+ )(params, send_params)
515
+
516
+ def asset_destroy(
517
+ self, params: AssetDestroyParams, send_params: SendParams | None = None
518
+ ) -> SendSingleTransactionResult:
519
+ """Destroys an Algorand Standard Asset.
520
+
521
+ :param params: Asset destruction parameters
522
+ :param send_params: Send parameters
523
+ :return: Result of the destroy transaction
524
+
525
+ :example:
526
+ >>> result = algorand.send.asset_destroy(AssetDestroyParams(
527
+ >>> sender="MANAGERADDRESS",
528
+ >>> asset_id=123456,
529
+ >>> ))
530
+
531
+ >>> # Advanced example
532
+ >>> result = algorand.send.asset_destroy(AssetDestroyParams(
533
+ >>> sender="MANAGERADDRESS",
534
+ >>> asset_id=123456,
535
+ >>> lease="lease",
536
+ >>> note="note",
537
+ >>> # You wouldn't normally set this field
538
+ >>> first_valid_round=1000,
539
+ >>> validity_window=10,
540
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
541
+ >>> static_fee=AlgoAmount(micro_algo=1000),
542
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
543
+ >>> # already specified, but here for completeness
544
+ >>> max_fee=AlgoAmount(micro_algo=3000),
545
+ >>> # Signer only needed if you want to provide one,
546
+ >>> # generally you'd register it with AlgorandClient
547
+ >>> # against the sender and not need to pass it in
548
+ >>> signer=transactionSigner
549
+ >>> ), send_params=SendParams(
550
+ >>> max_rounds_to_wait_for_confirmation=5,
551
+ >>> suppress_log=True,
552
+ >>> ))
553
+ """
554
+ return self._send(
555
+ lambda c: c.add_asset_destroy,
556
+ pre_log=lambda params, transaction: (
557
+ f"Destroying asset with ID {params.asset_id} via transaction {transaction.get_txid()}"
558
+ ),
559
+ )(params, send_params)
560
+
561
+ def asset_transfer(
562
+ self, params: AssetTransferParams, send_params: SendParams | None = None
563
+ ) -> SendSingleTransactionResult:
564
+ """Transfer an Algorand Standard Asset.
565
+
566
+ :param params: Asset transfer parameters
567
+ :param send_params: Send parameters
568
+ :return: Result of the transfer transaction
569
+
570
+ :example:
571
+ >>> result = algorand.send.asset_transfer(AssetTransferParams(
572
+ >>> sender="HOLDERADDRESS",
573
+ >>> asset_id=123456,
574
+ >>> amount=1,
575
+ >>> receiver="RECEIVERADDRESS",
576
+ >>> ))
577
+
578
+ >>> # Advanced example (with clawback)
579
+ >>> result = algorand.send.asset_transfer(AssetTransferParams(
580
+ >>> sender="CLAWBACKADDRESS",
581
+ >>> asset_id=123456,
582
+ >>> amount=1,
583
+ >>> receiver="RECEIVERADDRESS",
584
+ >>> clawback_target="HOLDERADDRESS",
585
+ >>> # This field needs to be used with caution
586
+ >>> close_asset_to="ADDRESSTOCLOSETO",
587
+ >>> lease="lease",
588
+ >>> note="note",
589
+ >>> # You wouldn't normally set this field
590
+ >>> first_valid_round=1000,
591
+ >>> validity_window=10,
592
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
593
+ >>> static_fee=AlgoAmount(micro_algo=1000),
594
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
595
+ >>> # already specified, but here for completeness
596
+ >>> max_fee=AlgoAmount(micro_algo=3000),
597
+ >>> # Signer only needed if you want to provide one,
598
+ >>> # generally you'd register it with AlgorandClient
599
+ >>> # against the sender and not need to pass it in
600
+ >>> signer=transactionSigner
601
+ >>> ), send_params=SendParams(
602
+ >>> max_rounds_to_wait_for_confirmation=5,
603
+ >>> suppress_log=True,
604
+ >>> ))
605
+ """
606
+ return self._send(
607
+ lambda c: c.add_asset_transfer,
608
+ pre_log=lambda params, transaction: (
609
+ f"Transferring {params.amount} units of asset with ID {params.asset_id} from "
610
+ f"{params.sender} to {params.receiver} via transaction {transaction.get_txid()}"
611
+ ),
612
+ )(params, send_params)
613
+
614
+ def asset_opt_in(
615
+ self, params: AssetOptInParams, send_params: SendParams | None = None
616
+ ) -> SendSingleTransactionResult:
617
+ """Opt an account into an Algorand Standard Asset.
618
+
619
+ :param params: Asset opt-in parameters
620
+ :param send_params: Send parameters
621
+ :return: Result of the opt-in transaction
622
+
623
+ :example:
624
+ >>> result = algorand.send.asset_opt_in(AssetOptInParams(
625
+ >>> sender="SENDERADDRESS",
626
+ >>> asset_id=123456,
627
+ >>> ))
628
+
629
+ >>> # Advanced example
630
+ >>> result = algorand.send.asset_opt_in(AssetOptInParams(
631
+ >>> sender="SENDERADDRESS",
632
+ >>> asset_id=123456,
633
+ >>> lease="lease",
634
+ >>> note="note",
635
+ >>> # You wouldn't normally set this field
636
+ >>> first_valid_round=1000,
637
+ >>> validity_window=10,
638
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
639
+ >>> static_fee=AlgoAmount(micro_algo=1000),
640
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
641
+ >>> # already specified, but here for completeness
642
+ >>> max_fee=AlgoAmount(micro_algo=3000),
643
+ >>> # Signer only needed if you want to provide one,
644
+ >>> # generally you'd register it with AlgorandClient
645
+ >>> # against the sender and not need to pass it in
646
+ >>> signer=transactionSigner
647
+ >>> ), send_params=SendParams(
648
+ >>> max_rounds_to_wait_for_confirmation=5,
649
+ >>> suppress_log=True,
650
+ >>> ))
651
+ """
652
+ return self._send(
653
+ lambda c: c.add_asset_opt_in,
654
+ pre_log=lambda params, transaction: (
655
+ f"Opting in {params.sender} to asset with ID {params.asset_id} via transaction "
656
+ f"{transaction.get_txid()}"
657
+ ),
658
+ )(params, send_params)
659
+
660
+ def asset_opt_out(
661
+ self,
662
+ *,
663
+ params: AssetOptOutParams,
664
+ send_params: SendParams | None = None,
665
+ ensure_zero_balance: bool = True,
666
+ ) -> SendSingleTransactionResult:
667
+ """Opt an account out of an Algorand Standard Asset.
668
+
669
+ :param params: Asset opt-out parameters
670
+ :param send_params: Send parameters
671
+ :param ensure_zero_balance: Check if account has zero balance before opt-out, defaults to True
672
+ :raises ValueError: If account has non-zero balance or is not opted in
673
+ :return: Result of the opt-out transaction
674
+
675
+ :example:
676
+ >>> result = algorand.send.asset_opt_out(AssetOptOutParams(
677
+ >>> sender="SENDERADDRESS",
678
+ >>> creator="CREATORADDRESS",
679
+ >>> asset_id=123456,
680
+ >>> ensure_zero_balance=True,
681
+ >>> ))
682
+
683
+ >>> # Advanced example
684
+ >>> result = algorand.send.asset_opt_out(AssetOptOutParams(
685
+ >>> sender="SENDERADDRESS",
686
+ >>> asset_id=123456,
687
+ >>> creator="CREATORADDRESS",
688
+ >>> ensure_zero_balance=True,
689
+ >>> lease="lease",
690
+ >>> note="note",
691
+ >>> # You wouldn't normally set this field
692
+ >>> first_valid_round=1000,
693
+ >>> validity_window=10,
694
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
695
+ >>> static_fee=AlgoAmount(micro_algo=1000),
696
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
697
+ >>> # already specified, but here for completeness
698
+ >>> max_fee=AlgoAmount(micro_algo=3000),
699
+ >>> # Signer only needed if you want to provide one,
700
+ >>> # generally you'd register it with AlgorandClient
701
+ >>> # against the sender and not need to pass it in
702
+ >>> signer=transactionSigner
703
+ >>> ), send_params=SendParams(
704
+ >>> max_rounds_to_wait_for_confirmation=5,
705
+ >>> suppress_log=True,
706
+ >>> ))
707
+ """
708
+ if ensure_zero_balance:
709
+ try:
710
+ account_asset_info = self._asset_manager.get_account_information(params.sender, params.asset_id)
711
+ balance = account_asset_info.balance
712
+ if balance != 0:
713
+ raise ValueError(
714
+ f"Account {params.sender} does not have a zero balance for Asset "
715
+ f"{params.asset_id}; can't opt-out."
716
+ )
717
+ except Exception as e:
718
+ raise ValueError(
719
+ f"Account {params.sender} is not opted-in to Asset {params.asset_id}; " "can't opt-out."
720
+ ) from e
721
+
722
+ if not hasattr(params, "creator"):
723
+ asset_info = self._asset_manager.get_by_id(params.asset_id)
724
+ params = AssetOptOutParams(
725
+ **params.__dict__,
726
+ creator=asset_info.creator,
727
+ )
728
+
729
+ creator = params.__dict__.get("creator")
730
+ return self._send(
731
+ lambda c: c.add_asset_opt_out,
732
+ pre_log=lambda params, transaction: (
733
+ f"Opting {params.sender} out of asset with ID {params.asset_id} to creator "
734
+ f"{creator} via transaction {transaction.get_txid()}"
735
+ ),
736
+ )(params, send_params)
737
+
738
+ def app_create(
739
+ self, params: AppCreateParams, send_params: SendParams | None = None
740
+ ) -> SendAppCreateTransactionResult[ABIReturn]:
741
+ """Create a new application.
742
+
743
+ :param params: Application creation parameters
744
+ :param send_params: Send parameters
745
+ :return: Result containing the new application ID and address
746
+
747
+ :example:
748
+ >>> result = algorand.send.app_create(AppCreateParams(
749
+ >>> sender="CREATORADDRESS",
750
+ >>> approval_program="TEALCODE",
751
+ >>> clear_state_program="TEALCODE",
752
+ >>> ))
753
+
754
+ >>> # Advanced example
755
+ >>> result = algorand.send.app_create(AppCreateParams(
756
+ >>> sender="CREATORADDRESS",
757
+ >>> approval_program="TEALCODE",
758
+ >>> clear_state_program="TEALCODE",
759
+ >>> ))
760
+ >>> # algorand.send.appCreate(AppCreateParams(
761
+ >>> # sender='CREATORADDRESS',
762
+ >>> # approval_program="TEALCODE",
763
+ >>> # clear_state_program="TEALCODE",
764
+ >>> # schema={
765
+ >>> # "global_ints": 1,
766
+ >>> # "global_byte_slices": 2,
767
+ >>> # "local_ints": 3,
768
+ >>> # "local_byte_slices": 4
769
+ >>> # },
770
+ >>> # extra_program_pages: 1,
771
+ >>> # on_complete: algosdk.transaction.OnComplete.OptInOC,
772
+ >>> # args: [b'some_bytes']
773
+ >>> # account_references: ["ACCOUNT_1"]
774
+ >>> # app_references: [123, 1234]
775
+ >>> # asset_references: [12345]
776
+ >>> # box_references: ["box1", {app_id: 1234, name: "box2"}]
777
+ >>> # lease: 'lease',
778
+ >>> # note: 'note',
779
+ >>> # # You wouldn't normally set this field
780
+ >>> # first_valid_round: 1000,
781
+ >>> # validity_window: 10,
782
+ >>> # extra_fee: AlgoAmount(micro_algo=1000),
783
+ >>> # static_fee: AlgoAmount(micro_algo=1000),
784
+ >>> # # Max fee doesn't make sense with extraFee AND staticFee
785
+ >>> # # already specified, but here for completeness
786
+ >>> # max_fee: AlgoAmount(micro_algo=3000),
787
+ >>> # # Signer only needed if you want to provide one,
788
+ >>> # # generally you'd register it with AlgorandClient
789
+ >>> # # against the sender and not need to pass it in
790
+ >>> # signer: transactionSigner
791
+ >>> #}, send_params=SendParams(
792
+ >>> # max_rounds_to_wait_for_confirmation=5,
793
+ >>> # suppress_log=True,
794
+ >>> #))
795
+ """
796
+ return self._send_app_create_call(lambda c: c.add_app_create)(params, send_params)
797
+
798
+ def app_update(
799
+ self, params: AppUpdateParams, send_params: SendParams | None = None
800
+ ) -> SendAppUpdateTransactionResult[ABIReturn]:
801
+ """Update an application.
802
+
803
+ :param params: Application update parameters
804
+ :param send_params: Send parameters
805
+ :return: Result containing the compiled programs
806
+
807
+ :example:
808
+ >>> # Basic example
809
+ >>> algorand.send.app_update(AppUpdateParams(
810
+ >>> sender="CREATORADDRESS",
811
+ >>> approval_program="TEALCODE",
812
+ >>> clear_state_program="TEALCODE",
813
+ >>> ))
814
+ >>> # Advanced example
815
+ >>> algorand.send.app_update(AppUpdateParams(
816
+ >>> sender="CREATORADDRESS",
817
+ >>> approval_program="TEALCODE",
818
+ >>> clear_state_program="TEALCODE",
819
+ >>> on_complete=OnComplete.UpdateApplicationOC,
820
+ >>> args=[b'some_bytes'],
821
+ >>> account_references=["ACCOUNT_1"],
822
+ >>> app_references=[123, 1234],
823
+ >>> asset_references=[12345],
824
+ >>> box_references=[...],
825
+ >>> lease="lease",
826
+ >>> note="note",
827
+ >>> # You wouldn't normally set this field
828
+ >>> first_valid_round=1000,
829
+ >>> validity_window=10,
830
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
831
+ >>> static_fee=AlgoAmount(micro_algo=1000),
832
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
833
+ >>> # already specified, but here for completeness
834
+ >>> max_fee=AlgoAmount(micro_algo=3000),
835
+ >>> # Signer only needed if you want to provide one,
836
+ >>> # generally you'd register it with AlgorandClient
837
+ >>> # against the sender and not need to pass it in
838
+ >>> signer=transactionSigner
839
+ >>> ), send_params=SendParams(
840
+ >>> max_rounds_to_wait_for_confirmation=5,
841
+ >>> suppress_log=True,
842
+ >>> ))
843
+ """
844
+ return self._send_app_update_call(lambda c: c.add_app_update)(params, send_params)
845
+
846
+ def app_delete(
847
+ self, params: AppDeleteParams, send_params: SendParams | None = None
848
+ ) -> SendAppTransactionResult[ABIReturn]:
849
+ """Delete an application.
850
+
851
+ :param params: Application deletion parameters
852
+ :param send_params: Send parameters
853
+ :return: Result of the deletion transaction
854
+
855
+ :example:
856
+ >>> # Basic example
857
+ >>> algorand.send.app_delete(AppDeleteParams(
858
+ >>> sender="CREATORADDRESS",
859
+ >>> app_id=123456,
860
+ >>> ))
861
+ >>> # Advanced example
862
+ >>> algorand.send.app_delete(AppDeleteParams(
863
+ >>> sender="CREATORADDRESS",
864
+ >>> on_complete=OnComplete.DeleteApplicationOC,
865
+ >>> args=[b'some_bytes'],
866
+ >>> account_references=["ACCOUNT_1"],
867
+ >>> app_references=[123, 1234],
868
+ >>> asset_references=[12345],
869
+ >>> box_references=[...],
870
+ >>> lease="lease",
871
+ >>> note="note",
872
+ >>> # You wouldn't normally set this field
873
+ >>> first_valid_round=1000,
874
+ >>> validity_window=10,
875
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
876
+ >>> static_fee=AlgoAmount(micro_algo=1000),
877
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
878
+ >>> # already specified, but here for completeness
879
+ >>> max_fee=AlgoAmount(micro_algo=3000),
880
+ >>> # Signer only needed if you want to provide one,
881
+ >>> # generally you'd register it with AlgorandClient
882
+ >>> # against the sender and not need to pass it in
883
+ >>> signer=transactionSigner,
884
+ >>> ), send_params=SendParams(
885
+ >>> max_rounds_to_wait_for_confirmation=5,
886
+ >>> suppress_log=True,
887
+ >>> ))
888
+ """
889
+ return self._send_app_call(lambda c: c.add_app_delete)(params, send_params)
890
+
891
+ def app_call(
892
+ self, params: AppCallParams, send_params: SendParams | None = None
893
+ ) -> SendAppTransactionResult[ABIReturn]:
894
+ """Call an application.
895
+
896
+ :param params: Application call parameters
897
+ :param send_params: Send parameters
898
+ :return: Result containing any ABI return value
899
+
900
+ :example:
901
+ >>> # Basic example
902
+ >>> algorand.send.app_call(AppCallParams(
903
+ >>> sender="CREATORADDRESS",
904
+ >>> app_id=123456,
905
+ >>> ))
906
+ >>> # Advanced example
907
+ >>> algorand.send.app_call(AppCallParams(
908
+ >>> sender="CREATORADDRESS",
909
+ >>> on_complete=OnComplete.OptInOC,
910
+ >>> args=[b'some_bytes'],
911
+ >>> account_references=["ACCOUNT_1"],
912
+ >>> app_references=[123, 1234],
913
+ >>> asset_references=[12345],
914
+ >>> box_references=[...],
915
+ >>> lease="lease",
916
+ >>> note="note",
917
+ >>> # You wouldn't normally set this field
918
+ >>> first_valid_round=1000,
919
+ >>> validity_window=10,
920
+ >>> extra_fee=AlgoAmount(micro_algo=1000),
921
+ >>> static_fee=AlgoAmount(micro_algo=1000),
922
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
923
+ >>> # already specified, but here for completeness
924
+ >>> max_fee=AlgoAmount(micro_algo=3000),
925
+ >>> # Signer only needed if you want to provide one,
926
+ >>> # generally you'd register it with AlgorandClient
927
+ >>> # against the sender and not need to pass it in
928
+ >>> signer=transactionSigner,
929
+ >>> ), send_params=SendParams(
930
+ >>> max_rounds_to_wait_for_confirmation=5,
931
+ >>> suppress_log=True,
932
+ >>> ))
933
+ """
934
+ return self._send_app_call(lambda c: c.add_app_call)(params, send_params)
935
+
936
+ def app_create_method_call(
937
+ self, params: AppCreateMethodCallParams, send_params: SendParams | None = None
938
+ ) -> SendAppCreateTransactionResult[ABIReturn]:
939
+ """Call an application's create method.
940
+
941
+ :param params: Method call parameters for application creation
942
+ :param send_params: Send parameters
943
+ :return: Result containing the new application ID and address
944
+
945
+ :example:
946
+ >>> # Note: you may prefer to use `algorand.client` to get an app client for more advanced functionality.
947
+ >>> #
948
+ >>> # @param params The parameters for the app creation transaction
949
+ >>> # Basic example
950
+ >>> method = algorand.abi.Method(
951
+ >>> name='method',
952
+ >>> args=[b'arg1'],
953
+ >>> returns='string'
954
+ >>> )
955
+ >>> result = algorand.send.app_create_method_call({ sender: 'CREATORADDRESS',
956
+ >>> approval_program: 'TEALCODE',
957
+ >>> clear_state_program: 'TEALCODE',
958
+ >>> method: method,
959
+ >>> args: ["arg1_value"] })
960
+ >>> created_app_id = result.app_id
961
+ >>> ...
962
+ >>> # Advanced example
963
+ >>> method = algorand.abi.Method(
964
+ >>> name='method',
965
+ >>> args=[b'arg1'],
966
+ >>> returns='string'
967
+ >>> )
968
+ >>> result = algorand.send.app_create_method_call({
969
+ >>> sender: 'CREATORADDRESS',
970
+ >>> method: method,
971
+ >>> args: ["arg1_value"],
972
+ >>> approval_program: "TEALCODE",
973
+ >>> clear_state_program: "TEALCODE",
974
+ >>> schema: {
975
+ >>> "global_ints": 1,
976
+ >>> "global_byte_slices": 2,
977
+ >>> "local_ints": 3,
978
+ >>> "local_byte_slices": 4
979
+ >>> },
980
+ >>> extra_program_pages: 1,
981
+ >>> on_complete: algosdk.transaction.OnComplete.OptInOC,
982
+ >>> args: [new Uint8Array(1, 2, 3, 4)],
983
+ >>> account_references: ["ACCOUNT_1"],
984
+ >>> app_references: [123, 1234],
985
+ >>> asset_references: [12345],
986
+ >>> box_references: [...],
987
+ >>> lease: 'lease',
988
+ >>> note: 'note',
989
+ >>> # You wouldn't normally set this field
990
+ >>> first_valid_round: 1000,
991
+ >>> validity_window: 10,
992
+ >>> extra_fee: AlgoAmount(micro_algo=1000),
993
+ >>> static_fee: AlgoAmount(micro_algo=1000),
994
+ >>> # Max fee doesn't make sense with extraFee AND staticFee
995
+ >>> # already specified, but here for completeness
996
+ >>> max_fee: AlgoAmount(micro_algo=3000),
997
+ >>> # Signer only needed if you want to provide one,
998
+ >>> # generally you'd register it with AlgorandClient
999
+ >>> # against the sender and not need to pass it in
1000
+ >>> signer: transactionSigner,
1001
+ >>> }, send_params=SendParams(
1002
+ >>> max_rounds_to_wait_for_confirmation=5,
1003
+ >>> suppress_log=True,
1004
+ >>> ))
1005
+ """
1006
+ return self._send_app_create_call(lambda c: c.add_app_create_method_call)(params, send_params)
1007
+
1008
+ def app_update_method_call(
1009
+ self, params: AppUpdateMethodCallParams, send_params: SendParams | None = None
1010
+ ) -> SendAppUpdateTransactionResult[ABIReturn]:
1011
+ """Call an application's update method.
1012
+
1013
+ :param params: Method call parameters for application update
1014
+ :param send_params: Send parameters
1015
+ :return: Result containing the compiled programs
1016
+
1017
+ :example:
1018
+ # Basic example:
1019
+ >>> method = algorand.abi.Method(
1020
+ ... name="updateMethod",
1021
+ ... args=[{"type": "string", "name": "arg1"}],
1022
+ ... returns="string"
1023
+ ... )
1024
+ >>> params = AppUpdateMethodCallParams(
1025
+ ... sender="CREATORADDRESS",
1026
+ ... app_id=123,
1027
+ ... method=method,
1028
+ ... args=["new_value"],
1029
+ ... approval_program="TEALCODE",
1030
+ ... clear_state_program="TEALCODE"
1031
+ ... )
1032
+ >>> result = algorand.send.app_update_method_call(params)
1033
+ >>> print(result.compiled_approval, result.compiled_clear)
1034
+
1035
+ # Advanced example:
1036
+ >>> method = algorand.abi.Method(
1037
+ ... name="updateMethod",
1038
+ ... args=[{"type": "string", "name": "arg1"}, {"type": "uint64", "name": "arg2"}],
1039
+ ... returns="string"
1040
+ ... )
1041
+ >>> params = AppUpdateMethodCallParams(
1042
+ ... sender="CREATORADDRESS",
1043
+ ... app_id=456,
1044
+ ... method=method,
1045
+ ... args=["new_value", 42],
1046
+ ... approval_program="TEALCODE_ADVANCED",
1047
+ ... clear_state_program="TEALCLEAR_ADVANCED",
1048
+ ... account_references=["ACCOUNT1", "ACCOUNT2"],
1049
+ ... app_references=[789],
1050
+ ... asset_references=[101112]
1051
+ ... )
1052
+ >>> result = algorand.send.app_update_method_call(params)
1053
+ >>> print(result.compiled_approval, result.compiled_clear)
1054
+ """
1055
+ return self._send_app_update_call(lambda c: c.add_app_update_method_call)(params, send_params)
1056
+
1057
+ def app_delete_method_call(
1058
+ self, params: AppDeleteMethodCallParams, send_params: SendParams | None = None
1059
+ ) -> SendAppTransactionResult[ABIReturn]:
1060
+ """Call an application's delete method.
1061
+
1062
+ :param params: Method call parameters for application deletion
1063
+ :param send_params: Send parameters
1064
+ :return: Result of the deletion transaction
1065
+
1066
+ :example:
1067
+ # Basic example:
1068
+ >>> method = algorand.abi.Method(
1069
+ ... name="deleteMethod",
1070
+ ... args=[],
1071
+ ... returns="void"
1072
+ ... )
1073
+ >>> params = AppDeleteMethodCallParams(
1074
+ ... sender="CREATORADDRESS",
1075
+ ... app_id=123,
1076
+ ... method=method
1077
+ ... )
1078
+ >>> result = algorand.send.app_delete_method_call(params)
1079
+ >>> print(result.tx_id)
1080
+
1081
+ # Advanced example:
1082
+ >>> method = algorand.abi.Method(
1083
+ ... name="deleteMethod",
1084
+ ... args=[{"type": "uint64", "name": "confirmation"}],
1085
+ ... returns="void"
1086
+ ... )
1087
+ >>> params = AppDeleteMethodCallParams(
1088
+ ... sender="CREATORADDRESS",
1089
+ ... app_id=123,
1090
+ ... method=method,
1091
+ ... args=[1],
1092
+ ... account_references=["ACCOUNT1"],
1093
+ ... app_references=[456]
1094
+ ... )
1095
+ >>> result = algorand.send.app_delete_method_call(params)
1096
+ >>> print(result.tx_id)
1097
+ """
1098
+ return self._send_app_call(lambda c: c.add_app_delete_method_call)(params, send_params)
1099
+
1100
+ def app_call_method_call(
1101
+ self, params: AppCallMethodCallParams, send_params: SendParams | None = None
1102
+ ) -> SendAppTransactionResult[ABIReturn]:
1103
+ """Call an application's call method.
1104
+
1105
+ :param params: Method call parameters
1106
+ :param send_params: Send parameters
1107
+ :return: Result containing any ABI return value
1108
+
1109
+ :example:
1110
+ # Basic example:
1111
+ >>> method = algorand.abi.Method(
1112
+ ... name="callMethod",
1113
+ ... args=[{"type": "uint64", "name": "arg1"}],
1114
+ ... returns="uint64"
1115
+ ... )
1116
+ >>> params = AppCallMethodCallParams(
1117
+ ... sender="CALLERADDRESS",
1118
+ ... app_id=123,
1119
+ ... method=method,
1120
+ ... args=[12345]
1121
+ ... )
1122
+ >>> result = algorand.send.app_call_method_call(params)
1123
+ >>> print(result.abi_return)
1124
+
1125
+ # Advanced example:
1126
+ >>> method = algorand.abi.Method(
1127
+ ... name="callMethod",
1128
+ ... args=[{"type": "uint64", "name": "arg1"}, {"type": "string", "name": "arg2"}],
1129
+ ... returns="uint64"
1130
+ ... )
1131
+ >>> params = AppCallMethodCallParams(
1132
+ ... sender="CALLERADDRESS",
1133
+ ... app_id=123,
1134
+ ... method=method,
1135
+ ... args=[12345, "extra"],
1136
+ ... account_references=["ACCOUNT1"],
1137
+ ... asset_references=[101112],
1138
+ ... app_references=[789]
1139
+ ... )
1140
+ >>> result = algorand.send.app_call_method_call(params)
1141
+ >>> print(result.abi_return)
1142
+ """
1143
+ return self._send_app_call(lambda c: c.add_app_call_method_call)(params, send_params)
1144
+
1145
+ def online_key_registration(
1146
+ self, params: OnlineKeyRegistrationParams, send_params: SendParams | None = None
1147
+ ) -> SendSingleTransactionResult:
1148
+ """Register an online key.
1149
+
1150
+ :param params: Key registration parameters
1151
+ :param send_params: Send parameters
1152
+ :return: Result of the registration transaction
1153
+
1154
+ :example:
1155
+ # Basic example:
1156
+ >>> params = OnlineKeyRegistrationParams(
1157
+ ... sender="ACCOUNTADDRESS",
1158
+ ... vote_key="VOTEKEY",
1159
+ ... selection_key="SELECTIONKEY",
1160
+ ... vote_first=1000,
1161
+ ... vote_last=2000,
1162
+ ... vote_key_dilution=10
1163
+ ... )
1164
+ >>> result = algorand.send.online_key_registration(params)
1165
+ >>> print(result.tx_id)
1166
+
1167
+ # Advanced example:
1168
+ >>> params = OnlineKeyRegistrationParams(
1169
+ ... sender="ACCOUNTADDRESS",
1170
+ ... vote_key="VOTEKEY",
1171
+ ... selection_key="SELECTIONKEY",
1172
+ ... vote_first=1000,
1173
+ ... vote_last=2100,
1174
+ ... vote_key_dilution=10,
1175
+ ... state_proof_key=b'\x01' * 64
1176
+ ... )
1177
+ >>> result = algorand.send.online_key_registration(params)
1178
+ >>> print(result.tx_id)
1179
+ """
1180
+ return self._send(
1181
+ lambda c: c.add_online_key_registration,
1182
+ pre_log=lambda params, transaction: (
1183
+ f"Registering online key for {params.sender} via transaction {transaction.get_txid()}"
1184
+ ),
1185
+ )(params, send_params)
1186
+
1187
+ def offline_key_registration(
1188
+ self, params: OfflineKeyRegistrationParams, send_params: SendParams | None = None
1189
+ ) -> SendSingleTransactionResult:
1190
+ """Register an offline key.
1191
+
1192
+ :param params: Key registration parameters
1193
+ :param send_params: Send parameters
1194
+ :return: Result of the registration transaction
1195
+
1196
+ :example:
1197
+ # Basic example:
1198
+ >>> params = OfflineKeyRegistrationParams(
1199
+ ... sender="ACCOUNTADDRESS",
1200
+ ... prevent_account_from_ever_participating_again=True
1201
+ ... )
1202
+ >>> result = algorand.send.offline_key_registration(params)
1203
+ >>> print(result.tx_id)
1204
+
1205
+ # Advanced example:
1206
+ >>> params = OfflineKeyRegistrationParams(
1207
+ ... sender="ACCOUNTADDRESS",
1208
+ ... prevent_account_from_ever_participating_again=True,
1209
+ ... note=b'Offline registration'
1210
+ ... )
1211
+ >>> result = algorand.send.offline_key_registration(params)
1212
+ >>> print(result.tx_id)
1213
+ """
1214
+ return self._send(
1215
+ lambda c: c.add_offline_key_registration,
1216
+ pre_log=lambda params, transaction: (
1217
+ f"Registering offline key for {params.sender} via transaction {transaction.get_txid()}"
1218
+ ),
1219
+ )(params, send_params)