Algorand Virtual Machine
A bytecode-based stack interpreter that executes programs associated with Algorand transactions
What is the AVM?
The AVM is a bytecode based stack interpreter that executes programs associated with Algorand transactions. TEAL is an assembly language syntax for specifying a program that is ultimately converted to AVM bytecode. These programs can be used to check the parameters of a transaction and approve the transaction as if by a signature.
This use is called a Logic Signature. Starting with v2, these programs may also execute as Smart Contracts, which are often called Applications. Contract executions are invoked with explicit application call transactions.
Programs have read-only access to the transaction they are attached to, the other transactions in their atomic transaction group, and a few global values. In addition, Smart Contracts have access to limited state that is global to the application, per-account local state for each account that has opted-in to the application, and additional per-application arbitrary state in named boxes.
Execution Modes
Starting from v2, the AVM can run programs in two distinct modes:
LogicSig Mode
Stateless mode used to execute Logic Signatures
- • Max program length: LogicSigMaxSize
- • Max program cost: LogicSigMaxCost
- • Limited opcode availability
- • No access to changing global values
Application Mode
Stateful mode used to execute Smart Contracts
- • Max program length: MaxAppTotalProgramLen
- • Max program cost: MaxAppProgramCost
- • Full opcode availability
- • Access to blockchain state and changing values
The Stack
The stack starts empty and can contain values of either uint64 or byte-arrays (byte-arrays may not exceed 4096 bytes in length). Most operations act on the stack, popping arguments from it and pushing results to it.
Stack Limitations:
- • Maximum stack depth: 1000
- • Maximum byte-array length: 4096 bytes
- • Program fails if limits are exceeded
- • Operations fail if trying to access non-existent stack positions
Stack Types
While the stack can only store two basic types of values - uint64 and bytes - these values are often bounded, meaning they have specific ranges or limits on what they can contain:
Boolean Values
uint64 that must be either 0 or 1
Address Values
Must be exactly 32 bytes long
Scratch Space
In addition to the stack there are 256 positions of scratch space. Like stack values, scratch locations may be uint64 or bytes. Scratch locations are initialized as uint64 zero.
Access Operations:
- •
load(s)- Move data from scratch space to stack - •
store(s)- Move data from stack to scratch space - •
gload(s)(s)- Inspect scratch space from earlier app calls in same group
Versions
In order to maintain existing semantics for previously written programs, AVM code is versioned. When new opcodes are introduced, or behavior is changed, a new version is introduced. Programs carrying old versions are executed with their original semantics.
In the AVM bytecode, the version is an incrementing integer and denoted vX throughout documentation.
Execution Environment for Logic Signatures
Logic Signatures execute as part of testing a proposed transaction to see if it is valid and authorized to be committed into a block. If an authorized program executes and finishes with a single non-zero uint64 value on the stack then that program has validated the transaction it is attached to.
Data Access
Transaction Data
Access via txn op
Group Data
Access via gtxn op
Global Values
Access via global op
Authorization Models
Delegated Authorization
Account signs the program with ed25519 or multisignature. Transaction is authorized if program returns true. Allows delegated actions approved by the program.
Contract Account
SHA512_256 hash of program (prefixed by "Program") equals the authorizer address. Contract account wholly controlled by the program.
Important Note
Logic Signature Args are recorded on the blockchain and publicly visible when the transaction is submitted, even before inclusion in a block. Args are not part of the transaction ID or TxGroup hash.
Execution Environment for Smart Contracts
Smart Contracts are executed in ApplicationCall transactions. Like Logic Signatures, contracts indicate success by leaving a single non-zero integer on the stack. A failed Smart Contract call to an ApprovalProgram is not a valid transaction, thus not written to the blockchain.
Enhanced Capabilities
State Access
- • Blockchain state (balances)
- • Contract state (own and others)
- • Global application state
- • Per-account local state
- • Named boxes for arbitrary state
Dynamic Values
- • Time-changing global values
- • Transaction effects observation
- • Logs and allocated IDs
- • ASA and Application creation
Cost Management
Execution Cost Limits
Smart contracts have limits on their execution cost (700, consensus parameter MaxAppProgramCost).
- • Before v4: Static limit on all instruction costs
- • Starting v4: Dynamic cost tracking during execution
- • Beginning v5: Pooled costs across app executions in group
- • v6: Inner application calls increase pooled budget
ClearStateProgram Execution
More stringent execution to ensure applications can be closed out while allowing cleanup. Requires MaxAppProgramCost budget at start, limited to MaxAppProgramCost during execution.
Resource Availability
Smart contracts have limits on the amount of blockchain state they may examine. Opcodes may only access blockchain resources such as Accounts, Assets, Boxes, and contract state if the given resource is available.
Available Resources
Always Available
- •
txn.Sender - •
global CurrentApplicationID - •
global CurrentApplicationAddress
Foreign Array Resources
- • Resources in
txn.Accounts - • Resources in
txn.ForeignAssets - • Resources in
txn.ForeignApplications
Group-Level Resource Sharing (v9+)
Any resource available in some top-level transaction in a transaction group is available in all v9 or later application calls in the group.
Transaction Type Resources
Payment (pay)
Sender, Receiver, CloseRemainderTo
Asset Transfer (axfer)
Sender, AssetReceiver, AssetSender, AssetCloseTo, XferAsset holdings
Asset Config (acfg)
Sender, ConfigAsset, ConfigAsset holding of Sender
Asset Freeze (afrz)
Sender, FreezeAccount, FreezeAsset holdings
Constants
Constants can be pushed onto the stack in two different ways for optimal efficiency:
Direct Push
More efficient for constants used only once
pushint 1234
pushbytes 0xcafed00dConstant Blocks
More efficient for constants used multiple times
intcblock
bytecblock
intc, intc_[0123]
bytec, bytec_[0123]Assembler Optimization
The assembler automatically optimizes constant usage, allowing simple use of int 1234 and byte 0xcafed00d. Constants are assembled into appropriate opcodes to minimize program size.
Operations
Most operations work with only one type of argument, uint64 or bytes, and fail if the wrong type value is on the stack.
Value Designation
Many instructions accept values to designate Accounts, Assets, or Applications. Beginning with v4, these values may be given as:
Offset Method
Offset in corresponding Txn fields (Txn.Accounts, Txn.ForeignAssets, Txn.ForeignApps)
Direct Value
The value itself (byte-array address for Accounts, uint64 ID for Assets/Apps)
Stack Argument Convention
In opcode documentation, stack arguments are referred to alphabetically, beginning with the deepest argument as A:
- • Arguments are popped from stack and results pushed to it
- • Type requirements are specified for each opcode
- • Operations fail if specified type is incorrect
- • Multiple results are named for clarity concerning stack positions
Operation Failures
Critical Failures
- • Some operations immediately fail the program
- • A transaction checked by a failed program is not valid
- • Stack underflow (accessing non-existent stack positions)
- • Type mismatches for opcode requirements
- • Exceeding stack depth or byte-array size limits
What AVM Programs Cannot Do
While the AVM is powerful and flexible, there are important limitations designed to ensure security, determinism, and network performance:
Network and External Access
- • Cannot make HTTP requests or access external APIs
- • Cannot access the internet or external data sources
- • Cannot communicate with other blockchains directly
- • No file system access or local storage
Non-Deterministic Operations
- • Cannot generate true random numbers (must use VRF or external randomness)
- • Cannot access current wall-clock time (only block timestamps)
- • Cannot perform floating-point arithmetic
- • No access to system-specific information
Resource and Performance Limits
- • Cannot exceed opcode budget limits
- • Cannot create infinite loops or unbounded recursion
- • Limited memory and storage access
- • Cannot access arbitrary blockchain state without proper references
State and Transaction Limitations
- • Cannot modify past transactions or blocks
- • Cannot directly transfer Algos or assets (must use inner transactions)
- • Cannot access private keys or perform arbitrary cryptographic operations
- • Limited to predefined transaction types and operations
Programming Model Constraints
- • No dynamic memory allocation
- • No garbage collection or automatic memory management
- • Limited data types (only uint64 and bytes)
- • No object-oriented programming constructs
Design Philosophy
These limitations are intentional design choices that ensure AVM programs are deterministic, secure, and efficient. They prevent common smart contract vulnerabilities while maintaining high performance and predictable execution costs.
