Application Client
The ApplicationClient
provides a convenient way to interact with our Application
.
# Create Application client
app_client1 = client.ApplicationClient(
client=localnet.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 AlgodClient
passed to the ApplicationClient
is always one pointing to the localnet in examples. This is not a requirement, it can be connected to any Algod
node and 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.
If create
is called, 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=localnet.get_algod_client(),
app=nicknames.app,
signer=acct1.signer,
app_id=app_client1.app_id,
)
The primary way to interact with our application is by 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 multiple app calls are required in the same atomic group, the ApplicationClient
also allows composing a group of calls using the add_method_call
method which uses an AtomicTransactionComposer
to build the group.
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)
- class beaker.client.ApplicationClient[source]
- __init__(client: AlgodClient, app: algokit_utils.application_specification.ApplicationSpecification | str | pathlib.Path | beaker.application.Application, *, app_id: int = 0, signer: algosdk.atomic_transaction_composer.TransactionSigner | None = None, sender: str | None = None, suggested_params: algosdk.transaction.SuggestedParams | None = None)[source]
- clear_state(sender: str | None = None, signer: algosdk.atomic_transaction_composer.TransactionSigner | None = None, suggested_params: algosdk.transaction.SuggestedParams | None = None, **kwargs: Any) str [source]
Submits a signed ApplicationCallTransaction with OnComplete set to ClearState
- close_out(sender: str | None = None, signer: algosdk.atomic_transaction_composer.TransactionSigner | None = None, suggested_params: algosdk.transaction.SuggestedParams | None = None, **kwargs: Any) str [source]
Submits a signed ApplicationCallTransaction with OnComplete set to CloseOut
- create(sender: str | None = None, signer: algosdk.atomic_transaction_composer.TransactionSigner | None = None, suggested_params: algosdk.transaction.SuggestedParams | None = None, on_complete: OnComplete = OnComplete.NoOpOC, extra_pages: int | None = 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: str | None = None, signer: algosdk.atomic_transaction_composer.TransactionSigner | None = None, suggested_params: algosdk.transaction.SuggestedParams | None = None, **kwargs: Any) str [source]
Submits a signed ApplicationCallTransaction with OnComplete set to DeleteApplication
- fund(amt: int, addr: str | None = 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
- opt_in(sender: str | None = None, signer: algosdk.atomic_transaction_composer.TransactionSigner | None = None, suggested_params: algosdk.transaction.SuggestedParams | None = None, **kwargs: Any) str [source]
Submits a signed ApplicationCallTransaction with OnComplete set to OptIn
- prepare(signer: algosdk.atomic_transaction_composer.TransactionSigner | None = None, sender: str | None = None, app_id: int | None = None) ApplicationClient [source]
makes a copy of the current ApplicationClient and the fields passed
- update(sender: str | None = None, signer: algosdk.atomic_transaction_composer.TransactionSigner | None = None, suggested_params: algosdk.transaction.SuggestedParams | None = None, **kwargs: Any) str [source]
Submits a signed ApplicationCallTransaction with OnComplete set to UpdateApplication and source from the Application passed
Full Example
from algokit_utils import LogicError
from beaker import client, consts, localnet
from beaker.client import ApplicationClient
from examples.client import nicknames
def main() -> None:
# Set up accounts we'll use
accts = localnet.get_accounts()
acct1 = accts.pop()
acct2 = accts.pop()
# Create Application client
app_client1 = client.ApplicationClient(
client=localnet.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 LogicError 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 LogicError 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=localnet.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()