Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Article Thumbnail

Introducing AVM 9: Group Resource Sharing

With AVM 9, smart contracts can now access resources available to other transactions in their transaction group during evaluation.

The spec concisely describing resource availability rules is available here.

A Refresher on Reference Arrays

When processing transactions, the evaluator reads and writes data to/from disk. To eliminate the possibility for abuse and ensure high performance of the blockchain, ledger access per transaction must be limited.

The mechanism used by the AVM to control read and write budget is the smart contract reference arrays. These include the apps array, assets array, accounts array, and boxes array. They are limited to 8 total references per app call transaction.

The references passed in through these arrays define which pieces of blockchain state the smart contract can access during evaluation. There are also some references that are implicitly available, e.g. the address of the sender of a transaction.

Example 1: a simple swap

Alice calls an automated market maker (AMM) to swap ETH for BTC on Algorand. The evaluation of the AMM call will need access to its own liquidity pool’s balance of BTC and ETH. Thus, Alice’s app call must have ETH and BTC in its assets array.

The contract evaluation will also need access to Alice’s account to perform an inner transaction of BTC to her account. But, since Alice is the sender of the app call, her address is implicitly available.

Number of resource references in arrays: 2 – ETH and BTC in the assets array.

Example 2: a better swap

Alice has become a little obsessed with trading cryptocurrencies on Algorand and her sophistication as a trader has grown. There are several AMM options on Algorand, and she wants to ensure she gets the best price across all of them.

Alice writes an AMM Aggregator smart contract that calls two AMMs to determine which one has the better exchange rate at that moment, and then executes the swap on that one.

When Alice calls her AMM aggregator app, the app call must still have ETH and BTC in its assets array. It must now additionally have both AMM IDs in its apps array.

Number of resource references in the arrays of the top-level aggregator call: 4.

The inner app calls each need their reference arrays populated with ETH and BTC.

Of course, there are more than two AMM’s available on Algorand. Alice can aggregate at most 6 AMM’s in this fashion (assuming they’re all implemented without requiring additional references), at which point she reaches the maximum number of resources in her app call arrays.

Example 3: an even better swap

As Alice continues to research trading, she realizes she can sometimes get a better swap rate by going through a 3rd asset, e.g. if she wants to swap ETH for BTC, she might get the best rate by first swapping ETH for USDC and then USDC for BTC.

USDC is just an example, any other asset could be used as an intermediary to offer a potentially better swap rate.

To achieve this, Alice’s new aggregator smart contract would compare the swap rate of ETH for BTC with the rate obtained by first swapping ETH for USDC, then USDC for BTC.

Number of resource references in the arrays of the top-level aggregator call: 4. ETH and BTC in the assets array, and the ETH/USDC AMM ID and the USDC/BTC AMM ID in the apps array.

But this basic version is not enough for Alice. Now a professional managing millions, she wants to be able to look at other AMMs and other possible multi-hop routes for her trades, ensuring that she is always getting the optimal swap rate. The reference limit is now a barrier to her work being implemented fully on-chain.

You may be thinking: why can’t Alice figure out the optimal swap from off-chain and then just execute on-chain? Why go to all this trouble? The main reason is that by performing these optimizations on-chain, Alice ensures that the information used during evaluation is always up-to-date with the current state and she is indeed getting the best swap rate for that moment.

The Solution: Sharing References Across the Transaction Group

Similarly to how opcode budget and fees are pooled across the transaction group, as of AVM 9 access to references is now also being shared across the transaction group.

Imagine a transaction group composed of two app call transactions, transaction 1 and transaction 2. They both need access to asset A.

In previous versions of the AVM (before version 9), both transactions 1 and 2 would need to include A in their assets arrays.

As of version 9, this is no longer necessary: as long as asset A appears in at least one asset array in the top-level transaction group, all transactions in the group are given access to A during evaluation. This includes inner transactions - it is no longer necessary to populate inner transaction reference arrays.

As a result of this access to references across the group, a single app call transaction evaluation can now access more than 8 references. In fact, since there can be a maximum of 16 top-level transactions grouped together, there can now be a maximum of 8*16 = 128 references used by a single app call.

A Noteworthy Subtlety: Resources that Require Two References to Specify

There are three pieces of data that have a unique access pattern: app local state, asset balances, and boxes. These pieces of state each require two references to be available. For this type of resource, both of the references needed to identify them must appear in the same transaction.

To access an app local state for an account, both the app ID and the account ID need to be available in the same top-level app call.

To access the asset balance for an account, both the asset ID and the account ID need to be available in the same top-level transaction - either in an app’s foreign arrays or in a simple axfer transaction.

Accessing a box requires calling the app that created the box, because box storage is private to the app that created it. So, both the app ID and the box name must appear in the same transaction. If the top-level transaction is a call to the app that created the box, then that app ID is implicitly in the apps array at position 0.