Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
359 changes: 359 additions & 0 deletions _ARCHIVE/app-client.md

Large diffs are not rendered by default.

261 changes: 261 additions & 0 deletions _ARCHIVE/app-deploy.md

Large diffs are not rendered by default.

166 changes: 166 additions & 0 deletions _ARCHIVE/app.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
title: "App management"
description: "App management is a higher-order use case capability provided by AlgoKit Utils that builds on top of the core capabilities. It allows you to create, update, delete, call (ABI and otherwise) smart contract apps and the metadata associated with them (including state and boxes)."
---

App management is a higher-order use case capability provided by AlgoKit Utils that builds on top of the core capabilities. It allows you to create, update, delete, call (ABI and otherwise) smart contract apps and the metadata associated with them (including state and boxes).

## `AppManager`

The `AppManager` is a class that is used to manage app information. To get an instance of `AppManager` you can use either [`AlgorandClient`](../../core/algorand-client/) via `algorand.app` or instantiate it directly (passing in an algod client instance):

```python
from algokit_utils import AppManager

app_manager = AppManager(algod_client)
```

## Calling apps

### App Clients

The recommended way of interacting with apps is via [App clients](../app-client/) and [App factory](../app-client/#appfactory). The methods shown on this page are the underlying mechanisms that app clients use and are for advanced use cases when you want more control.

### Compilation

The `AppManager` class allows you to compile TEAL code with caching semantics that allows you to avoid duplicate compilation and keep track of source maps from compiled code.

```python
# Basic compilation
teal_code = "return 1"
compilation_result = app_manager.compile_teal(teal_code)

# Get cached compilation result
cached_result = app_manager.get_compilation_result(teal_code)

# Compile with template substitution
template_code = "int TMPL_VALUE"
template_params = {"VALUE": 1}
compilation_result = app_manager.compile_teal_template(
template_code,
template_params=template_params
)

# Compile with deployment control (updatable/deletable)
control_template = f"""#pragma version 8
int {UPDATABLE_TEMPLATE_NAME}
int {DELETABLE_TEMPLATE_NAME}"""
deployment_metadata = {"updatable": True, "deletable": True}
compilation_result = app_manager.compile_teal_template(
control_template,
deployment_metadata=deployment_metadata
)
```

The compilation result contains:

- `teal` - Original TEAL code
- `compiled` - Base64 encoded compiled bytecode
- `compiled_hash` - Hash of compiled bytecode
- `compiled_base64_to_bytes` - Raw bytes of compiled bytecode
- `source_map` - Source map for debugging

## Accessing state

### Global state

To access global state you can use:

```python
# Get global state for app
global_state = app_manager.get_global_state(app_id)

# Parse raw state from algod
decoded_state = AppManager.decode_app_state(raw_state)

# Access state values
key_raw = decoded_state["value1"].key_raw # Raw bytes
key_base64 = decoded_state["value1"].key_base64 # Base64 encoded
value = decoded_state["value1"].value # Parsed value (str or int)
value_raw = decoded_state["value1"].value_raw # Raw bytes if bytes value
value_base64 = decoded_state["value1"].value_base64 # Base64 if bytes value
```

### Local state

To access local state you can use:

```python
local_state = app_manager.get_local_state(app_id, "ACCOUNT_ADDRESS")
```

### Boxes

To access box storage:

```python
# Get box names
box_names = app_manager.get_box_names(app_id)

# Get box values
box_value = app_manager.get_box_value(app_id, box_name)
box_values = app_manager.get_box_values(app_id, [box_name1, box_name2])

# Get decoded ABI values
abi_value = app_manager.get_box_value_from_abi_type(
app_id, box_name, algosdk.abi.StringType()
)
abi_values = app_manager.get_box_values_from_abi_type(
app_id, [box_name1, box_name2], algosdk.abi.StringType()
)

# Get box reference for transaction
box_ref = AppManager.get_box_reference(box_id)
```

## Getting app information

To get app information:

```python
# Get app info by ID
app_info = app_manager.get_by_id(app_id)

# Get ABI return value from transaction
abi_return = AppManager.get_abi_return(confirmation, abi_method)
```

## Box references

Box references can be specified in several ways:

```python
# String name (encoded to bytes)
box_ref = "my_box"

# Raw bytes
box_ref = b"my_box"

# Account signer (uses address as name)
box_ref = account_signer

# Box reference with app ID
box_ref = BoxReference(app_id=123, name=b"my_box")
```

## Common app parameters

When interacting with apps (creating, updating, deleting, calling), there are common parameters that can be passed:

- `app_id` - ID of the application
- `sender` - Address of transaction sender
- `signer` - Transaction signer (optional)
- `args` - Arguments to pass to the smart contract
- `account_references` - Account addresses to reference
- `app_references` - App IDs to reference
- `asset_references` - Asset IDs to reference
- `box_references` - Box references to load
- `on_complete` - On complete action
- Other common transaction parameters like `note`, `lease`, etc.

For ABI method calls, additional parameters:

- `method` - The ABI method to call
- `args` - ABI typed arguments to pass

See [App client](../app-client/) for more details on constructing app calls.
187 changes: 187 additions & 0 deletions _ARCHIVE/typed-app-clients.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
---
title: "Typed application clients"
description: "Typed application clients are automatically generated, typed Python deployment and invocation clients for smart contracts that have a defined ARC-56 or ARC-32 application specification so that the development experience is easier with less upskill ramp-up and less deployment errors. These clients give you a type-safe, intellisense-driven experience for invoking the smart contract."
---

Typed application clients are automatically generated, typed Python deployment and invocation clients for smart contracts that have a defined [ARC-56](https://github.com/algorandfoundation/ARCs/pull/258) or [ARC-32](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0032.md) application specification so that the development experience is easier with less upskill ramp-up and less deployment errors. These clients give you a type-safe, intellisense-driven experience for invoking the smart contract.

Typed application clients are the recommended way of interacting with smart contracts. If you don't have/want a typed client, but have an ARC-56/ARC-32 app spec then you can use the [non-typed application clients](../app-client/) and if you want to call a smart contract you don't have an app spec file for you can use the underlying [app management](../app/) and [app deployment](../app-deploy/) functionality to manually construct transactions.

## Generating an app spec

You can generate an app spec file:

- Using [Algorand Python](https://algorandfoundation.github.io/puya/#quick-start)
- Using [TEALScript](https://tealscript.netlify.app/tutorials/hello-world/0004-artifacts/)
- By hand by following the specification [ARC-56](https://github.com/algorandfoundation/ARCs/pull/258)/[ARC-32](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0032.md)
- Using [Beaker](https://algorand-devrel.github.io/beaker/html/usage.html) (PyTEAL) _(DEPRECATED)_

## Generating a typed client

To generate a typed client from an app spec file you can use [AlgoKit CLI](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/generate.md#1-typed-clients):

```
> algokit generate client application.json --output /absolute/path/to/client.py
```

Note: AlgoKit Utils >= 3.0.0 is compatible with the older 1.x.x generated typed clients, however if you want to utilise the new features or leverage ARC-56 support, you will need to generate using >= 2.x.x. See [AlgoKit CLI generator version pinning](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/generate.md#version-pinning) for more information on how to lock to a specific version.

## Getting a typed client instance

To get an instance of a typed client you can use an [`AlgorandClient`](../../core/algorand-client/) instance or a typed app [`Factory`](#creating-a-typed-factory-instance) instance.

The approach to obtaining a client instance depends on how many app clients you require for a given app spec and if the app has already been deployed:

### App is deployed

#### Resolve App by ID

**Single Typed App Client Instance:**

```python
# Typed: Using the AlgorandClient extension method
typed_client = algorand.client.get_typed_app_client_by_id(
MyContractClient, # Generated typed client class
app_id=1234,
# ...
)
# or Typed: Using the generated client class directly
typed_client = MyContractClient(
algorand,
app_id=1234,
# ...
)
```

**Multiple Typed App Client Instances:**

```python
# Typed: Using a typed factory to get multiple client instances
typed_client1 = typed_factory.get_app_client_by_id(
app_id=1234,
# ...
)
typed_client2 = typed_factory.get_app_client_by_id(
app_id=4321,
# ...
)
```

#### Resolve App by Creator and Name

**Single Typed App Client Instance:**

```python
# Typed: Using the AlgorandClient extension method
typed_client = algorand.client.get_typed_app_client_by_creator_and_name(
MyContractClient, # Generated typed client class
creator_address="CREATORADDRESS",
app_name="contract-name",
# ...
)
# or Typed: Using the static method on the generated client class
typed_client = MyContractClient.from_creator_and_name(
algorand,
creator_address="CREATORADDRESS",
app_name="contract-name",
# ...
)
```

**Multiple Typed App Client Instances:**

```python
# Typed: Using a typed factory to get multiple client instances by name
typed_client1 = typed_factory.get_app_client_by_creator_and_name(
creator_address="CREATORADDRESS",
app_name="contract-name",
# ...
)
typed_client2 = typed_factory.get_app_client_by_creator_and_name(
creator_address="CREATORADDRESS",
app_name="contract-name-2",
# ...
)
```

### App is not deployed

#### Deploy a New App

```python
# Typed: For typed clients, you call a specific creation method rather than generic 'create'
typed_client, response = typed_factory.send.create.{METHODNAME}(
# ...
)
```

#### Deploy or Resolve App Idempotently by Creator and Name

```python
# Typed: Using the deploy method on a typed factory
typed_client, response = typed_factory.deploy(
on_update=OnUpdate.UpdateApp,
on_schema_break=OnSchemaBreak.ReplaceApp,
# The parameters for create/update/delete would be specific to your generated client
app_name="contract-name",
# ...
)
```

### Creating a typed factory instance

If your scenario calls for an app factory, you can create one using the below:

```python
# Typed: Using the AlgorandClient extension method
typed_factory = algorand.client.get_typed_app_factory(MyContractFactory) # Generated factory class
# or Typed: Using the factory class constructor directly
typed_factory = MyContractFactory(algorand)
```

## Client usage

See the [official usage docs](https://github.com/algorandfoundation/algokit-client-generator-py/blob/main/docs/usage.md) for full details about typed clients.

Below is a realistic example that deploys a contract, funds it if newly created, and calls a `"hello"` method:

```python
# Typed: Complete example using a typed application client
import algokit_utils
from artifacts.hello_world.hello_world_client import (
HelloArgs, # Generated args class
HelloWorldFactory, # Generated factory class
)

# Get Algorand client from environment variables
algorand = algokit_utils.AlgorandClient.from_environment()
deployer = algorand.account.from_environment("DEPLOYER")

# Create the typed app factory
typed_factory = algorand.client.get_typed_app_factory(
HelloWorldFactory, default_sender=deployer.address
)

# Deploy idempotently - creates if it doesn't exist or updates if changed
typed_client, result = typed_factory.deploy(
on_update=algokit_utils.OnUpdate.AppendApp,
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
)

# Fund the app with 1 ALGO if it's newly created
if result.operation_performed in [
algokit_utils.OperationPerformed.Create,
algokit_utils.OperationPerformed.Replace,
]:
algorand.send.payment(
algokit_utils.PaymentParams(
amount=algokit_utils.AlgoAmount(algo=1),
sender=deployer.address,
receiver=typed_client.app_address,
)
)

# Call the hello method on the smart contract
name = "world"
response = typed_client.send.hello(args=HelloArgs(name=name)) # Using generated args class
```
20 changes: 0 additions & 20 deletions docs/sidebar.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,11 @@
{ "slug": "concepts/algorand-client" },
{ "slug": "concepts/transactions" },
{ "slug": "concepts/account" },
{ "slug": "concepts/core/amount" },
{ "slug": "concepts/assets" },
{ "slug": "concepts/core/client" },
{ "slug": "concepts/core/secret-management" },
{ "slug": "concepts/applications" },
{ "slug": "concepts/errors-and-debugging" }
]
},
{
"label": "Building Applications",
"items": [
{ "slug": "concepts/building/asset" },
{ "slug": "concepts/building/transfer" },
{ "slug": "concepts/building/testing" }
]
},
{
"label": "Advanced Topics",
"collapsed": true,
"items": [
{ "slug": "concepts/advanced/modular-imports" },
{ "slug": "concepts/advanced/indexer" },
{ "slug": "concepts/advanced/dispenser-client" }
]
},
{
"label": "Migration Guides",
"collapsed": true,
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/concepts/account.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Other operations, such as creating and renaming a wallet, can also be performed
frame="none"
/>

The KMD SDK is fairly low level, so to make use of it directly there is a fair bit of boilerplate. This is abstracted away into the `KmdAccountManager` class, which you can access from [`AlgorandClient`](../algorand-client/) via `algorand.account.kmd` or instantiate directly (passing in a [`ClientManager`](../client/)):
The KMD SDK is fairly low level, so to make use of it directly there is a fair bit of boilerplate. This is abstracted away into the `KmdAccountManager` class, which you can access from [`AlgorandClient`](../algorand-client/) via `algorand.account.kmd` or instantiate directly (passing in a [`ClientManager`](/algokit-utils-py/api/algokit_utils/clients/client_manager/)):

<RemoteCode
src="https://raw.githubusercontent.com/algorandfoundation/algokit-utils-py/refs/heads/main/examples/concepts/accounts.py"
Expand Down
Loading
Loading