Migration Guide - v3¶
Version 3 of algokit-utils-ts moved from a stateless function-based interface to a stateful class-based interfaces. This change allows for:
Easier and simpler consumption experience guided by IDE autocompletion
Less redundant parameter passing (e.g.,
algodclient)Better performance through caching of commonly retrieved values like transaction parameters
More consistent and intuitive API design
Stronger type safety and better error messages
Improved ARC-56 compatibility
Feature parity with
algokit-utils-ts>=v7interfaces
The entry point to most functionality in AlgoKit Utils is now available via a single entry-point, the AlgorandClient class.
The v2 interfaces and abstractions will be removed in future major version bumps, however in order to ensure gradual migration, all v2 abstractions are available with respective deprecation warnings. The new way to use AlgoKit Utils is via the AlgorandClient class, which is easier, simpler, and more convenient to use and has powerful new features.
BREAKING CHANGE: the
betamodule is now removed, any imports fromalgokit_utils.betawill now raise an error with a link to a new expected import path. This is due to the fact that the interfaces introduced inbetaare now refined and available in the main module.
Migration Steps¶
In general, your codebase might fall into one of the following migration scenarios:
Using
algokit-utils-pyv2.x only without use of abstractions frombetamoduleUsing
algokit-utils-pyv2.x only and with use of abstractions frombetamoduleUsing
algokit-utils-pyv2.x withalgokit-client-generator-pyv1.xUsing
algokit-client-generator-pyv1.x only (implies implicit dependency onalgokit-utils-pyv2.x)
Given that algokit-utils-py v3.x is backwards compatible with algokit-client-generator-py v1.x, the following general guidelines are applicable to all scenarios (note that the order of operations is important to ensure straight-forward migration):
Upgrade to
algokit-utils-pyv3.x1.1 (If used) Update imports from
algokit_utils.betatoalgokit_utils1.2 Follow hints in deprecation warnings to update your codebase to rely on latest v3 interfaces
Upgrade to
algokit-client-generator-pyv2.x and regenerate typed clients2.1 Follow
algokit-client-generator-pyv2.x migration guide
The remaining set of guidelines are outlining migrations for specific abstractions that had direct equivalents in algokit-utils-py v2.x.
Prerequisites¶
It is important to reiterate that if you have previously relied on beta versions of algokit-utils-py v2.x, you will need to update your imports to rely on the new interfaces. Errors thrown during import from beta will provide a description of the new expected import path.
As with
v2.xall public abstractions inalgokit_utilsare available for direct importsfrom algokit_utils import ..., however underlying modules have been refined to be structured loosely around common AVM domains such asapplications,transactions,accounts,assets, etc. See API reference for latest and detailed overview.
Step 1 - Replace SDK Clients with AlgorandClient¶
First, replace your SDK client initialization with AlgorandClient. Look for get_algod_client calls and replace with an appropriate AlgorandClient initialization:
"""Before"""
import algokit_utils
algod = algokit_utils.get_algod_client()
indexer = algokit_utils.get_indexer_client()
"""After"""
from algokit_utils import AlgorandClient
algorand = AlgorandClient.from_environment() # or .testnet(), .mainnet(), etc.
During migration, you can still access SDK clients if needed:
algod = algorand.client.algod
indexer = algorand.client.indexer
kmd = algorand.client.kmd
Step 2 - Update Account Management¶
Account management has moved to algorand.account:
Before:¶
account = algokit_utils.get_account_from_mnemonic(
mnemonic=os.getenv("MY_ACCOUNT_MNEMONIC"),
)
dispenser = algokit_utils.get_dispenser_account(algod)
After:¶
account = algorand.account.from_mnemonic(os.getenv("MY_ACCOUNT_MNEMONIC"))
dispenser = algorand.account.dispenser_from_environment()
Key changes:
get_account→account.from_environmentget_account_from_mnemonic→account.from_mnemonicget_dispenser_account→account.dispenser_from_environmentget_localnet_default_account→account.localnet_dispenser
Step 3 - Update Transaction Management¶
Transaction creation and sending is now more structured:
Before:¶
# Single transaction
result = algokit_utils.transfer_algos(
from_account=account,
to_addr="RECEIVER",
amount=algokit_utils.algos(1),
algod_client=algod,
)
# Transaction groups
atc = AtomicTransactionComposer()
# ... add transactions ...
result = algokit_utils.execute_atc_with_logic_error(atc, algod)
After:¶
# Single transaction
result = algorand.send.payment(
sender=account.address,
receiver="RECEIVER",
amount=AlgoAmount.from_algo(1),
)
# Transaction groups
composer = algorand.new_group()
# ... add transactions ...
result = composer.send()
Key changes:
transfer_algos→algorand.send.paymenttransfer_asset→algorand.send.asset_transferexecute_atc_with_logic_error→composer.send()Transaction parameters are now more consistently named (e.g.,
senderinstead offrom_account)Improved amount handling with dedicated
AlgoAmountclass (e.g.,AlgoAmount.from_algo(1))
Step 4 - Update ApplicationSpecification usage¶
ApplicationSpecification abstraction is largely identical to v2, however it’s been renamed to Arc32Contract to better reflect the fact that it’s a contract specification for a specific ARC and addition of Arc56Contract supporting the latest recommended conventions. Hence the main actionable change is to update your import to from algokit_utils import Arc32Contract and rename ApplicationSpecification to Arc32Contract.
You can instantiate an Arc56Contract instance from an Arc32Contract instance using the Arc56Contract.from_arc32 method. For instance:
testing_app_arc32_app_spec = Arc32Contract.from_json(app_spec_json)
arc56_app_spec = Arc56Contract.from_arc32(testing_app_arc32_app_spec)
Despite auto conversion of ARC-32 to ARC-56, we recommend recompiling your contract to a fully compliant ARC-56 specification given that auto conversion would skip populating information that can’t be parsed from raw ARC-32.
Step 5 - Replace ApplicationClient usage¶
The existing ApplicationClient (untyped app client) class is still present until at least v4, but it’s worthwhile migrating to the new AppClient and AppFactory classes. These new clients are ARC-56 compatible, but also support ARC-32 app specs and will continue to support this indefinitely until such time the community deems they are deprecated.
All of the functionality in ApplicationClient is available within the new classes, but their interface is slightly different to make it easier to use and more consistent with the new AlgorandClient functionality. The key existing methods that have changed all have @deprecation notices to help guide you on this, but broadly the changes are:
The app resolution semantics, now have static methods that determine different ways of constructing a client and the constructor itself is very simple (requiring
app_id)If you want to call
createordeploythen you need anAppFactoryto do that, and then it will in turn give you anAppClientinstance that is connected to the app you just created / deployed. This significantly simplifies the app client because now the app client has a clear operating purpose: allow for calls and state management for an instance of an app, whereas the app factory handles all of the calls when you don’t have an instance yet (or may or may not have an instance in the case ofdeploy).This means that you can simply access
client.app_idandclient.app_addressonAppClientsince these values are known statically and won’t change (previously associated calls toapp_address,app_idproperties potentially required extra API calls as the values weren’t always available).Adding
fund_app_accountwhich serves as a convenience method to top up the balance of address associated with application.All of the methods that return or execute a transaction (
update,call,opt_in, etc.) are now exposed in an interface similar to the one inAlgorandClient, namely (where{call_type}is one of:update/delete/opt_in/close_out/clear_state/call):appClient.create_transaction.{callType}to get a transaction for an ABI method callappClient.send.{call_type}to sign and send a transaction for an ABI method callappClient.params.{call_type}to get a params object for an ABI method callappClient.create_transaction.bare.{call_type}to get a transaction for a bare app callappClient.send.bare.{call_type}to sign and send a transaction for a bare app callappClient.params.bare.{call_type}to get a params object for a bare app call
The semantics to resolve the application is now available via simpler entrypoints within
algorand.clientWhen making an ABI method call, the method arguments property is are now passed via explicit
argsfield in a parameters dataclass applicable to the method call.The foreign reference arrays have been renamed to align with typed parameters on
tsand related corealgosdk:boxes->box_referencesapps->app_referencesassets->asset_referencesaccounts->account_references
The return value for methods that send a transaction will have any ABI return value directly in the
abi_returnproperty rather than the low level algosdkABIResulttype while also automatically decoding values based on provided ARC56 spec.
Step 6 - Replace typed app client usage¶
Version 2 of the Python typed app client generator introduces breaking changes to the generated client that support the new AppFactory and AppClient functionality along with adding ARC-56 support. The generated client has better typing support for things like state commensurate with the new capabilities within ARC-56.
It’s worth noting that because we have maintained backwards compatibility with the pre v2 algokit-utils-py stateless functions, older typed clients generated using version 1 of the Python typed client generator will work against v3 of utils, however you won’t have access to the new features or ARC-56 support.
If you want to convert from an older typed client to a new one you will need to make certain changes. Refer to client generator v2 migration guide.
Step 7 - Update AppClient State Management¶
State management is now more structured and type-safe:
"""Before"""
global_state = app_client.get_global_state()
local_state = app_client.get_local_state(account_address)
box_value = app_client.get_box_value("box_name")
"""After"""
# Global state
global_state = app_client.state.global_state.get_all()
value = app_client.state.global_state.get_value("key_name")
map_value = app_client.state.global_state.get_map_value("map_name", "key")
# Local state
local_state = app_client.state.local_state(account_address).get_all()
value = app_client.state.local_state(account_address).get_value("key_name")
map_value = app_client.state.local_state(account_address).get_map_value("map_name", "key")
# Box storage
box_value = app_client.state.box.get_value("box_name")
boxes = app_client.state.box.get_all()
map_value = app_client.state.box.get_map_value("map_name", "key")
Step 8 - Update Asset Management¶
Asset management is now more consistent:
"""Before"""
result = algokit_utils.opt_in(algod, account, [asset_id])
"""After"""
result = algorand.send.asset_opt_in(
params=AssetOptInParams(
sender=account.address,
asset_id=asset_id,
)
)
Breaking Changes¶
Client Management
Removal of standalone client creation functions
All clients now accessed through
AlgorandClient
Account Management
Account creation functions moved to
AccountManageraccessible viaalgorand.accountpropertyUnified
TransactionSignerAccountProtocolwith compliant and typedSigningAccount,TransactionSignerAccount,LogicSigAccount,MultiSigAccountclasses encapsulating low levelalgosdkabstractions.Improved typing for account operations, such as obtaining account information from
algod, returning a typed information object.
Transaction Management
Consistent and intuitive transaction creation and sending interface accessible via
algorand.{send|params|create_transaction}propertiesNew transaction composition interface accessible via
algorand.new_groupRemoving necessity to interact with low level and untyped
algosdkabstractions for assembling, signing and sending transaction(s).
Application Client
Split into
AppClient,AppDeployerandAppFactorydeploymethod inAppFactory/AppDeployerno longer auto increments the contract version by default. It is the user’s responsibility to explicitly manage versioning of their smart contracts (if desired).New intuitive structured interface for creating or sending
AppCall|AppMethodCalltransactionsARC-56 support along with automatic conversion of specs from ARC-32 to ARC-56
State Management
New hierarchical state access available via
app_client.state.{global_state|local_state|box}propertiesImproved typing for state values
Support for ARC-56 state schemas
Asset Management
Dedicated
AssetManagerclass for asset management accessible viaalgorand.assetpropertyImproved typing for asset operations, such as obtaining asset information from
algod, returning a typed information object.Consistent interface for asset opt-in, transfer, freeze, etc.
Best Practices¶
Use the new
AlgorandClientas the main entry pointLeverage IDE autocompletion to discover available functionality, consult with API reference when unsure
Use the transaction parameter builders for type-safe transaction creation (
algorand.params.{})Use the state accessor patterns for cleaner state management {
algorand.state.{}}Use high level
TransactionComposerinterface over low levelalgosdkabstractions (where possible)Use source maps and debug mode to quickly troubleshoot on-chain errors
Use idempotent deployment patterns with versioning
Troubleshooting¶
A v2 interface/method/class does not display a deprecation warning correctly or at all¶
Submit an issue to algokit-utils-py with a description of the problem and the code that is causing it.
Useful scenario of converting v2 to v3 not covered in generic migration guide¶
If you have a scenario that you think is useful and not covered in the generic migration guide, please submit an issue to algokit-utils-py with a scenario.