Account management | Algorand Developer Portal

Account management

Account management is one of the core capabilities provided by AlgoKit Utils. It allows you to create mnemonic, rekeyed, multisig, transaction signer, idempotent KMD, and environment variable injected accounts that can be used to sign transactions as well as representing a sender address at the same time. This significantly simplifies management of transaction signing.

AccountManager

The AccountManager is a class that is used to get, create, and fund accounts and perform account-related actions such as funding. The AccountManager also keeps track of signers for each address, so when using the TransactionComposer to send transactions, a signer function does not need to manually be specified for each transaction - instead, it can be inferred from the sender address automatically!

To get an instance of AccountManager, you can use either AlgorandClient via algorand.account or instantiate it directly:

from algokit_utils import AccountManager

account_manager = AccountManager(client_manager)

TransactionSignerAccountProtocol

The core internal type that holds information about a signer/sender pair for a transaction is TransactionSignerAccountProtocol, which represents an algosdk.transaction.TransactionSigner (signer) along with a sender address (address) as the encoded string address.

The following conform to TransactionSignerAccountProtocol:

Registering a signer

The AccountManager keeps track of which signer is associated with a given sender address. This is used by AlgorandClient to automatically sign transactions by that sender. Any of the methods within AccountManager that return an account will automatically register the signer with the sender.

There are two methods that can be used for this, set_signer_from_account, which takes any number of account-based objects that combine signer and sender (TransactionSignerAccount | SigningAccount | LogicSigAccount | MultisigAccount), or set_signer which takes the sender address and the TransactionSigner:

algorand.account .set_signer_from_account(TransactionSignerAccount(your_address, your_signer)) .set_signer_from_account(SigningAccount.new_account()) .set_signer_from_account( LogicSigAccount(algosdk.transaction.LogicSigAccount(program, args)) ) .set_signer_from_account( MultisigAccount( MultisigMetadata( version = 1, threshold = 1, addresses = ["ADDRESS1...", "ADDRESS2..."] ), [account1, account2] ) ) .set_signer("SENDERADDRESS", transaction_signer)

Default signer

If you want to have a default signer that is used to sign transactions without a registered signer (rather than throwing an exception) then you can set_default_signer:

algorand.account.set_default_signer(my_default_signer)

Get a signer

AlgorandClient will automatically retrieve a signer when signing a transaction, but if you need to get a TransactionSigner externally to do something more custom then you can get_signer for a given sender address:

signer = algorand.account.get_signer("SENDER_ADDRESS")

If there is no signer registered for that sender address, it will either return the default signer ( if registered) or throw an exception.

Accounts

In order to get/register accounts for signing operations, you can use the following methods on AccountManager (expressed here as algorand.account to denote the syntax via an AlgorandClient):

Underlying account classes

While TransactionSignerAccount is the main class used to represent an account that can sign, there are underlying account classes that can underpin the signer within the transaction signer account.

Dispenser

Rekey account

One of the unique features of Algorand is the ability to change the private key that can authorise transactions for an account. This is called rekeying.

Rekeying should be done with caution as a rekey transaction can result in permanent loss of control of an account.

You can issue a transaction to rekey an account by using the rekey_account function:

You can also pass in rekeyTo as a common transaction parameter to any transaction.

Examples

Basic example (with string addresses)

algorand.account.rekey_account({
  account: "ACCOUNTADDRESS",
  rekey_to: "NEWADDRESS",
})

Basic example (with signer accounts)

algorand.account.rekey_account({
  account: account1,
  rekey_to: new_signer_account,
})

Advanced example

algorand.account.rekey_account({
  account: "ACCOUNTADDRESS",
  rekey_to: "NEWADDRESS",
  lease: "lease",
  note: "note",
  first_valid_round: 1000,
  validity_window: 10,
  extra_fee: AlgoAmount.from_micro_algos(1000),
  static_fee: AlgoAmount.from_micro_algos(1000),
  max_fee: AlgoAmount.from_micro_algos(3000),
  max_rounds_to_wait_for_confirmation: 5,
  suppress_log: True,
})

Using a rekeyed account

Note: if a signing account is passed into `algorand.account.rekey_account`, then you don't need to call `rekeyed_account` to register the new signer
rekeyed_account = algorand.account.rekey_account(account, new_account)

KMD account management

When running LocalNet, you have an instance of the Key Management Daemon, which is useful for:

The KMD SDK is fairly low-level, so to make use of it there is a fair bit of boilerplate code that’s needed. This code has been abstracted away into the KmdAccountManager class.

To get an instance of the KmdAccountManager class, you can access it from AlgorandClient via algorand.account.kmd or instantiate it directly (passing in a ClientManager):

from algokit_utils import KmdAccountManager kmd_account_manager = KmdAccountManager(client_manager)

The methods that are available are:

Get a wallet account that seeded the LocalNet network

default_dispenser_account = kmd_account_manager.get_wallet_account(
    "unencrypted-default-wallet",
    lambda a: a["status"] != "Offline" and a["amount"] > 1_000_000_000
)

Same as above, but dedicated method call for convenience

localnet_dispenser_account = kmd_account_manager.get_localnet_dispenser_account()

Idempotently get (if exists) or create (if it doesn't exist yet) an account by name using KMD

new_account = kmd_account_manager.get_or_create_wallet_account(
    "account1",
    AlgoAmount.from_algos(2)
)

This will return the same account as above since the name matches

existing_account = kmd_account_manager.get_or_create_wallet_account(
    "account1"
)

Some of this functionality is directly exposed from AccountManager, which has the added benefit of registering the account as a signer so they can be automatically used to sign transactions when using via AlgorandClient:

Get and register LocalNet dispenser

localnet_dispenser = algorand.account.localnet_dispenser()

Get and register a dispenser by environment variable, or if not set then LocalNet dispenser via KMD

dispenser = algorand.account.dispenser_from_environment()

Get an account from KMD idempotently by name. In this case, we'll get the default dispenser account

dispenser_via_kmd = algorand.account.from_kmd('unencrypted-default-wallet', lambda a: a.status != 'Offline' and a.amount > 1_000_000_000)

Get / create and register account from KMD idempotently by name

fresh_account_via_kmd = algorand.account.kmd.get_or_create_wallet_account('account1', AlgoAmount.from_algos(2))