Arweave AO Lua Programming Guide
Arweave AO (Actor Oriented) uses the Lua programming language to describe processes. This article explains the basic syntax for writing Lua in AO and AO-specific patterns. Variables and Data Types Basic Variable Declaration -- Global variables MyVariable = "Hello World" Counter = 42 IsActive = true -- Local variables local localVar = "Local variable" local number = 123 Data Types Lua is a dynamically typed language that supports the following data types: -- Numeric types local integer = 42 local float = 3.14 local scientific = 1.23e-4 -- String types local str1 = "Double quotes" local str2 = 'Single quotes' local multiline = [[ Multi-line strings are possible ]] -- Boolean values local isTrue = true local isFalse = false -- nil (undefined value) local nothing = nil Tables (Arrays and Dictionaries) Lua tables are flexible data structures that function as both arrays and dictionaries. Arrays -- Arrays (indices start from 1) local fruits = {"apple", "banana", "orange"} print(fruits[1]) -- "apple" print(#fruits) -- 3 (array length) Dictionaries (Associative Arrays) -- Dictionary local person = { name = "John", age = 25, active = true } -- Access methods print(person.name) -- "John" print(person["age"]) -- 25 Composite Tables -- Mixed arrays and dictionaries local mixed = { "first", -- [1] "second", -- [2] name = "Mixed", -- ["name"] count = 100 -- ["count"] } -- Nested tables local config = { database = { host = "localhost", port = 5432, credentials = { username = "admin", password = "secret" } } } Functions Basic Function Definition -- Regular function function greet(name) return "Hello, " .. name end -- Local function local function add(a, b) return a + b end -- Anonymous function local multiply = function(x, y) return x * y end Advanced Function Features -- Multiple return values function getCoordinates() return 10, 20 end local x, y = getCoordinates() -- Variable arguments function sum(...) local args = {...} local total = 0 for i = 1, #args do total = total + args[i] end return total end -- Usage example local result = sum(1, 2, 3, 4, 5) -- 15 Control Structures Conditional Statements local score = 85 if score >= 90 then print("Excellent") elseif score >= 70 then print("Good") else print("Needs improvement") end Loop Processing -- Numeric loop for i = 1, 10 do print("Count: " .. i) end -- Reverse loop for i = 10, 1, -1 do print(i) end -- Array iteration local items = {"a", "b", "c"} for i = 1, #items do print(i, items[i]) end -- Key-value pair iteration (all elements) local data = {name = "John", age = 30, city = "Tokyo"} for key, value in pairs(data) do print(key, value) end -- Array-specific iteration (consecutive indices only) for index, value in ipairs(items) do print(index, value) end -- while statement local count = 0 while count = amount end -- Balance inquiry handler Handlers.add( "balance", Handlers.utils.hasMatchingTag("Action", "Balance"), function(msg) local account = msg.Tags.Account or msg.From local balance = Balances[account] or 0 ao.send({ Target = msg.From, Tags = { Action = "Balance-Response", Account = account, Balance = tostring(balance) } }) end ) -- Transfer handler Handlers.add( "transfer", Handlers.utils.hasMatchingTag("Action", "Transfer"), function(msg) local from = msg.From local to = msg.Tags.To local amount = tonumber(msg.Tags.Amount) -- Validation if not to or not amount or amount

Arweave AO (Actor Oriented) uses the Lua programming language to describe processes. This article explains the basic syntax for writing Lua in AO and AO-specific patterns.
Variables and Data Types
Basic Variable Declaration
-- Global variables
MyVariable = "Hello World"
Counter = 42
IsActive = true
-- Local variables
local localVar = "Local variable"
local number = 123
Data Types
Lua is a dynamically typed language that supports the following data types:
-- Numeric types
local integer = 42
local float = 3.14
local scientific = 1.23e-4
-- String types
local str1 = "Double quotes"
local str2 = 'Single quotes'
local multiline = [[
Multi-line
strings are possible
]]
-- Boolean values
local isTrue = true
local isFalse = false
-- nil (undefined value)
local nothing = nil
Tables (Arrays and Dictionaries)
Lua tables are flexible data structures that function as both arrays and dictionaries.
Arrays
-- Arrays (indices start from 1)
local fruits = {"apple", "banana", "orange"}
print(fruits[1]) -- "apple"
print(#fruits) -- 3 (array length)
Dictionaries (Associative Arrays)
-- Dictionary
local person = {
name = "John",
age = 25,
active = true
}
-- Access methods
print(person.name) -- "John"
print(person["age"]) -- 25
Composite Tables
-- Mixed arrays and dictionaries
local mixed = {
"first", -- [1]
"second", -- [2]
name = "Mixed", -- ["name"]
count = 100 -- ["count"]
}
-- Nested tables
local config = {
database = {
host = "localhost",
port = 5432,
credentials = {
username = "admin",
password = "secret"
}
}
}
Functions
Basic Function Definition
-- Regular function
function greet(name)
return "Hello, " .. name
end
-- Local function
local function add(a, b)
return a + b
end
-- Anonymous function
local multiply = function(x, y)
return x * y
end
Advanced Function Features
-- Multiple return values
function getCoordinates()
return 10, 20
end
local x, y = getCoordinates()
-- Variable arguments
function sum(...)
local args = {...}
local total = 0
for i = 1, #args do
total = total + args[i]
end
return total
end
-- Usage example
local result = sum(1, 2, 3, 4, 5) -- 15
Control Structures
Conditional Statements
local score = 85
if score >= 90 then
print("Excellent")
elseif score >= 70 then
print("Good")
else
print("Needs improvement")
end
Loop Processing
-- Numeric loop
for i = 1, 10 do
print("Count: " .. i)
end
-- Reverse loop
for i = 10, 1, -1 do
print(i)
end
-- Array iteration
local items = {"a", "b", "c"}
for i = 1, #items do
print(i, items[i])
end
-- Key-value pair iteration (all elements)
local data = {name = "John", age = 30, city = "Tokyo"}
for key, value in pairs(data) do
print(key, value)
end
-- Array-specific iteration (consecutive indices only)
for index, value in ipairs(items) do
print(index, value)
end
-- while statement
local count = 0
while count < 5 do
print("Count: " .. count)
count = count + 1
end
AO-Specific Syntax
AO has several special rules in addition to regular Lua.
Persisted Variables
-- Global variables starting with capital letters are automatically persisted
PersistentData = PersistentData or {}
TotalSupply = 1000000
Balances = Balances or {}
-- Conditional initialization pattern (for process restart compatibility)
if not Owner then
Owner = ao.env.Process.Owner
end
AO Built-in Functions
-- Message sending
ao.send({
Target = "ProcessID",
Tags = {
Action = "Transfer",
Amount = "100"
},
Data = "Additional data"
})
-- Environment variable access
local processId = ao.id
local owner = ao.env.Process.Owner
Message Handlers
AO's characteristic message processing system.
Basic Handler
Handlers.add(
"balance_check", -- Handler name
Handlers.utils.hasMatchingTag("Action", "Balance"), -- Condition
function(msg) -- Processing function
local account = msg.Tags.Account or msg.From
local balance = Balances[account] or 0
ao.send({
Target = msg.From,
Tags = {
Action = "Balance-Response",
Balance = tostring(balance)
}
})
end
)
Handlers with Complex Conditions
-- Custom condition function
local function isValidTransfer(msg)
return msg.Tags.Action == "Transfer" and
msg.Tags.To and
msg.Tags.Amount and
tonumber(msg.Tags.Amount) > 0
end
Handlers.add(
"transfer",
isValidTransfer,
function(msg)
local from = msg.From
local to = msg.Tags.To
local amount = tonumber(msg.Tags.Amount)
-- Transfer processing
if Balances[from] and Balances[from] >= amount then
Balances[from] = Balances[from] - amount
Balances[to] = (Balances[to] or 0) + amount
ao.send({
Target = msg.From,
Tags = { Action = "Transfer-Success" }
})
else
ao.send({
Target = msg.From,
Tags = { Action = "Transfer-Error", Error = "Insufficient balance" }
})
end
end
)
Common Patterns
Safe Type Conversion
-- Safe numeric conversion
local function safeToNumber(value, default)
local num = tonumber(value)
return num and num or (default or 0)
end
-- Safe string conversion
local function safeToString(value)
return tostring(value or "")
end
Validation Functions
local function validateTransfer(from, to, amount)
-- Sender/recipient check
if not from or not to or from == to then
return false, "Invalid sender or recipient"
end
-- Amount check
local numAmount = tonumber(amount)
if not numAmount or numAmount <= 0 then
return false, "Invalid amount"
end
-- Balance check
if not Balances[from] or Balances[from] < numAmount then
return false, "Insufficient balance"
end
return true, numAmount
end
-- Usage example
local isValid, amountOrError = validateTransfer(msg.From, msg.Tags.To, msg.Tags.Amount)
if not isValid then
ao.send({
Target = msg.From,
Tags = { Action = "Error", Message = amountOrError }
})
return
end
Utility Functions
-- Table copying
local function deepCopy(original)
local copy = {}
for key, value in pairs(original) do
if type(value) == "table" then
copy[key] = deepCopy(value)
else
copy[key] = value
end
end
return copy
end
-- Check if table is empty
local function isEmpty(tbl)
return next(tbl) == nil
end
-- Search for element in array
local function findInArray(array, value)
for i, v in ipairs(array) do
if v == value then
return i
end
end
return nil
end
Error Handling
pcall (Protected Call)
-- Safe function execution
local success, result = pcall(function()
return someRiskyFunction()
end)
if success then
print("Success: " .. tostring(result))
else
print("Error: " .. tostring(result))
end
assert
-- Condition check
local function divide(a, b)
assert(type(a) == "number", "First argument must be a number")
assert(type(b) == "number", "Second argument must be a number")
assert(b ~= 0, "Cannot divide by zero")
return a / b
end
Custom Error Handling
local function safeExecute(func, errorHandler)
local success, result = pcall(func)
if success then
return result
else
if errorHandler then
return errorHandler(result)
else
print("An error occurred: " .. tostring(result))
return nil
end
end
end
-- Usage example
local result = safeExecute(
function() return calculateSomething() end,
function(error) return "Calculation failed: " .. error end
)
Practical Example: Simple Token Contract
Here's a practical example combining the knowledge covered so far:
-- Token basic information
TokenName = "MyToken"
TokenSymbol = "MTK"
TotalSupply = 1000000
Balances = Balances or {}
-- Initialization
if not Owner then
Owner = ao.env.Process.Owner
Balances[Owner] = TotalSupply
end
-- Utility functions
local function hasBalance(account, amount)
return Balances[account] and Balances[account] >= amount
end
-- Balance inquiry handler
Handlers.add(
"balance",
Handlers.utils.hasMatchingTag("Action", "Balance"),
function(msg)
local account = msg.Tags.Account or msg.From
local balance = Balances[account] or 0
ao.send({
Target = msg.From,
Tags = {
Action = "Balance-Response",
Account = account,
Balance = tostring(balance)
}
})
end
)
-- Transfer handler
Handlers.add(
"transfer",
Handlers.utils.hasMatchingTag("Action", "Transfer"),
function(msg)
local from = msg.From
local to = msg.Tags.To
local amount = tonumber(msg.Tags.Amount)
-- Validation
if not to or not amount or amount <= 0 then
ao.send({
Target = from,
Tags = { Action = "Transfer-Error", Error = "Invalid parameters" }
})
return
end
if not hasBalance(from, amount) then
ao.send({
Target = from,
Tags = { Action = "Transfer-Error", Error = "Insufficient balance" }
})
return
end
-- Execute transfer
Balances[from] = Balances[from] - amount
Balances[to] = (Balances[to] or 0) + amount
ao.send({
Target = from,
Tags = {
Action = "Transfer-Success",
From = from,
To = to,
Amount = tostring(amount)
}
})
end
)
Summary
Lua programming in AO requires understanding the following key points in addition to regular Lua knowledge:
- Persistence concept: Automatic persistence of global variables starting with capital letters
- Message-driven architecture: Asynchronous processing using Handlers
- State management: Conditional initialization for process restart compatibility
- Error handling: Robust error handling in distributed environments
Understanding these concepts enables you to build efficient and secure processes on the AO platform. While AO's distributed computing environment requires asynchronous, message-based thinking that differs from traditional synchronous programming, Lua's simple syntax helps reduce that complexity.