Skip to content
This new developer portal is under construction. For complete documentation, please refer to the old developer portal.

Resource Usage

Algorand smart contracts do not have default access to the entire blockchain ledger. Therefore, when a smart contract method needs to access resources such as accounts, assets (ASA), other applications (smart contracts), or box references, these must be provided through the reference (foreign) array during invocation. This page explains what reference arrays are, why they are necessary, the different ways to provide them, and includes a series of code examples.

Resource Availability

When smart contracts are executed, they may require data stored within the blockchain ledger for evaluation. For this data (resource) to be accessible to the smart contract, it must be made available. When you say, ‘A resource is available to the smart contract,’ it means that the reference array, referencing the resource, was provided during the invocation and execution of a smart contract method that requires access to that resource.

What are Reference Arrays?

There are four reference arrays:

  • Accounts(link to accounts page): Reference to Algorand accounts
  • assets(ASAs)(link to assets page): Reference to Algorand Standard Assets
  • applications(smart contracts)(link to app page): Reference to an external smart contract
  • Boxes(link to box page): Reference to Boxes created within the smart contract

Including necessary resources in the appropriate arrays enables the smart contract to access the necessary data during execution, such as reading an account’s Algo balance or examining the immutable properties of an ASA. This page explains how data access is managed by a smart contract in version 9 or later of the Algorand Virtual Machine (AVM). For details on earlier AVM versions, refer to the TEAL specification

By default, the reference arrays are empty, with the exception of the accounts and applications arrays. The Accounts array contains the transaction sender’s address, and the Applications array contains the called smart contract ID.

Types of Resources to make available

Using these four reference arrays, you can make the following six unique ledger items available during smart contract execution: account, asset, application, account+asset, account+application, and application+box. Accounts and Applications can contain sublists with potentially large datasets. For example, an account may opt into an extensive set of assets or applications (which store the user’s local state). Additionally, smart contracts can store potentially unlimited boxes of data within the ledger. For instance, a smart contract might create a unique box of arbitrary data for each user. Combinations like account+asset, account+application, and application+box refer to cases accessing the sublist resources. For example:

  • Account+Asset: To read what the balance of an asset is for a specific account, both the asset and the account reference must be included in the respective reference arrays.
  • Account+Application: To access an account’s local state of an application, both the account and the application reference must be included in the respective reference arrays.
  • Application+Box: To retrieve data from a specific box created by an application, the application and the box reference must be included in the respective reference arrays.

Inner Transaction Resource Availability

Inner transactions within a contract have access to the contract’s resource availability. So if a smart contract has an inner transaction calling another smart contract, the inner contract automatically inherits the resource availability of the top-level smart contract. For example, if contract A sends an inner transaction to call a method in contract B that requires access to asset XYZ, providing a reference to asset XYZ when calling contract A allows contract B to share the resource availability of contract A and access asset XYZ.

Reference Array Constraints and Requirements

There are certain limitations and requirements you need to consider when providing references in the reference arrays:

  • The four reference arrays are limited to a combined total of eight values per application transaction. (This limit excludes the default references to the transaction sender’s address and the called smart contract ID)
  • The accounts array can contain no more than four accounts.
  • The values passed into the reference arrays can change per application transaction.
  • When accessing one of the sublists of items, the application transaction must include both the top-level item and the nested list item within the same call. For example, to read an ASA balance for a specific account, the account and the asset must be present in the respective accounts and asset arrays for the given transaction.

Reason for limited access to resources

To maintain a high level of performance, the AVM restricts how much of the ledger can be viewed within a single contract execution. This is implemented with reference arrays passed with each application call transaction, defining the specific ledger items available during execution. These arrays are the Account, Asset, Application, and Boxes arrays.

Resource Sharing

Resources are shared across transactions within the same atomic group. This means that if there are two app calls calling different smart contracts in the same atomic group, the two smart contracts share resource availability.

For example, say you have two smart contract call transactions grouped together, transaction #1 and transaction #2. Transaction #1 has asset 123456 in its assets array, and transaction #2 has asset 555555 in its assets array. Both assets are available to both smart contract calls during evaluation.

When accessing a sublist resource (account+asa, account+application local state, application+box), both resources must be in the same transaction’s arrays. For example, you cannot have account A in transaction #1 and asset Z in transaction #2 and then try to get the balance of asset Z for account A. Asset Z and account A must be in the same application transaction. If asset Z and account A are in transaction #1’s arrays, A’s balance for Z is also available to transaction #2 during evaluation.

Because Algorand supports grouping up to 16 transactions simultaneously, this pushes the available resources up to 8x16 or 128 items if all 16 transactions are application transactions.

If an application transaction is grouped with other types of transactions, other resources will be made available to the smart contract called in the application transaction. For example, if an application transaction is grouped with a payment transaction, the payment transaction’s sender and receiver accounts are available to the smart contract.

If the CloseRemainderTo field is set, that account will also be available to the smart contract. The table below summarizes what each transaction type adds to resource availability.

TransactionTransaction TypeAvailability Notes
Paymentpaytxn.Sender, txn.Receiver, and txn.CloseRemainderTo (if set)
Key Registrationkeyregtxn.Sender
Asset Config/Createacfgtxn.Sender, txn.ConfigAsset, and the txn.ConfigAsset holding of txn.Sender
Asset Transferaxfertxn.Sender, txn.AssetReceiver, txn.AssetSender (if set), txnAssetCloseTo (if set), txn.XferAsset, and the txn.XferAsset holding of each of those accounts
Asset Freezeafrztxn.Sender, txn.FreezeAccount, txn.FreezeAsset, and the txn.FreezeAsset holding of txn.FreezeAccount. The txn.FreezeAsset holding of txn.Sender is not made available

Different ways to provide references

There are different ways you can provide resource references when calling smart contract methods:

  1. Automatic Resource Population: Automatically input resource references in the reference(foreign) arrays with automatic resource population using the AlgoKit Utils library (TypeScript and Python)

  2. Reference Types: Pass reference types as arguments to contract methods. (You can only do this for Accounts, Assets, and Applications and not Boxes.)

  3. Manually Input: Manually input resource references in the reference(foreign) arrays

Account reference example

Here is a simple smart contract with two methods that read the balance of an account. This smart contract requires the account reference to be provided during invocation.

1
from algopy import ARC4Contract, UInt64, Account
2
from algopy.arc4 import abimethod
3
4
5
class AccountReference(ARC4Contract):
6
7
@abimethod
8
def get_account_balance(self) -> UInt64:
9
return Account(
10
"WMHF4FLJNKY2BPFK7YPV5ID6OZ7LVDB2B66ZTXEAMLL2NX4WJZRJFVX66M"
11
).balance # Replace with your account address
12
13
@abimethod
14
def get_account_balance_with_arg(self, acct: Account) -> UInt64:
15
return acct.balance

Here are three different ways you can provide the account reference when calling a contract method using the AlgoKit Utils library.

Method #1: Automatic Resource Population

1
// Configurate automatic resource population per app call
2
const response = await AccountReferenceAppClient.getAccountBalance({}, { sendParams: { populateAppCallResources: true } })
3
console.log('Method #2 Account Balance', response.return)
4
5
// OR
6
7
// Set the default value for populateAppCallResources to true once and apply to all contract invocations
8
algokit.Config.configure({ populateAppCallResources: true })
9
10
const response = await AccountReferenceAppClient.getAccountBalance({})
11
console.log('Method #2 Account Balance', response.return)

Method #2: Using Reference Types

1
const response = await AccountReferenceAppClient.getAccountBalanceWithArg({ acct: alice.addr })
2
console.log('Method #3 Account Balance', response.return)

Method #3: Manually Input

1
const response = await AccountReferenceAppClient.getAccountBalance({}, { accounts: [alice.addr] })
2
console.log('Method #1 Account Balance', response.return)

Asset reference example

Here is a simple smart contract with two methods that read the total supply of an asset(ASA). This smart contract requires the asset reference to be provided during invocation.

1
from algopy import ARC4Contract, UInt64, Asset
2
from algopy.arc4 import abimethod
3
4
5
class AssetReference(ARC4Contract):
6
7
@abimethod
8
def get_asset_total_supply(self) -> UInt64:
9
return Asset(1185).total # Replace with your asset id
10
11
@abimethod
12
def get_asset_total_supply_with_arg(self, asa: Asset) -> UInt64:
13
return asa.total

Here are three different ways you can provide the asset reference when calling a contract method using the AlgoKit Utils library.

Method #1: Automatic Resource Population

1
// Configurate automatic resource population per app call
2
const response = await AssetRefAppClient.getAssetTotalSupply({}, { sendParams: { populateAppCallResources: true } })
3
console.log('Method #2 Asset Total Supply', response.return)
4
5
// OR
6
7
// Set the default value for populateAppCallResources to true once and apply to all contract invocations
8
algokit.Config.configure({ populateAppCallResources: true })
9
10
const response = await AssetRefAppClient.getAssetTotalSupply({})
11
console.log('Method #2 Asset Total Supply', response.return)

Method #2: Using Reference Types

1
const response = await AssetRefAppClient.getAssetTotalSupplyWithArg({ asa: assetId })
2
console.log('Method #3 Asset Total Supply', response.return)

Method #3: Manually Input

1
const response = await AssetRefAppClient.getAssetTotalSupply({}, { assets: [Number(assetId)] })
2
console.log('Method #1 Asset Total Supply', response.return)

App reference example

Here is a simple smart contract named ApplicationReference with two methods that call the increment method in the Counter smart contract via inner transaction. The ApplicationReference smart contract requires the Counter application reference to be provided during invocation.

1
from algopy import ARC4Contract, UInt64, Application, arc4
2
from algopy.arc4 import abimethod
3
4
5
class Counter(ARC4Contract):
6
7
def __init__(self) -> None:
8
self.counter = UInt64(0)
9
10
@abimethod
11
def increment(self) -> UInt64:
12
self.counter += 1
13
return self.counter
14
15
16
class ApplicationReference(ARC4Contract):
17
18
@abimethod
19
def increment_via_inner(self) -> UInt64:
20
app = Application(1717) # Replace with your application id
21
22
counter_result, call_txn = arc4.abi_call(
23
Counter.increment,
24
fee=0,
25
app_id=app,
26
)
27
return counter_result
28
29
@abimethod
30
def increment_via_inner_with_arg(self, app: Application) -> UInt64:
31
counter_result, call_txn = arc4.abi_call(Counter.increment, fee=0, app_id=app)
32
return counter_result

Here are three different ways you can provide the app reference when calling a contract method using the AlgoKit Utils library.

Method #1: Automatic Resource Population

1
// Configurate automatic resource population per app call
2
const response = await AppRefAppClient.incrementViaInner(
3
{},
4
{ sendParams: { populateAppCallResources: true, fee: algokit.algos(0.002) } }, // doubling the fee to cover inner txn
5
)
6
console.log('Method #2 Increment via inner', response.return)
7
8
// OR
9
10
// Set the default value for populateAppCallResources to true once and apply to all contract invocations
11
algokit.Config.configure({ populateAppCallResources: true })
12
13
const response = await AppRefAppClient.incrementViaInner(
14
{},
15
{ sendParams: { fee: algokit.algos(0.002) } }, // doubling the fee to cover inner txn
16
)
17
console.log('Method #2 Increment via inner', response.return)

Method #2: Using Reference Types

1
const response = await AppRefAppClient.incrementViaInnerWithArg(
2
{ app: counterAppId },
3
{ sendParams: { fee: algokit.algos(0.002) } }, // doubling the fee to cover inner txn
4
)
5
console.log('Method #3 Increment via inner', response.return)

Method #3: Manually Input

1
const response = await AppRefAppClient.incrementViaInner(
2
{},
3
{ apps: [Number(counterAppId)], sendParams: { fee: algokit.algos(0.002) } }, // doubling the fee to cover inner txn
4
)
5
console.log('Method #1 Increment via inner', response.return)

Account + Asset example

Here is a simple smart contract with two methods that read the balance of an ASA in an account. This smart contract requires both the asset reference and the account reference to be provided during invocation.

1
from algopy import UInt64, Account, Asset, op, ARC4Contract
2
from algopy.arc4 import abimethod
3
4
5
class AccountAndAssetReference(ARC4Contract):
6
7
@abimethod
8
def get_asset_balance(self) -> UInt64:
9
acct = Account(
10
"WMHF4FLJNKY2BPFK7YPV5ID6OZ7LVDB2B66ZTXEAMLL2NX4WJZRJFVX66M"
11
) # Replace with your account address
12
asset = Asset(1185) # Replace with your asset id
13
balance, has_value = op.AssetHoldingGet.asset_balance(acct, asset)
14
15
if has_value:
16
return balance
17
return UInt64(0)
18
19
@abimethod
20
def get_asset_balance_with_arg(self, acct: Account, asset: Asset) -> UInt64:
21
balance, has_value = op.AssetHoldingGet.asset_balance(acct, asset)
22
23
if has_value:
24
return balance
25
return UInt64(0)

Here are three different ways you can provide both the account reference and the asset reference when calling a contract method using the AlgoKit Utils library.

Method #1: Automatic Resource Population

1
// Configurate automatic resource population per app call
2
const response = await AccountAndAssetRefAppClient.getAssetBalance(
3
{},
4
{ sendParams: { populateAppCallResources: true } },
5
)
6
console.log('Method #2 Asset Balance', response.return)
7
8
// OR
9
10
// Set the default value for populateAppCallResources to true once and apply to all contract invocations
11
algokit.Config.configure({ populateAppCallResources: true })
12
13
const response = await AccountAndAssetRefAppClient.getAssetBalance({})
14
console.log('Method #2 Asset Balance', response.return)

Method #2: Using Reference Types

1
const response = await AccountAndAssetRefAppClient.getAssetBalanceWithArg({ acct: alice.addr, asset: assetId })
2
console.log('Method #3 Asset Balance', response.return)

Method #3: Manually Input

1
const response = await AccountAndAssetRefAppClient.getAssetBalance({}, { assets: [Number(assetId)], accounts: [alice.addr] })
2
console.log('Method #1 Asset Balance', response.return)

Account + Application example

Here is a simple smart contract named AccountAndAppReference with two methods that read the local state my_counter of an account in the Counter smart contract. The AccountAndAppReference smart contract requires both the Counter application reference and the account reference to be provided during invocation.

1
from algopy import (
2
ARC4Contract,
3
UInt64,
4
Account,
5
Application,
6
op,
7
Txn,
8
LocalState,
9
Global,
10
)
11
from algopy.arc4 import abimethod
12
13
14
class Counter(ARC4Contract):
15
16
def __init__(self) -> None:
17
self.my_counter = LocalState(UInt64)
18
19
@abimethod(allow_actions=["OptIn"])
20
def opt_in(self) -> None:
21
self.my_counter[Txn.sender] = UInt64(0)
22
23
@abimethod
24
def increment_my_counter(self) -> UInt64:
25
assert Txn.sender.is_opted_in(Global.current_application_id)
26
27
self.my_counter[Txn.sender] += 1
28
return self.my_counter[Txn.sender]
29
30
31
class AccountAndAppReference(ARC4Contract):
32
33
@abimethod
34
def get_my_counter(self) -> UInt64:
35
acct = Account(
36
"WMHF4FLJNKY2BPFK7YPV5ID6OZ7LVDB2B66ZTXEAMLL2NX4WJZRJFVX66M"
37
) # Replace with your account address
38
app = Application(1717) # Replace with your application id
39
my_count, exist = op.AppLocal.get_ex_uint64(acct, app, b"my_counter")
40
if exist:
41
return my_count
42
return UInt64(0)
43
44
@abimethod
45
def get_my_counter_with_arg(self, acct: Account, app: Application) -> UInt64:
46
my_count, exist = op.AppLocal.get_ex_uint64(acct, app, b"my_counter")
47
if exist:
48
return my_count
49
return UInt64(0)

Here are three different ways you can provide both the account reference and the application reference when calling a contract method using the AlgoKit Utils library.

Method #1: Automatic Resource Population

1
// Configurate automatic resource population per app call
2
response = await AccountAndAppRefAppClient.getMyCounter({}, { sendParams: { populateAppCallResources: true } })
3
console.log('Method #2 My Counter', response.return)
4
5
// OR
6
7
// Set the default value for populateAppCallResources to true once and apply to all contract invocations
8
algokit.Config.configure({ populateAppCallResources: true })
9
10
response = await AccountAndAppRefAppClient.getMyCounter({})
11
console.log('Method #2 My Counter', response.return)

Method #2: Using Reference Types

1
response = await AccountAndAppRefAppClient.getMyCounterWithArg({ acct: alice.addr, app: counterAppId })
2
console.log('Method #3 My Counter', response.return)

Method #3: Manually Input

1
response = await AccountAndAppRefAppClient.getMyCounter({}, { accounts: [alice.addr], apps: [counterAppId] })
2
console.log('Method #1 My Counter', response.return)

Application + Box reference example

Here is a simple smart contract with a methods that increments the counter value stored in a BoxMap. Each box uses box_counter + account address as its key and stores the counter as its value. This smart contract requires the box reference to be provided during invocation.

1
from algopy import ARC4Contract, UInt64, Account, BoxMap, Txn, Global, gtxn
2
from algopy.arc4 import abimethod
3
4
COUNTER_BOX_KEY_LENGTH = 32 + 19
5
COUNTER_BOX_VALUE_LENGTH = 8
6
COUNTER_BOX_SIZE = COUNTER_BOX_KEY_LENGTH + COUNTER_BOX_VALUE_LENGTH
7
COUNTER_BOX_MBR = 2_500 + COUNTER_BOX_SIZE * 400
8
9
10
class BoxCounter(ARC4Contract):
11
12
def __init__(self) -> None:
13
self.account_box_counter = BoxMap(Account, UInt64)
14
15
@abimethod
16
def increment_box_counter(self, payMbr: gtxn.PaymentTransaction) -> UInt64:
17
assert payMbr.amount == COUNTER_BOX_MBR
18
assert payMbr.receiver == Global.current_application_address
19
20
if Txn.sender in self.account_box_counter:
21
self.account_box_counter[Txn.sender] += 1
22
else:
23
self.account_box_counter[Txn.sender] = 1
24
25
return self.account_box_counter[Txn.sender]

Here are two different ways you can provide the box reference when calling a contract method using the AlgoKit Utils library.

Method #1: Automatic Resource Population

1
const payMbr2 = await algorand.transactions.payment({
2
amount: algokit.microAlgos(boxMBR),
3
sender: alice.addr,
4
receiver: counterAppAddress,
5
})
6
7
const response = await AliceCounterClient.incrementBoxCounter(
8
{ payMbr: payMbr2 },
9
{ sendParams: { populateAppCallResources: true } },
10
)
11
console.log('Method #2 Box Counter', response.return)
12
13
// OR
14
15
// Set the default value for populateAppCallResources to true once and apply to all contract invocations
16
algokit.Config.configure({ populateAppCallResources: true })
17
18
const response = await AliceCounterClient.incrementBoxCounter({ payMbr: payMbr2 })
19
console.log('Method #2 Box Counter', response.return)

Method #2: Manually Input

1
const boxPrefix = 'account_box_counter' // box identifier prefix
2
const encoder = new TextEncoder()
3
const boxPrefixBytes = encoder.encode(boxPrefix) //UInt8Array of boxPrefix
4
const publicKey = decodeAddress(alice.addr).publicKey
5
6
const payMbr = await algorand.transactions.payment({
7
amount: algokit.microAlgos(boxMBR),
8
sender: alice.addr,
9
receiver: counterAppAddress,
10
})
11
12
const response = await AliceCounterClient.incrementBoxCounter(
13
{ payMbr: payMbr },
14
{ boxes: [new Uint8Array([...boxPrefixBytes, ...publicKey])] },
15
)
16
console.log('Method #1 Box Counter', response.return)