Skip to content

Control Flow

Control flow in Algorand smart contracts follows common programming paradigms, with support for if statements, while loops, for loops, and switch/match statements. Both Algorand Python and Algorand TypeScript provide familiar syntax for these constructs.

If statements

If statements work as you would expect in any programming language. The conditions must be an expression that evaluates to a boolean.

/**
* Determines if an account is rich based on its balance
* @param accountBalance The account balance to check
* @returns A string describing the account's wealth status
*/
@arc4.abimethod({ readonly: true })
public isRich(accountBalance: uint64): string {
if (accountBalance > 1000) {
return 'This account is rich!'
} else if (accountBalance > 100) {
return 'This account is doing well.'
} else {
return 'This account is poor :('
}
}

Ternary conditions

Ternary conditions allow for compact conditional expressions. The condition must be an expression that evaluates to a boolean.

/**
* Determines if a number is even or odd
* @param number The number to check
* @returns "Even" if the number is even, "Odd" otherwise
*/
@arc4.abimethod({ readonly: true })
public isEven(number: uint64): string {
return number % 2 === 0 ? 'Even' : 'Odd'
}

While loops

While loops iterate as long as the specified condition is true. The condition must be an expression that evaluates to a boolean.

You can use break and continue statements to control loop execution.

/**
* Demonstrates while loop with continue and break statements
* @returns The number of iterations performed
*/
@arc4.abimethod({ readonly: true })
public loop(): uint64 {
let num: uint64 = 10
let loopCount: uint64 = 0
while (num > 0) {
if (num > 5) {
num -= 1
loopCount += 1
continue
}
num -= 2
loopCount += 1
if (num === 1) {
break
}
}
return loopCount
}

For Loops

For loops are used to iterate over sequences, ranges and ARC-4 arrays.

In Algorand Python, utility functions like uenumerate and urange facilitate creating sequences and ranges of UInt64 numbers, and the built-in reversed method works with these. In Algorand TypeScript, standard iteration constructs are available.

Here is an example of how you can use For loops in smart contracts:

/**
* Demonstrates different types of for loops
* @returns An array of uint64 values in reversed order
*/
@arc4.abimethod({ readonly: true })
public forLoop(): uint64[] {
// Create an array with values [0, 1, 2, 3]
let numbers: uint64[] = []
// Use for-of loop with urange to fill the array
for (const item of urange(4)) {
numbers = [...numbers, item]
}
// Create a reversed array [3, 2, 1, 0]
let reversed: uint64[] = []
// Reverse the array by prepending each element
// This demonstrates another way to use for-of loops
for (const num of numbers) {
// Add each new element to the beginning of the array
reversed = [num, ...reversed]
}
// Sum all values in the reversed array
let sum: uint64 = 0
for (const num of reversed) {
sum += num
}
// The sum should be 0 + 1 + 2 + 3 = 6
assert(sum === 6, 'Sum of reversed array should be 6')
return reversed
}

Switch or Match Statements

switch for TypeScript and match for Python provide a clean way to handle multiple conditions. They follow the standard syntax of their respective languages.

/**
* Returns the day of the week based on a numeric input
* @param date A number from 0-6 representing a day of the week
* @returns The name of the day, or "Invalid day" if out of range
*/
@arc4.abimethod({ readonly: true })
public getDay(date: uint64): string {
switch (Uint64(date)) {
case Uint64(1):
return 'Monday'
case Uint64(2):
return 'Tuesday'
case Uint64(3):
return 'Wednesday'
case Uint64(4):
return 'Thursday'
case Uint64(5):
return 'Friday'
case Uint64(6):
return 'Saturday'
case Uint64(7):
return 'Sunday'
default:
return 'Invalid day'
}
}

Note: Captures and patterns are not supported. Currently, there is only support for basic case/switch functionality; pattern matching and guard clauses are not currently supported.

TEAL Flow Control Opcode

Algorand Python and TypeScript are high-level smart contract languages that allow developers to express control flows in more accessible languages. However, the Algorand Virtual Machine (AVM) executes the Transaction Execution Approval Language (TEAL) flow control opcodes after compilation. TEAL is a low-level assembly language that the AVM understands directly. While developers will write smart contracts in higher-level languages, understanding the underlying TEAL opcodes can be beneficial to comprehend what’s happening line by line. The following chart contains all of the control flow opcodes available in TEAL.

OpcodeDescription
errFail immediately.
bnz targetbranch to TARGET if value A is not zero
bz targetbranch to TARGET if value A is zero
b targetbranch unconditionally to TARGET
returnuse A as success value; end
popdiscard A
popn nremove N values from the top of the stack
dupduplicate A
dup2duplicate A and B
dupn nduplicate A, N times
dig nNth value from the top of the stack. dig 0 is equivalent to dup
bury nreplace the Nth value from the top of the stack with A. bury 0 fails.
cover nremove top of stack, and place it deeper in the stack such that N elements are above it. Fails if stack depth <= N.
uncover nremove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack. Fails if stack depth <= N.
frame_dig iNth (signed) value from the frame pointer.
frame_bury ireplace the Nth (signed) value from the frame pointer in the stack with A
swapswaps A and B on stack
selectselects one of two values based on top-of-stack: B if C != 0, else A
assertimmediately fail unless A is a non-zero number
callsub targetbranch unconditionally to TARGET, saving the next instruction on the call stack
proto a rPrepare top call frame for a retsub that will assume A args and R return values.
retsubpop the top instruction from the call stack and branch to it
switch target …branch to the Ath label. Continue at following instruction if index A exceeds the number of labels.
match target …given match cases from A[1] to A[N], branch to the Ith label where A[I] = B. Continue to the following instruction if no matches are found.