Application Client

The ApplicationClient provides a convenient way to interact with our Application.

    # Create Application client
    app_client1 = client.ApplicationClient(
        client=sandbox.get_algod_client(), app=nicknames.app, signer=acct1.signer
    )

By passing an AlgodClient, an instance of our Application and a TransactionSigner, we can easily make calls to our application.

Note

The ApplicationClient takes an AlgodClient as its first argument, the most common API providers are available in beaker.client.api_providers

If the application does not yet exist, the app_id argument can be omitted but the first interaction with the Application should be to create it. Once this is done, the app_id will be set for the lifetime of the ApplicationClient instance.

If the application does exist, the app_id can be provided directly

    # Create a new client that just sets the app id we wish to interact with
    app_client3 = ApplicationClient(
        client=sandbox.get_algod_client(),
        app=nicknames.app,
        signer=acct1.signer,
        app_id=app_client1.app_id,
    )

The primary way to of interact with our application is done using the call method, passing the method we want to call and the arguments it expects as keyword arguments.

    app_client1.call(nicknames.set_nick, nick="first")

If there are multiple signers or you want to re-use some suggested parameters, the prepare method may be called with the different arguments and a copy of the client is returned with the updated parameters.

    app_client2 = app_client1.prepare(signer=acct2.signer)

Full Example

class beaker.client.ApplicationClient[source]
__init__(client: AlgodClient, app: beaker.application_specification.ApplicationSpecification | str | pathlib.Path | beaker.application.Application, app_id: int = 0, signer: Optional[TransactionSigner] = None, sender: Optional[str] = None, suggested_params: Optional[SuggestedParams] = None)[source]
add_method_call(atc: AtomicTransactionComposer, method: algosdk.abi.method.Method | pyteal.ABIReturnSubroutine | str, sender: Optional[str] = None, signer: Optional[TransactionSigner] = None, suggested_params: Optional[SuggestedParams] = None, on_complete: OnComplete = OnComplete.NoOpOC, local_schema: Optional[StateSchema] = None, global_schema: Optional[StateSchema] = None, approval_program: Optional[bytes] = None, clear_program: Optional[bytes] = None, extra_pages: Optional[int] = None, accounts: Optional[list[str]] = None, foreign_apps: Optional[list[int]] = None, foreign_assets: Optional[list[int]] = None, boxes: Optional[Sequence[tuple[int, bytes | bytearray | str | int]]] = None, note: Optional[bytes] = None, lease: Optional[bytes] = None, rekey_to: Optional[str] = None, **kwargs: Any) AtomicTransactionComposer[source]

Adds a transaction to the AtomicTransactionComposer passed

call(method: algosdk.abi.method.Method | pyteal.ABIReturnSubroutine | str, sender: Optional[str] = None, signer: Optional[TransactionSigner] = None, suggested_params: Optional[SuggestedParams] = None, on_complete: OnComplete = OnComplete.NoOpOC, local_schema: Optional[StateSchema] = None, global_schema: Optional[StateSchema] = None, approval_program: Optional[bytes] = None, clear_program: Optional[bytes] = None, extra_pages: Optional[int] = None, accounts: Optional[list[str]] = None, foreign_apps: Optional[list[int]] = None, foreign_assets: Optional[list[int]] = None, boxes: Optional[Sequence[tuple[int, bytes | bytearray | str | int]]] = None, note: Optional[bytes] = None, lease: Optional[bytes] = None, rekey_to: Optional[str] = None, atc: Optional[AtomicTransactionComposer] = None, **kwargs: Any) ABIResult[source]

Handles calling the application

clear_state(sender: Optional[str] = None, signer: Optional[TransactionSigner] = None, suggested_params: Optional[SuggestedParams] = None, **kwargs: Any) str[source]

Submits a signed ApplicationCallTransaction with OnComplete set to ClearState

close_out(sender: Optional[str] = None, signer: Optional[TransactionSigner] = None, suggested_params: Optional[SuggestedParams] = None, **kwargs: Any) str[source]

Submits a signed ApplicationCallTransaction with OnComplete set to CloseOut

create(sender: Optional[str] = None, signer: Optional[TransactionSigner] = None, suggested_params: Optional[SuggestedParams] = None, on_complete: OnComplete = OnComplete.NoOpOC, extra_pages: Optional[int] = None, **kwargs: Any) tuple[int, str, str][source]

Submits a signed ApplicationCallTransaction with application id == 0 and the schema and source from the Application passed

delete(sender: Optional[str] = None, signer: Optional[TransactionSigner] = None, suggested_params: Optional[SuggestedParams] = None, **kwargs: Any) str[source]

Submits a signed ApplicationCallTransaction with OnComplete set to DeleteApplication

fund(amt: int, addr: Optional[str] = None) str[source]

convenience method to pay the address passed, defaults to paying the app address for this client from the current signer

get_application_account_info() dict[str, Any][source]

gets the account info for the application account

get_global_state(*, raw: bool = False) dict[bytes | str, bytes | str | int][source]

gets the global state info for the app id set

get_local_state(account: Optional[str] = None, *, raw: bool = False) dict[str | bytes, bytes | str | int][source]

gets the local state info for the app id set and the account specified

opt_in(sender: Optional[str] = None, signer: Optional[TransactionSigner] = None, suggested_params: Optional[SuggestedParams] = None, **kwargs: Any) str[source]

Submits a signed ApplicationCallTransaction with OnComplete set to OptIn

prepare(signer: Optional[TransactionSigner] = None, sender: Optional[str] = None, **kwargs: Any) ApplicationClient[source]

makes a copy of the current ApplicationClient and the fields passed

update(sender: Optional[str] = None, signer: Optional[TransactionSigner] = None, suggested_params: Optional[SuggestedParams] = None, **kwargs: Any) str[source]

Submits a signed ApplicationCallTransaction with OnComplete set to UpdateApplication and source from the Application passed

Full Example

from beaker import client, consts, sandbox
from beaker.client import ApplicationClient, LogicException

from examples.client import nicknames


def main() -> None:
    # Set up accounts we'll use
    accts = sandbox.get_accounts()

    acct1 = accts.pop()
    acct2 = accts.pop()

    # Create Application client
    app_client1 = client.ApplicationClient(
        client=sandbox.get_algod_client(), app=nicknames.app, signer=acct1.signer
    )

    # Create the app on-chain (uses signer1)
    app_id, app_addr, txid = app_client1.create()
    print(f"Created app with id {app_id} and address {app_addr} in transaction {txid}")

    print(f"Current app state: {app_client1.get_global_state()}")
    # Fund the app account with 1 algo
    app_client1.fund(1 * consts.algo)

    # Try calling set nickname from both accounts after opting in
    app_client1.opt_in()
    app_client1.call(nicknames.set_nick, nick="first")

    print(f"Current app state: {app_client1.get_global_state()}")
    # Create copies of the app client with specific signer, _after_ we've created and set the app id
    app_client2 = app_client1.prepare(signer=acct2.signer)
    print(f"Current app state: {app_client1.get_global_state()}")

    # Try calling without opting in
    try:
        app_client2.call(nicknames.set_nick, nick="second")
    except LogicException as e:
        print(f"\n{e}\n")

    app_client2.opt_in()
    app_client2.call(nicknames.set_nick, nick="second")

    # Get the local state for each account
    print(app_client1.get_local_state())
    print(app_client2.get_local_state())

    # Get the global state
    print(f"Current app state: {app_client1.get_global_state()}")

    try:
        app_client2.call(nicknames.set_manager, new_manager=acct2.address)
        print("Shouldn't get here")
    except LogicException as e:
        print("Failed as expected, only addr1 should be authorized to set the manager")
        print(f"\n{e}\n")

    # Have addr1 set the manager to addr2
    app_client1.call(nicknames.set_manager, new_manager=acct2.address)
    print(f"Current app state: {app_client1.get_global_state()}")

    print(app_client1.get_global_state())
    # and back
    app_client2.call(nicknames.set_manager, new_manager=acct1.address)
    print(f"Current app state: {app_client1.get_global_state()}")

    # Create a new client that just sets the app id we wish to interact with
    app_client3 = ApplicationClient(
        client=sandbox.get_algod_client(),
        app=nicknames.app,
        signer=acct1.signer,
        app_id=app_client1.app_id,
    )

    try:
        app_client1.close_out()
        app_client2.close_out()
        app_client3.delete()
    except Exception as e:
        print(e)


if __name__ == "__main__":
    main()