Skip to content

Language Basics

EVMcrispr uses a custom DSL (domain-specific language) designed for writing EVM transaction scripts. This guide covers the core syntax.

Lines starting with # are comments:

# This is a comment
set $x 42 # Inline comments work too

Commands are the primary building blocks. They produce transactions or control program flow. Each command starts with its name followed by arguments:

exec 0xAbC... "transfer(address,uint256)" @me 100e18
set $greeting "hello"
print "The value is" $x

Commands from non-default modules use a prefix:

load aragonos
aragonos:connect my-dao.aragonid.eth (
aragonos:grant @me voting CREATE_VOTES_ROLE
)

Helpers are expressions that produce values. They are prefixed with @:

@me # No arguments
@token(DAI) # Single argument
@get(0xAbC... "balanceOf(address)(uint256)" @me) # Multiple arguments

Helpers can be nested and used as arguments to commands:

exec @token(DAI) "transfer(address,uint256)" @me @token.amount(DAI 100)

Use set to assign values and $name to reference them:

set $recipient 0x1234...
set $amount @token.amount(DAI 1000)
exec @token(DAI) "transfer(address,uint256)" $recipient $amount

The DSL supports these value types:

TypeExampleDescription
address0xAbCd...123420-byte Ethereum address
number42, 100e18, 1.5e6Integer or scientific notation
string"hello"Quoted string
booltrue, falseBoolean
bytes0xdeadbeefHex-encoded bytes
bytes320x00...00132-byte value
array[1 2 3]Ordered collection

Numbers support scientific notation with e: 100e18 means 100 * 10^18. This is useful for token amounts with 18 decimals.

Some commands accept a block of sub-commands in parentheses:

batch (
exec 0xA... "foo()"
exec 0xB... "bar()"
)
for $i in @range(0 5) (
print $i
)
if @bool($x > 0) (
print "positive"
) else (
print "non-positive"
)

Contract function signatures follow Solidity syntax:

# Write functions (for exec)
"transfer(address,uint256)"
"approve(address,uint256)"
# Read functions (for @get) — include (returnType) after inputs
"balanceOf(address)(uint256)"
"name()(string)"
"getReserves()(uint112,uint112,uint32)"

The std module is loaded by default. Load additional modules with:

load aragonos
load sim
load ens
load http

After loading, use their commands and helpers with the module prefix:

load sim
sim:fork 1 (
sim:set-balance @me 100e18
exec 0xAbC... "foo()"
)

Some commands accept options with --name value:

exec 0xAbC... "foo()" --value 1e18
exec 0xAbC... "foo()" --from 0x1234...
load aragonos --as dao

The exec command can capture events emitted by the transaction:

exec 0xAbC... "createPool(address,uint24)" @token(DAI) 3000 -> Transfer [_ $pool]

Use @num() for arithmetic and @bool() for boolean logic:

set $total @num($a + $b * 2)
set $isValid @bool($x > 0 and $y < 100)
# Conditional
if @bool($balance > 0) (
print "Has balance"
)
# Loop over array
for $item in @range(0 10) (
print $item
)
# While loop
set $i 0
while @bool($i < 5) (
print $i
set $i @num($i + 1)
)

Use def to define reusable commands and helpers:

# Define a helper
def @double "$x: number -> number" (
@num($x * 2)
)
# Define a command
def transfer($token $to $amount) (
exec @token($token) "transfer(address,uint256)" $to @token.amount($token $amount)
)
# Use them
set $result @double(21)
transfer DAI 0x1234... 100