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)
- 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
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()