# std module The standard module is loaded by default. It provides core language constructs, contract interaction, control flow, and data manipulation. ## Configuration variables Config variables are set with `set` (fully qualified, including the module prefix) and are only readable by their own module and the user script. | Variable | Type | Default | Description | |----------|------|---------|-------------| | `$std:tokenlist` | `string` | `https://api.evmcrispr.com/tokenlist/{chainId}` | Tokenlist URL used to resolve token symbols (must be HTTPS). | | `$std:ipfsJwt` | `string` | — | Pinata JWT used by @ipfs to upload content. | ## Commands | Command | Description | |---------|-------------| | [batch](src/commands/batch.md) | Group multiple commands into a single transaction. | | [def](src/commands/def.md) | Define a user command, helper, or module (`def module ( ...defs )`), or return early from a command body (`def return`). | | [exec](src/commands/exec.md) | Call a contract function, encoding the arguments from its signature. | | [exit](src/commands/exit.md) | Stop script execution immediately. | | [if](src/commands/if.md) | Conditionally execute a block of commands, with an optional else block. | | [load](src/commands/load.md) | Load a module. Its commands and helpers become available qualified (`mod:cmd`, `@mod:helper`); an import list makes selected names available unqualified. | | [loop](src/commands/loop.md) | Repeat a block: iterate over an array (`loop $x of $arr`), repeat until a condition is true (`loop until `), or exit/skip an iteration from inside the block (`loop break`, `loop continue`). | | [print](src/commands/print.md) | Log values to the console output. Arrays render as headerless tables: a flat array as one row, an array of arrays as one row per inner array. | | [send](src/commands/send.md) | Send a low-level transaction. Provide [to] for a call/transfer, --data for raw calldata, --value for native value, or any combination. | | [set](src/commands/set.md) | Assign a value to a variable for use later in the script. | | [sign](src/commands/sign.md) | Sign a message or typed data with the connected wallet. | | [switch](src/commands/switch.md) | Switch the active chain by name or ID. | | [wait](src/commands/wait.md) | Wait for a duration before executing the next action (fork simulations advance the chain's clock instead). | ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@abi.decode](src/helpers/abi.decode.md) | `array` | Decode ABI-encoded bytes into values given a comma-separated type list. | | [@abi.decodeCall](src/helpers/abi.decodeCall.md) | `array` | Decode calldata into `[contract signature [args]]` with human-readable EVML values. | | [@abi.encode](src/helpers/abi.encode.md) | `bytes` | ABI-encode values given a comma-separated type list, like Solidity abi.encode. | | [@abi.encodeCall](src/helpers/abi.encodeCall.md) | `bytes` | ABI-encode a function call from its signature and arguments. | | [@abi.encodePacked](src/helpers/abi.encodePacked.md) | `bytes` | ABI non-standard packed encoding, matching Solidity's abi.encodePacked. | | [@arr](src/helpers/arr.md) | `array` | Generate an array of sequential integers from start (inclusive) to end (exclusive). | | [@block](src/helpers/block.md) | `array` | Return [number, timestamp] of the latest or a specific block. | | [@bool](src/helpers/bool.md) | `bool` | Evaluate a boolean expression or convert a value to a boolean string. | | [@bytes](src/helpers/bytes.md) | `bytes` | Convert a value to hex bytes, force UTF-8 encoding, or perform a bitwise operation. | | [@bytes32](src/helpers/bytes32.md) | `bytes32` | Pad a value to a 32-byte hex string. Integers and arithmetic expressions are left-padded like Solidity's `bytes32(uint256(...))` cast; hex strings pad left by default or right with a trailing `right`. | | [@date](src/helpers/date.md) | `number` | Parse a date string into a Unix timestamp, with an optional offset. | | [@ens](src/helpers/ens.md) | `address` | Resolve an ENS name to its address. | | [@gas.estimate](src/helpers/gas.estimate.md) | `number` | Estimate the gas required for a contract call. | | [@gas.price](src/helpers/gas.price.md) | `number` | Return the current gas price in wei. | | [@get](src/helpers/get.md) | `any` | Call a read-only contract function and return its result. | | [@hash](src/helpers/hash.md) | `bytes32` | Compute the hash of a string with keccak256 (default) or sha256. | | [@ipfs](src/helpers/ipfs.md) | `string` | Upload text content to IPFS and return the CID. | | [@ipfs.get](src/helpers/ipfs.get.md) | `string` | Fetch content from IPFS and return it as text. | | [@me](src/helpers/me.md) | `address` | Return the connected wallet address. | | [@nonce](src/helpers/nonce.md) | `number` | Get the transaction count (nonce) of an address. | | [@num](src/helpers/num.md) | `number` | Evaluate an arithmetic expression or convert a value to a number. | | [@sigValid](src/helpers/sigValid.md) | `bool` | Verify a signature against an expected signer address. Auto-detects EIP-712 typed data (JSON) vs. plain message. | | [@str](src/helpers/str.md) | `string` | Convert a value to its string representation, or decode hex bytes as UTF-8. | | [@token](src/helpers/token.md) | `address` | Resolve a token symbol to its contract address on the current chain. | --- --- title: "batch" --- Group multiple commands into a single transaction. ## Syntax ```evml batch ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `block` | `block` | Block of commands | ## Examples ```evml # Batch approve + transfer into one transaction batch ( exec @token(DAI) "approve(address,uint256)" 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6 1000e18 exec @token(DAI) "transfer(address,uint256)" 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6 1000e18 ) ``` ## Error Captures on Batches Error captures on a batch catch the combined transaction revert: ```evml set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb batch ( exec $token "transfer(address,uint256)" @me 100e18 ) -!> Error(string) [$reason] # Assertion only: assert the batch reverts with a specific error batch ( exec $token "transfer(address,uint256)" @me 100e18 ) -!> Unauthorized() # Optional form with a boolean variable ($reverted = "true"/"false") batch ( exec $token "transfer(address,uint256)" @me 100e18 ) -?!> Unauthorized() $reverted ``` ## Notes - All commands in the batch are combined into a single atomic transaction (EIP-5792 `wallet_sendCalls` for EOAs, batched Safe transaction for Safes) - If any command in the batch reverts, the entire batch reverts - Event captures (`->`) on a batch apply to the combined transaction receipt - Error captures (`-!>` / `-?!>`) on a batch catch the combined transaction revert - Inside a `sim:fork` block, the batch is simulated as an EIP-7702 transaction: a delegation to MetaMask's EIP7702StatelessDeleGator is installed on the sender EOA (if not already delegated) and the calls execute atomically through it — mirroring how wallets fulfill `wallet_sendCalls` ## See Also - [exec](exec.md) — individual contract calls --- --- title: "def" --- Define a user command, helper, or module (`def module ( ...defs )`), or return early from a command body (`def return`). ## Syntax ```evml def [params] [body] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `command \| helper` | | | `[params]` | `string` | Definition expression (see syntax variants below) | | `[body]` | `expression \| block` | | ## Examples ```evml # Constant helper - returns a fixed address def @myAddr "address" 0x44fA8E6f47987339850636F88629646662444217 set $result @myAddr # Helper with typed parameters def @double "$n: number -> number" @num($n * 2) set $result @double(5) # Boolean helper def @isPositive "$n: number -> bool" @bool($n > 0) set $result @isPositive(5) # Composition def @double "$n: number -> number" @num($n * 2) def @quadruple "$n: number -> number" @double(@double($n)) set $result @quadruple(3) # Inline module - a def of defs, used as if the module was loaded def module math ( def @double "$n: number -> number" @num($n * 2) ) set $result @math:double(21) # Guard clause - def return exits the command body early def maybe-print "$n: number" ( if @bool($n == 0) ( def return ) print $n ) maybe-print 0 maybe-print 5 ``` ## Syntax ``` # Define a constant helper def @name "type" # Define a helper with parameters def @name "$param1: type $param2: type -> returnType" # Define a command def commandName "$param1: type $param2: type" ( ... ) # Define an inline module (block may only contain defs) def module moduleName ( def @helperName "$n: type -> type" def commandName "$param: type" ( ... ) ) # Return early from a command body def return ``` ## Notes - The type signature string defines parameter names, types, and return type - Parameters are prefixed with `$`, optional params wrapped in `[]` - Helpers defined inside blocks (e.g. `if`) are scoped to that block - Type inference: if the return type is omitted, it is inferred from the body ## Early return Inside a command body, `def return` stops executing the body — typically as a guard clause: ```evml def approve-if-any "$amount: number" ( if @bool($amount == 0) ( def return ) print "approving" $amount ) approve-if-any 0 ``` Actions produced before the `def return` still execute. `return` and `module` are reserved def names. A `def return` also exits from inside a loop within the body; use [`loop break`](loop.md) to leave only the loop, or [`exit`](exit.md) to stop the whole script. ## Modules `def module ( ...defs )` groups defs into an inline module — using it is exactly like loading a module: its defs are available qualified as `name:cmd` and `@name:helper`, and never leak unqualified into the script. Inside the block, sibling defs resolve unqualified (shadowing same-named caller defs). Module defs run isolated: their `set` bindings are scope-local and they cannot read or write `$mod:key` config variables. `module` is a reserved def name — nested module definitions are not allowed. Module names shadow registered-but-unloaded modules (the editor warns, but the script still runs — so a name you pick today keeps working even if a future built-in module takes it). Only `std` is reserved, and defining a name that is actually loaded in the script is an error. A file containing exactly one `def module` command can be published to IPFS and loaded remotely — see [load](load.md#external-evml-modules---from). ## See Also - [set](set.md) — assign values to variables - [loop](loop.md) — `loop break` / `loop continue` - [exit](exit.md) — stop the whole script --- --- title: "exec" --- Call a contract function, encoding the arguments from its signature. ## Syntax ```evml exec [...params] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `contractAddress` | `address` | Target contract address | | `signature` | `write-abi` | Function signature (e.g. `"transfer(address,uint256)"`) | | `[...params]` | `any` | Arguments matching the signature types | ## Options | Name | Type | Description | |------|------|-------------| | `--value` | `number` | ETH to send with the call (in wei) | | `--from` | `address` | Sender address (requires simulation or connected wallet) | | `--gas` | `number` | Gas limit | | `--max-fee-per-gas` | `number` | Max fee per gas (EIP-1559) | | `--max-priority-fee-per-gas` | `number` | Max priority fee per gas (EIP-1559) | | `--nonce` | `number` | Transaction nonce override | ## Examples ```evml # Approve a token exec @token(DAI) "approve(address,uint256)" 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6 1200e18 # Send ETH with the call exec 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d "deposit()" --value 1e18 # Specify sender exec @token(DAI) "approve(address,uint256)" 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6 1200e18 --from 0x44fA8E6f47987339850636F88629646662444217 # Capture events from the transaction load sim set $wxdai 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d sim:fork --using anvil ( sim:set-balance @me 1e18 exec $wxdai "deposit()" --value 0.001e18 -> Deposit(address indexed, uint) [_ $amount] exec $wxdai "withdraw(uint)" $amount ) # Complex parameter types exec 0xd0e81E3EE863318D0121501ff48C6C3e3Fd6cbc7 "addBatches(bytes32[],bytes)" [0x02732126661d25c59fd1cc2308ac883b422597fc3103f285f382c95d51cbe667] @bytes(QmTik4Zd7T5ALWv5tdMG8m2cLiHmqtTor5QmnCSGLUjLU2) ``` ## Error Captures Error captures (`-!>` / `-?!>`) catch transaction reverts and decode the error data into variables. Three forms are available after the error name: nothing (assertion only), destructure (`[...]`), or a boolean variable (`$var`). ```evml set $c 0x44fA8E6f47987339850636F88629646662444217 # Assert a specific error without capturing data exec $c "deny()" -!> Unauthorized() # Destructure error arguments into variables exec $c "withdraw(uint256)" 200 -!> InsufficientBalance(uint256,uint256) [$balance $required] # Catch a require/revert reason exec $c "transfer(address,uint256)" @me 100e18 -!> Error(string) [$reason] # Boolean variable: $e is "true" if the error matched exec $c "deny()" -!> Unauthorized() $e # Generic catch-all (no error name) exec $c "doSomething()" -!> [$reason] exec $c "doSomething()" -!> $e # Optional: skip silently if tx succeeds exec $c "maybeRevert()" -?!> Error(string) [$reason] exec $c "maybeRevert()" -?!> Unauthorized() $e # $e = "false" if tx succeeds or wrong error ``` - `-!>` expects the transaction to revert; throws if it succeeds - `-?!>` captures the error if the tx reverts; silently continues if it succeeds - With a boolean variable (`$e`), `-?!>` sets `$e = "false"` on success or mismatched error; `-!>` always sets `$e = "true"` (throws otherwise) - Supported error types: custom named errors, `Error(string)` (require/revert), `Panic(uint256)` (assert), and empty reverts ## Notes - The signature follows Solidity syntax: `"functionName(type1,type2)"` - Parameters are automatically ABI-encoded based on the signature - Use `--value` to send ETH with the call - Use `--from` to impersonate a sender (requires simulation mode) - Event captures (`->`) execute the transaction immediately and store decoded log values in variables - Error captures (`-!>` / `-?!>`) catch and decode transaction reverts ## See Also - [@get](../helpers/get.md) — read-only contract calls - [batch](batch.md) — group multiple exec calls into one transaction - [send](send.md) — send pre-encoded calldata or native value --- --- title: "exit" --- Stop script execution immediately. ## Syntax ```evml exit ``` ## Examples ```evml # Stop script execution print "before" exit ``` ## Notes - `exit` is a clean stop, not an error: actions produced before it have already executed, everything after it is skipped. - It stops the whole script from anywhere — including inside `loop` blocks and `def` command bodies. Use [`loop break`](loop.md) to leave just the loop, or [`def return`](def.md) to leave just the command body. ## See Also - [if](if.md) — conditional execution - [loop](loop.md) — `loop break` / `loop continue` for loop-scoped exits - [def](def.md) — `def return` for command-body exits --- --- title: "if" --- Conditionally execute a block of commands, with an optional else block. ## Syntax ```evml if [elseBlock] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `condition` | `bool` | Whether to execute the then block | | `thenBlock` | `block` | Commands when condition is true | | `[elseBlock]` | `block` | Commands when condition is false | ## Examples ```evml # Simple condition if true ( print "yes" ) # Boolean expression if @bool(1 == 1) ( print "equal" ) # If-else set $x 10 if @bool($x > 0) ( print "positive" ) ( print "non-positive" ) ``` ## See Also - [@bool](../helpers/bool.md) — boolean expressions --- --- title: "load" --- Load a module. Its commands and helpers become available qualified (`mod:cmd`, `@mod:helper`); an import list makes selected names available unqualified. ## Syntax ```evml load [imports] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `moduleName` | `module` | Module name (e.g. `aragonos`, `sim`); with --from, `name>alias` loads the module under a local alias | | `[imports]` | `expression` | Import list: `[cmd cmd>renamed @helper @helper>@renamed]` — names usable without the module prefix | ## Options | Name | Type | Description | |------|------|-------------| ## Examples ```evml # Load the simulation module load sim # Import selected names for unqualified use (barewords = commands, @names = helpers) load ens [renew @addr] # Rename an import with > load ens [set-addr>ens-set-addr @contenthash>@ch] ``` ## The Import List After `load `, every export of the module is available in its qualified form: commands as `:` (e.g. `ens:renew`) and helpers/constants as `@:` (e.g. `@ens:addr`). The optional import list makes selected exports usable *without* the module prefix: - **Barewords import commands** — `load ens [renew]` lets you write `renew` instead of `ens:renew`. - **`@names` import helpers and constants** — `load ens [@addr]` lets you write `@addr(...)` instead of `@ens:addr(...)`. - **`>` renames an import** — `load aragonos [connect>arConn]` binds the command as `arConn`; `load ens [@contenthash>@ch]` binds the helper as `@ch`. Renaming only affects the unqualified name: the qualified form keeps the original name (`aragonos:connect` works, `aragonos:arConn` does not). ```evml load sim [fork expect] load token [@balance] # Imported commands and helpers work unqualified, including inside blocks fork --using anvil ( sim:set-balance @me 1e18 expect @bool(@balance(ETH @me) > 0) ) ``` ## External EVML Modules (`--from`) `load --from ipfs://` fetches an EVML module file from IPFS. The file must contain exactly one [`def module`](def.md) command, and the name it declares must match the name written in the load line — so the load line always documents which module you are pulling in. Add `>alias` to bind it under a different local name (e.g. when two libraries picked the same name): ```evml novalidate load math --from ipfs://QmYourModuleCid set $x @math:double(21) # Load under a local alias — the canonical name stays unbound load math>mylib --from ipfs://QmYourModuleCid # Import lists work the same as with registered modules load math --from ipfs://QmYourModuleCid [@double>@dbl] ``` - Only `ipfs://` (and `"ipfs://#"`) sources are supported — content-addressing pins the exact code you audited, forever. - The pin must be plain text (publish with the `evmcrispr_publish_module` MCP tool or by uploading the file in the terminal) or a share pin whose script is a module file. Encrypted share links produced by `create-link` need their key appended and the source quoted (`--from "ipfs://#"` — `#` starts a comment outside quotes); without the key they are rejected. - `name>alias` renames are only valid together with `--from` — registered module namespaces are never aliased. - External modules may shadow registered-but-unloaded module names (the editor warns; rename with `>alias` to keep both available). This keeps published scripts working when future built-in modules take the same name. Loading the same local name twice is always an error. - Module defs run isolated: their `set` bindings are scope-local and they cannot read or write `$mod:key` config variables. ## Rules - The import list must be a literal array: `load ens [renew @addr]`. - Every entry must name an existing export of the module, otherwise the load fails (e.g. `module ens has no command named foo`). - Duplicate imports and imports that collide with an already-imported name or a `def`-defined name are errors — use `>` to rename one of them. - `std` is the prelude: its commands and helpers are always available unqualified (they may also be qualified as `std:set`, `@std:token.amount`). ## See Also - [std:def](def.md) — define your own commands and helpers --- --- title: "loop" --- Repeat a block: iterate over an array (`loop $x of $arr`), repeat until a condition is true (`loop until `), or exit/skip an iteration from inside the block (`loop break`, `loop continue`). ## Syntax ```evml loop [variable] [value] [block] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[variable]` | `variable` | Loop variable, bound per element (iteration form) | | `connector` | `command` | Keyword `of` (iterate an array), `until` (repeat while false), `break` or `continue` (inside a loop block) | | `[value]` | `expression` | Array to iterate over, or exit condition | | `[block]` | `block` | Commands to repeat | ## Examples ```evml # Iterate over an array set $items [1 2 3] loop $item of $items ( print $item ) # Repeat until a condition is true set $i 0 loop until @bool($i >= 3) ( print $i set $i @num($i + 1) ) # Exit a loop early with loop break loop $i of @arr(0 10) ( if @bool($i >= 3) ( loop break ) print $i ) # Skip to the next iteration with loop continue loop $i of [1 2 3 4] ( if @bool($i == 2 or $i == 4) ( loop continue ) print $i ) ``` ## Notes - Two forms share one command: `loop $x of $array ( ... )` iterates an array, and `loop until ( ... )` repeats while the condition is false. - The until form checks the condition *before* each iteration and stops as soon as it becomes true — an initially-true condition runs zero iterations. - The loop variable (`$item`, `$i`, ...) is scoped to the block. - Empty arrays result in zero iterations. - An until loop that never terminates fails after 10,000 iterations. ## break and continue Inside a loop block, `loop break` exits the nearest enclosing loop and `loop continue` skips to the next iteration. Both are typically used as guards: ```evml set $items [1 0 200 3] loop $item of $items ( if @bool($item == 0) ( loop continue ) if @bool($item > 100) ( loop break ) print $item ) ``` - They only work inside a loop block; a `def` command body is a boundary — a `loop break` inside a def body cannot break a loop at the call site. - Use [`def return`](def.md) to leave a command body, or [`exit`](exit.md) to stop the whole script. ## See Also - [if](if.md) — conditional execution - [exit](exit.md) — stop the whole script - [@arr](../helpers/arr.md) — generate a sequence of numbers - [@bool](../helpers/bool.md) — boolean expressions --- --- title: "print" --- Log values to the console output. Arrays render as headerless tables: a flat array as one row, an array of arrays as one row per inner array. ## Syntax ```evml print [...values] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[...values]` | `any` | Values to output, space-separated | ## Options | Name | Type | Description | |------|------|-------------| | `--headers` | `array` | Column headers; renders the printed arrays as a table, one array per column | ## Examples ```evml # Print a string print "hello" # Print multiple values print "count:" 42 # Print variables set $name "world" print "hello" $name # Print an array as a one-row table print [1 2 3] # Print an array of arrays as table rows print [[alice 10] [bob 20]] # Print column arrays as a table print [[alice bob] [10 20]] --headers [Name Score] ``` ## See Also --- --- title: "send" --- Send a low-level transaction. Provide [to] for a call/transfer, --data for raw calldata, --value for native value, or any combination. ## Syntax ```evml send [to] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[to]` | `address` | Target address. Omit for a CREATE-style deployment (use the `deploy` command for address binding). | ## Options | Name | Type | Description | |------|------|-------------| | `--data` | `bytes` | Pre-encoded calldata or init code | | `--value` | `number` | Native value to send (in wei) | | `--from` | `address` | Sender address (requires simulation or connected wallet) | | `--gas` | `number` | Gas limit | | `--max-fee-per-gas` | `number` | Max fee per gas (EIP-1559) | | `--max-priority-fee-per-gas` | `number` | Max priority fee per gas (EIP-1559) | | `--nonce` | `number` | Transaction nonce override | ## Examples ```evml # Send pre-encoded calldata set $data @abi.encodeCall("transfer(address,uint256)" 0x44fA8E6f47987339850636F88629646662444217 100e18) send @token(DAI) --data $data # Native value transfer send 0x44fA8E6f47987339850636F88629646662444217 --value 1e18 ``` ## Error Captures Like `exec`, `send` supports error captures (`-!>` / `-?!>`): ```evml set $contract 0x44fA8E6f47987339850636F88629646662444217 set $calldata 0xa3fdfee3 # Assert the call reverts with a specific error send $contract --data 0xa3fdfee3 -!> Unauthorized() # Capture the revert reason send $contract --data $calldata -!> Error(string) [$reason] # Boolean variable send $contract --data $calldata -?!> Unauthorized() $e ``` ## Notes - Either `` or `--data` must be provided. Sending without either is a no-op and is rejected. - Omitting `` while supplying `--data` produces a CREATE-style deployment transaction. For deployments where you also want the predicted contract address bound to a variable, use the [deploy](../../../contracts/src/commands/deploy.md) command instead. ## See Also - [exec](exec.md) — call a contract by signature (auto-encodes) - [deploy](../../../contracts/src/commands/deploy.md) — deploy a contract from raw creation bytecode - [@abi.encodeCall](../helpers/abi.encodeCall.md) — encode calldata from a signature --- --- title: "set" --- Assign a value to a variable for use later in the script. ## Syntax ```evml set ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `variable` | `variable` | Variable name | | `value` | `any` | Value to assign | ## Examples ```evml # Set a simple value set $amount 1e18 # Set a string set $greeting "hello world" # Set from a helper result set $dai @token(DAI) # Destructuring assignment set [$a $b] ["hello" "world"] # Skip values with _ set [_ $second] ["skip" "keep"] # Nested destructuring set [$a [_ $b]] ["x" ["skip" "y"]] ``` ## See Also - [@get](../helpers/get.md) — read contract state into a variable - [def](def.md) — define reusable commands/helpers --- --- title: "sign" --- Sign a message or typed data with the connected wallet. ## Syntax ```evml sign [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `variable` | `variable` | Variable name | | `[message]` | `string` | Plain-text message to sign | ## Options | Name | Type | Description | |------|------|-------------| | `--typed` | `string` | EIP-712 typed data JSON string | ## Examples ``` # Sign a plain-text message sign $sig "hello world" # Sign typed data (EIP-712) sign $sig --typed '{"types":{"Mail":[{"name":"to","type":"address"}]},"primaryType":"Mail","message":{"to":"0x1234..."}}' # Store and print the signature sign $sig "approve this action" print $sig ``` ## See Also - [exec](exec.md) — call a contract function --- --- title: "switch" --- Switch the active chain by name or ID. ## Syntax ```evml switch ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `networkNameOrId` | `chain` | Chain name in camelCase as exported by viem (e.g. `mainnet`, `gnosis`, `baseSepolia`, `polygonZkEvm`) or numeric chain ID | ## Examples ```evml # Switch by chain name switch gnosis # Testnets and multi-word chains use camelCase viem names switch baseSepolia # Switch by chain ID switch 137 ``` ## See Also --- --- title: "wait" --- Wait for a duration before executing the next action (fork simulations advance the chain's clock instead). ## Syntax ```evml wait ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `duration` | `number` | Time to wait, in time units (e.g. 30s, 1d) | ## Examples ```evml # Wait a minute between two transactions set $contract 0x44fA8E6f47987339850636F88629646662444217 exec $contract start() wait 1m exec $contract finish() ``` ```evml # Inside a fork simulation the wait is instant: the chain's clock is warped load sim sim:fork ( wait 1d ) ``` ## Notes - In live execution the client really waits (the script pauses between transactions); in `sim:fork` blocks the fork's timestamp is advanced instead, so timelocks and vesting cliffs can be crossed instantly. ## See Also --- --- title: "@abi.decode" --- Decode ABI-encoded bytes into values given a comma-separated type list. **Returns**: `array` ## Syntax ```evml @abi.decode(types data) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `types` | `string` | Comma-separated Solidity types (e.g. "uint256,address") | | `data` | `bytes` | ABI-encoded hex data | ## Examples ```evml # Decode a single uint256 set $values @abi.decode("uint256" 0x0000000000000000000000000000000000000000000000000000000000000064) print $values # Decode multiple types set $values @abi.decode("uint256,address" 0x000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000044fa8e6f47987339850636f88629646662444217) print $values ``` ## See Also - [@abi.encode](abi.encode.md) — the inverse: ABI-encode values - [@abi.encodeCall](abi.encodeCall.md) — ABI-encode a function call - [@abi.encodePacked](abi.encodePacked.md) — packed encoding --- --- title: "@abi.decodeCall" --- Decode calldata into `[contract signature [args]]` with human-readable EVML values. **Returns**: `array` ## Syntax ```evml @abi.decodeCall(contract calldata) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `contract` | `address` | Contract the calldata targets (its verified ABI is used) | | `calldata` | `bytes` | Full calldata including the 4-byte function selector | ## Examples ```evml # Decode a token transfer set [$to $sig $args] @abi.decodeCall(0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d 0xa9059cbb000000000000000000000000000000000000000000000000000000000000dead0000000000000000000000000000000000000000000000000de0b6b3a7640000) print $sig ``` ## See Also - [@abi.encodeCall](abi.encodeCall.md) — the inverse: encode a call from signature and args - [@abi.decode](abi.decode.md) — decode raw ABI data given a type list - [@ens](ens.md) — resolve the `@ens(name)` values back to addresses --- --- title: "@abi.encode" --- ABI-encode values given a comma-separated type list, like Solidity abi.encode. **Returns**: `bytes` ## Syntax ```evml @abi.encode(types ...values) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `types` | `string` | Comma-separated Solidity types (e.g. `uint256,address`) | | `[...values]` | `any` | Values to encode, one per type | ## Examples ```evml # Encode values without a selector set $data @abi.encode("uint256,address" 100e18 0x44fA8E6f47987339850636F88629646662444217) print $data ``` ## See Also - [@abi.decode](abi.decode.md) — the inverse: decode ABI-encoded data - [@abi.encodeCall](abi.encodeCall.md) — encode a full function call (with selector) - [@abi.encodePacked](abi.encodePacked.md) — packed encoding --- --- title: "@abi.encodeCall" --- ABI-encode a function call from its signature and arguments. **Returns**: `bytes` ## Syntax ```evml @abi.encodeCall(signature ...params) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `signature` | `write-abi` | Function signature (e.g. `transfer(address,uint256)`) | | `[...params]` | `any` | Arguments to encode | ## Examples ```evml # Encode a transfer call set $data @abi.encodeCall("transfer(address,uint256)" 0x44fA8E6f47987339850636F88629646662444217 100e18) ``` ## See Also - [@abi.decodeCall](abi.decodeCall.md) — the inverse: decode calldata into `[contract sig [args]]` - [send](../commands/send.md) — send pre-encoded calldata - [exec](../commands/exec.md) — call by signature (auto-encodes) - [@hash](hash.md) — compute a function selector --- --- title: "@abi.encodePacked" --- ABI non-standard packed encoding, matching Solidity's abi.encodePacked. **Returns**: `bytes` ## Syntax ```evml @abi.encodePacked(types ...values) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `types` | `string` | Comma-separated Solidity types (e.g. "address,uint256") | | `[...values]` | `any` | Values to encode, one per type | ## Examples ```evml # Pack an address and amount set $packed @abi.encodePacked("address,uint256" @me 1e18) print $packed ``` ## See Also - [@abi.encode](abi.encode.md) — standard ABI encoding - [@abi.encodeCall](abi.encodeCall.md) — ABI-encode a function call - [@abi.decode](abi.decode.md) — decode ABI-encoded data --- --- title: "@arr" --- Generate an array of sequential integers from start (inclusive) to end (exclusive). **Returns**: `array` ## Syntax ```evml @arr(start end) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `start` | `number` | Start value (inclusive) | | `end` | `number` | End value (exclusive) | ## Examples ```evml # Generate [0, 1, 2, 3, 4] set $nums @arr(0 5) # Generate [3, 4, 5, 6] set $nums @arr(3 7) ``` ## See Also - [loop](../commands/loop.md) — iterate over arrays --- --- title: "@block" --- Return [number, timestamp] of the latest or a specific block. **Returns**: `array` ## Syntax ```evml @block(blockNumber?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[blockNumber]` | `number` | Block number (omit for latest) | ## Examples ```evml # Get latest block number and timestamp set [$num $timestamp] @block() print $num print $timestamp # Get a specific block's timestamp set [$num $timestamp] @block(1) print $timestamp ``` ## See Also - [@date](date.md) — convert a date to a Unix timestamp --- --- title: "@bool" --- Evaluate a boolean expression or convert a value to a boolean string. **Returns**: `bool` ## Syntax ```evml @bool(...tokens) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[...tokens]` | `any` | Boolean expression (e.g. `$a > 0 and $b < 100`) | ## Examples ```evml # Comparisons set $a @bool(1 == 1) set $b @bool(5 > 3) set $c @bool(5 <= 3) # Logical operators set $e @bool(true and true) set $f @bool(true or false) set $g @bool(not false) # Compound expression set $x 10 set $h @bool($x > 0 and $x < 100) ``` ## See Also - [if](../commands/if.md) — conditional execution - [loop](../commands/loop.md) — condition-based loop --- --- title: "@bytes" --- Convert a value to hex bytes, force UTF-8 encoding, or perform a bitwise operation. **Returns**: `bytes` ## Syntax ```evml @bytes(a b? c?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `a` | `any` | Value to convert or left operand | | `[b]` | `string` | Operator (`&` `|` `<<` `>>`) or `utf8` | | `[c]` | `any` | Right operand for bitwise ops | ## Examples ```evml # Convert a number to bytes set $b @bytes(0xff) # Bitwise AND set $b @bytes(0xff00 "&" 0x0ff0) # Left shift set $b @bytes(0x01 "<<" 8) ``` ## See Also - [@bytes.not](../../../lang/src/helpers/bytes.not.md) — bitwise NOT - [@bytes.concat](../../../lang/src/helpers/bytes.concat.md) — concatenate bytes - [@bytes.slice](../../../lang/src/helpers/bytes.slice.md) — extract a byte range --- --- title: "@bytes32" --- Pad a value to a 32-byte hex string. Integers and arithmetic expressions are left-padded like Solidity's `bytes32(uint256(...))` cast; hex strings pad left by default or right with a trailing `right`. **Returns**: `bytes32` ## Syntax ```evml @bytes32(...tokens) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[...tokens]` | `any` | Value or arithmetic expression, optionally followed by a `left`/`right` padding direction (hex strings only) | ## Examples ```evml # Derive the ERC-1967 admin slot set $slot @bytes32(@hash("eip1967.proxy.admin") - 1) # Right-pad a short hex value set $b @bytes32(0x01 right) ``` ## See Also --- --- title: "@date" --- Parse a date string into a Unix timestamp, with an optional offset. **Returns**: `number` ## Syntax ```evml @date(date offset?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `date` | `string` | ISO 8601 date string or `now` | | `[offset]` | `string` | Time offset (e.g. `+1d`, `-2h`, `+3mo`) | ## Examples ```evml # Parse an ISO date to Unix timestamp set $ts @date(2025-01-01) # Current timestamp set $now @date(now) # With positive offset set $future @date(2025-01-01 +1d) # With negative offset set $yesterday @date(2025-01-01 -1d) ``` ## See Also - [wait](../commands/wait.md) — wait between actions (advances time in simulations) --- --- title: "@ens" --- Resolve an ENS name to its address. **Returns**: `address` ## Syntax ```evml @ens(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. `vitalik.eth`) | ## Examples ```evml # Resolve an ENS name to its address set $addr @ens("vitalik.eth") ``` ## See Also - [@namehash](../../../ens/src/helpers/namehash.md) — compute ENS namehash - [@token](token.md) — resolve token addresses --- --- title: "@gas.estimate" --- Estimate the gas required for a contract call. **Returns**: `number` ## Syntax ```evml @gas.estimate(address signature ...params) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Target contract address | | `signature` | `write-abi` | Function signature (e.g. "transfer(address,uint256)") | | `[...params]` | `any` | Arguments matching the signature types | ## Examples ```evml # TODO: add examples ``` ## See Also --- --- title: "@gas.price" --- Return the current gas price in wei. **Returns**: `number` ## Syntax ```evml @gas.price ``` ## Examples ```evml # TODO: add examples ``` ## See Also --- --- title: "@get" --- Call a read-only contract function and return its result. **Returns**: `any` ## Syntax ```evml @get(address abi ...params) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Contract or account address | | `abi` | `read-abi` | Signature with return types (e.g. `"balanceOf(address)(uint256)"`) | | `[...params]` | `any` | Function arguments | ## Examples ```evml # Read a token name set $name @get(0x44fA8E6f47987339850636F88629646662444217 "name()(string)") # Read a balance set $balance @get(@token(DAI) "balanceOf(address)(uint256)" @me) # Read with indexed parameter set $info @get(0xdDCbf776dF3dE60163066A5ddDF2277cB445E0F3 "poolInfo(uint256)(uint128,uint64,uint64)" 1) ``` ## Notes - The ABI signature must include the return type(s) after the input types - Format: `"functionName(paramTypes)(returnTypes)"` ## See Also - [exec](../commands/exec.md) — write (state-changing) contract calls - [@token:balance](../../../token/src/helpers/balance.md) — shortcut for ERC-20 balance queries --- --- title: "@hash" --- Compute the hash of a string with keccak256 (default) or sha256. **Returns**: `bytes32` ## Syntax ```evml @hash(text algorithm?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `text` | `string` | String to hash (e.g. a function signature) | | `[algorithm]` | `string` | `keccak256` (default) or `sha256` | ## Examples ```evml # Compute a function selector set $sel @hash("transfer(address,uint256)") # Hash with sha256 instead of keccak256 set $digest @hash("an example" sha256) ``` ## See Also - [@namehash](../../../ens/src/helpers/namehash.md) — ENS namehash - [@abi.encodeCall](abi.encodeCall.md) — encode a full function call --- --- title: "@ipfs" --- Upload text content to IPFS and return the CID. **Returns**: `string` ## Syntax ```evml @ipfs(text) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `text` | `string` | Content to upload | ## Examples ```evml # Upload text to IPFS set $cid @ipfs("hello world") ``` Content is pinned byte-exact as plain text, so the CID addresses exactly the text you uploaded — a pinned module file can be loaded directly with [`load --from`](../commands/load.md). ## See Also - [@ens:contenthash](../../../ens/src/helpers/contenthash.md) — encode IPFS hash for ENS --- --- title: "@ipfs.get" --- Fetch content from IPFS and return it as text. **Returns**: `string` ## Syntax ```evml @ipfs.get(cid) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `cid` | `string` | Content identifier to fetch | Content is pinned and returned byte-exact, so `@ipfs.get(@ipfs("hello"))` returns `hello`. The terminal editor uses this helper automatically: pasting a hex string larger than 64 bytes pins it to IPFS and replaces it with an `@ipfs.get` call. Paste with `Ctrl+Shift+V` (`Cmd+Shift+V` on Mac) to keep the raw hex instead. ## Examples ```evml # Send a raw transaction whose calldata is pinned on IPFS send 0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d --data @ipfs.get("QmPK1s3pNYLi9ERiq3BDxKa4XosgWwFRQUydHUtz4YgpqB") ``` ```evml # Round-trip text through IPFS set $cid @ipfs("hello world") set $content @ipfs.get($cid) ``` ## See Also - [@ipfs](ipfs.md) — upload content to IPFS and return the CID --- --- title: "@me" --- Return the connected wallet address. **Returns**: `address` ## Syntax ```evml @me ``` ## Examples ```evml # Get own address print @me # Check own token balance set $balance @get(@token(DAI) "balanceOf(address)(uint256)" @me) print $balance # Use in exec exec @token(DAI) "approve(address,uint256)" @me 100e18 ``` ## See Also - [@get](get.md) — read contract state - [@token:balance](../../../token/src/helpers/balance.md) — shortcut for balance queries --- --- title: "@nonce" --- Get the transaction count (nonce) of an address. **Returns**: `number` ## Syntax ```evml @nonce(address) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Account address | ## Examples ```evml # Get the nonce of an address set $n @nonce(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266) print $n ``` ## See Also - [@me](me.md) — get the connected wallet address --- --- title: "@num" --- Evaluate an arithmetic expression or convert a value to a number. **Returns**: `number` ## Syntax ```evml @num(...tokens) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[...tokens]` | `any` | Arithmetic expression (e.g. `$a + $b * 2`) | ## Examples ```evml # Basic arithmetic set $sum @num(1 + 2) # Exponentiation set $pow @num(2 ^ 10) # Expression with variables set $a 10 set $b 3 set $result @num($a * $b + 1) # Convert a string to number set $n @num("42") ``` ## See Also - [@num.format](../../../lang/src/helpers/num.format.md) — format with decimals (like `formatUnits`) - [@num.parse](../../../lang/src/helpers/num.parse.md) — parse a decimal string (like `parseUnits`) - [@bool](bool.md) — boolean expressions --- --- title: "@sigValid" --- Verify a signature against an expected signer address. Auto-detects EIP-712 typed data (JSON) vs. plain message. **Returns**: `bool` ## Syntax ```evml @sigValid(address data signature) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Expected signer address | | `data` | `string` | Plain-text message, or EIP-712 typed data JSON string (matching what was signed). | | `signature` | `bytes` | Hex-encoded signature to verify | ## Examples ```evml # Verify a personal-message signature against the signer set $ok @sigValid(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 "hello" 0xf16ea9a3478698f695fd1401bfe27e9e4a7e8e3da94aa72b021125e31fa899cc573c48ea3fe1d4ab61a9db10c19032026e3ed2dbccba5a178235ac27f94504311c) print $ok ``` ## Behaviour If `data` parses as JSON with the EIP-712 shape (`types`, `primaryType`, `message`), the signature is verified with `verifyTypedData`. Otherwise `data` is treated as a plain personal-message and verified with `verifyMessage`. Returns `"false"` for malformed signatures rather than throwing, so it can safely drive `if` / `switch`. ## More examples ```evml # Round-trip: verify a message I just signed sign $sig "hello world" if @sigValid(@me "hello world" $sig) ( print "signature ok" ) # Round-trip an EIP-712 typed-data signature set $payload '{"types":{"Mail":[{"name":"to","type":"address"}]},"primaryType":"Mail","domain":{"name":"App"},"message":{"to":"0x1234567890abcdef1234567890abcdef12345678"}}' sign $sig --typed $payload set $ok @sigValid(@me $payload $sig) print $ok ``` ## See Also - [sign](../commands/sign.md) — produce a signature with the connected wallet - [if](../commands/if.md) — branch on a boolean --- --- title: "@str" --- Convert a value to its string representation, or decode hex bytes as UTF-8. **Returns**: `string` ## Syntax ```evml @str(value encoding?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `any` | Input value | | `[encoding]` | `string` | `utf8` to decode hex bytes as a UTF-8 string | ## Examples ```evml # Convert a number to string set $s @str(42) # Convert an address to string set $s @str(@me) # Decode hex bytes as UTF-8 set $s @str(0x48656c6c6f utf8) print $s ``` ## See Also - [@num](num.md) — convert to number - [@bytes](bytes.md) — convert to bytes - [@bool](bool.md) — convert to boolean --- --- title: "@token" --- Resolve a token symbol to its contract address on the current chain. **Returns**: `address` ## Syntax ```evml @token(tokenSymbolOrAddress) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `tokenSymbolOrAddress` | `token-symbol` | Token symbol (e.g. `DAI`) or address | ## Examples ```evml # Resolve a token symbol set $dai @token(DAI) # Resolve the native token set $native @token(XDAI) ``` ## See Also - [@token:amount](../../../token/src/helpers/amount.md) — convert human amounts to base units - [@token:balance](../../../token/src/helpers/balance.md) — query token balance --- # lang module Language primitives: string, number, bytes, array, and boolean helpers for data manipulation. Requires `load lang` (import the helpers you use, e.g. `load lang [@map @filter]`, or qualify them as `@lang:map`). ```evml load lang ``` ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@lang:all](src/helpers/all.md) | `bool` | Return true if every element satisfies the predicate. | | [@lang:any](src/helpers/any.md) | `bool` | Return true if at least one element satisfies the predicate. | | [@lang:at](src/helpers/at.md) | `any` | Access an element by index in an array. | | [@lang:bytes.at](src/helpers/bytes.at.md) | `bytes` | Access a single byte by index in a bytes value. | | [@lang:bytes.concat](src/helpers/bytes.concat.md) | `bytes` | Concatenate bytes values together. | | [@lang:bytes.len](src/helpers/bytes.len.md) | `number` | Return the byte length of a bytes value. | | [@lang:bytes.not](src/helpers/bytes.not.md) | `bytes` | Bitwise NOT of a bytes value (256-bit complement). | | [@lang:bytes.slice](src/helpers/bytes.slice.md) | `bytes` | Extract a byte range from a bytes value. | | [@lang:concat](src/helpers/concat.md) | `array` | Concatenate arrays together. | | [@lang:enumerate](src/helpers/enumerate.md) | `array` | Return an array of [index, element] pairs. | | [@lang:filter](src/helpers/filter.md) | `array` | Keep elements of an array for which a helper returns truthy. | | [@lang:find](src/helpers/find.md) | `any` | Return the first element that satisfies the predicate. | | [@lang:flat](src/helpers/flat.md) | `array` | Flatten one level of nesting in an array. | | [@lang:includes](src/helpers/includes.md) | `bool` | Check whether an array contains an element. | | [@lang:len](src/helpers/len.md) | `number` | Return the length of an array. | | [@lang:map](src/helpers/map.md) | `array` | Transform each element of an array by applying a helper. | | [@lang:num.format](src/helpers/num.format.md) | `string` | Format a number with decimal places (like formatUnits). | | [@lang:num.parse](src/helpers/num.parse.md) | `number` | Parse a decimal string with a given number of decimals (like parseUnits). | | [@lang:reduce](src/helpers/reduce.md) | `any` | Reduce an array to a single value by applying a helper. | | [@lang:reverse](src/helpers/reverse.md) | `array` | Return a new array with elements in reverse order. | | [@lang:slice](src/helpers/slice.md) | `array` | Extract a section of an array. | | [@lang:sort](src/helpers/sort.md) | `array` | Sort an array using a comparator helper. | | [@lang:str.at](src/helpers/str.at.md) | `string` | Access a character by index in a string. | | [@lang:str.concat](src/helpers/str.concat.md) | `string` | Concatenate strings together. | | [@lang:str.includes](src/helpers/str.includes.md) | `bool` | Check whether a string contains a substring. | | [@lang:str.join](src/helpers/str.join.md) | `string` | Join array elements into a string with a delimiter. | | [@lang:str.len](src/helpers/str.len.md) | `number` | Return the length of a string. | | [@lang:str.lower](src/helpers/str.lower.md) | `string` | Convert a string to lowercase. | | [@lang:str.replace](src/helpers/str.replace.md) | `string` | Replace all occurrences of a substring. | | [@lang:str.slice](src/helpers/str.slice.md) | `string` | Extract a section of a string. | | [@lang:str.split](src/helpers/str.split.md) | `array` | Split a string by a delimiter into an array of strings. | | [@lang:str.upper](src/helpers/str.upper.md) | `string` | Convert a string to uppercase. | | [@lang:unique](src/helpers/unique.md) | `array` | Remove duplicates from an array, preserving first-occurrence order. | | [@lang:unzip](src/helpers/unzip.md) | `array` | Transpose an array of pairs into two separate arrays. | | [@lang:zip](src/helpers/zip.md) | `array` | Combine two arrays element-wise into an array of pairs. | --- --- title: "@lang:all" --- Return true if every element satisfies the predicate. **Returns**: `bool` ## Syntax ```evml @lang:all(arr fn) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | | `fn` | `helper` | Predicate helper returning bool | ## See Also - [@any](any.md) — true if at least one matches - [@filter](filter.md) — keep matching elements --- --- title: "@lang:any" --- Return true if at least one element satisfies the predicate. **Returns**: `bool` ## Syntax ```evml @lang:any(arr fn) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | | `fn` | `helper` | Predicate helper returning bool | ## See Also - [@all](all.md) — true if all match - [@filter](filter.md) — keep matching elements --- --- title: "@lang:at" --- Access an element by index in an array. **Returns**: `any` ## Syntax ```evml @lang:at(value index) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `array` | Input value | | `index` | `number` | Zero-based index (negative counts from end) | ## See Also - [@slice](slice.md) — extract a sub-array --- --- title: "@lang:bytes.at" --- Access a single byte by index in a bytes value. **Returns**: `bytes` ## Syntax ```evml @lang:bytes.at(value index) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `bytes` | Input value | | `index` | `number` | Zero-based byte index | ## See Also - [@bytes.slice](bytes.slice.md) — extract a byte range - [@at](at.md) — array element access --- --- title: "@lang:bytes.concat" --- Concatenate bytes values together. **Returns**: `bytes` ## Syntax ```evml @lang:bytes.concat(first ...rest) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `first` | `bytes` | First bytes value | | `[...rest]` | `bytes` | Bytes values to append | ## See Also - [@concat](concat.md) — concatenate arrays - [@str.concat](str.concat.md) — concatenate strings --- --- title: "@lang:bytes.len" --- Return the byte length of a bytes value. **Returns**: `number` ## Syntax ```evml @lang:bytes.len(value) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `bytes` | Input value | ## See Also - [@len](len.md) — array length - [@str.len](str.len.md) — string length --- --- title: "@lang:bytes.not" --- Bitwise NOT of a bytes value (256-bit complement). **Returns**: `bytes` ## Syntax ```evml @lang:bytes.not(value) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `bytes` | Input value | ## See Also - [@bytes](../../../std/src/helpers/bytes.md) — bitwise AND, OR, shift --- --- title: "@lang:bytes.slice" --- Extract a byte range from a bytes value. **Returns**: `bytes` ## Syntax ```evml @lang:bytes.slice(value start end?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `bytes` | Input value | | `start` | `number` | Start index (inclusive) | | `[end]` | `number` | End index (exclusive) | ## See Also - [@bytes.at](bytes.at.md) — access a single byte - [@slice](slice.md) — array slice --- --- title: "@lang:concat" --- Concatenate arrays together. **Returns**: `array` ## Syntax ```evml @lang:concat(first ...rest) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `first` | `array` | First array to concatenate | | `[...rest]` | `array` | Additional arrays to append | ## See Also - [@flat](flat.md) — flatten nested arrays --- --- title: "@lang:enumerate" --- Return an array of [index, element] pairs. **Returns**: `array` ## Syntax ```evml @lang:enumerate(arr) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | ## See Also - [loop](../../../std/src/commands/loop.md) — iterate over arrays - [@zip](zip.md) — combine two arrays into pairs --- --- title: "@lang:filter" --- Keep elements of an array for which a helper returns truthy. **Returns**: `array` ## Syntax ```evml @lang:filter(arr fn) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | | `fn` | `helper` | Predicate helper returning bool | ## See Also - [@find](find.md) — return the first match - [@all](all.md) — check if all elements match - [@any](any.md) — check if any element matches - [@map](map.md) — transform each element --- --- title: "@lang:find" --- Return the first element that satisfies the predicate. **Returns**: `any` ## Syntax ```evml @lang:find(arr fn) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | | `fn` | `helper` | Predicate helper returning bool | ## See Also - [@filter](filter.md) — return all matches - [@includes](includes.md) — check if element exists --- --- title: "@lang:flat" --- Flatten one level of nesting in an array. **Returns**: `array` ## Syntax ```evml @lang:flat(arr) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | ## See Also - [@concat](concat.md) — concatenate arrays - [@map](map.md) — transform then flatten with `@flat(@map(...))` --- --- title: "@lang:includes" --- Check whether an array contains an element. **Returns**: `bool` ## Syntax ```evml @lang:includes(value item) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `array` | Input value | | `item` | `any` | Element to search for | ## See Also - [@find](find.md) — find the first matching element - [@filter](filter.md) — keep all matching elements --- --- title: "@lang:len" --- Return the length of an array. **Returns**: `number` ## Syntax ```evml @lang:len(value) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `array` | Input value | ## See Also - [@at](at.md) — access element by index - [@slice](slice.md) — extract a sub-array - [@str.len](str.len.md) — string length --- --- title: "@lang:map" --- Transform each element of an array by applying a helper. **Returns**: `array` ## Syntax ```evml @lang:map(arr fn) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | | `fn` | `helper` | Transform helper applied to each element | ## See Also - [@filter](filter.md) — keep elements by predicate - [@reduce](reduce.md) — fold an array to a single value - [loop](../../../std/src/commands/loop.md) — imperative iteration --- --- title: "@lang:num.format" --- Format a number with decimal places (like formatUnits). **Returns**: `string` ## Syntax ```evml @lang:num.format(value decimals) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `number` | Input value | | `decimals` | `number` | Number of decimal places | ## See Also - [@num.parse](num.parse.md) — inverse: parse a decimal string - [@token:amount](../../../token/src/helpers/amount.md) — token-aware unit conversion --- --- title: "@lang:num.parse" --- Parse a decimal string with a given number of decimals (like parseUnits). **Returns**: `number` ## Syntax ```evml @lang:num.parse(value decimals) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `string \| number` | Input value | | `decimals` | `number` | Number of decimal places | ## See Also - [@num.format](num.format.md) — inverse: format an integer with decimals - [@token:amount](../../../token/src/helpers/amount.md) — token-aware unit conversion --- --- title: "@lang:reduce" --- Reduce an array to a single value by applying a helper. **Returns**: `any` ## Syntax ```evml @lang:reduce(arr fn initial) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | | `fn` | `helper` | Reducer helper receiving `(accumulator, element)` | | `initial` | `any` | Initial accumulator value | ## See Also - [@map](map.md) — transform each element - [@filter](filter.md) — keep elements by predicate --- --- title: "@lang:reverse" --- Return a new array with elements in reverse order. **Returns**: `array` ## Syntax ```evml @lang:reverse(arr) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | ## See Also - [@sort](sort.md) — sort by comparator --- --- title: "@lang:slice" --- Extract a section of an array. **Returns**: `array` ## Syntax ```evml @lang:slice(value start end?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `array` | Input value | | `start` | `number` | Start index (inclusive) | | `[end]` | `number` | End index (exclusive) | ## See Also - [@at](at.md) — access a single element - [@len](len.md) — array length --- --- title: "@lang:sort" --- Sort an array using a comparator helper. **Returns**: `array` ## Syntax ```evml @lang:sort(arr fn) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | | `fn` | `helper` | Comparator helper returning a number | ## See Also - [@reverse](reverse.md) — reverse an array --- --- title: "@lang:str.at" --- Access a character by index in a string. **Returns**: `string` ## Syntax ```evml @lang:str.at(value index) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `string` | Input value | | `index` | `number` | Zero-based character index | ## See Also - [@str.slice](str.slice.md) — extract a substring - [@at](at.md) — array element access --- --- title: "@lang:str.concat" --- Concatenate strings together. **Returns**: `string` ## Syntax ```evml @lang:str.concat(first ...rest) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `first` | `string` | First string segment | | `[...rest]` | `string` | Strings to append | ## See Also - [@str.join](str.join.md) — join array elements with a delimiter - [@concat](concat.md) — concatenate arrays --- --- title: "@lang:str.includes" --- Check whether a string contains a substring. **Returns**: `bool` ## Syntax ```evml @lang:str.includes(value item) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `string` | Input value | | `item` | `string` | Substring to search for | ## See Also - [@str.replace](str.replace.md) — find and replace - [@includes](includes.md) — array membership check --- --- title: "@lang:str.join" --- Join array elements into a string with a delimiter. **Returns**: `string` ## Syntax ```evml @lang:str.join(arr delim) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | | `delim` | `string` | Delimiter string | ## See Also - [@str.split](str.split.md) — split a string into an array - [@str.concat](str.concat.md) — concatenate strings --- --- title: "@lang:str.len" --- Return the length of a string. **Returns**: `number` ## Syntax ```evml @lang:str.len(value) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `string` | Input value | ## See Also - [@str.slice](str.slice.md) — extract a substring - [@len](len.md) — array length --- --- title: "@lang:str.lower" --- Convert a string to lowercase. **Returns**: `string` ## Syntax ```evml @lang:str.lower(s) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `s` | `string` | Source string | ## See Also - [@str.upper](str.upper.md) — convert to uppercase --- --- title: "@lang:str.replace" --- Replace all occurrences of a substring. **Returns**: `string` ## Syntax ```evml @lang:str.replace(s old replacement) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `s` | `string` | Source string | | `old` | `string` | Substring to match | | `replacement` | `string` | Replacement text | ## See Also - [@str.includes](str.includes.md) — check for substring - [@str.split](str.split.md) — split by delimiter --- --- title: "@lang:str.slice" --- Extract a section of a string. **Returns**: `string` ## Syntax ```evml @lang:str.slice(value start end?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `value` | `string` | Input value | | `start` | `number` | Start index (inclusive) | | `[end]` | `number` | End index (exclusive) | ## See Also - [@str.at](str.at.md) — access a single character - [@slice](slice.md) — array slice --- --- title: "@lang:str.split" --- Split a string by a delimiter into an array of strings. **Returns**: `array` ## Syntax ```evml @lang:str.split(s delim) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `s` | `string` | Source string | | `delim` | `string` | Delimiter string | ## See Also - [@str.join](str.join.md) — join array into a string --- --- title: "@lang:str.upper" --- Convert a string to uppercase. **Returns**: `string` ## Syntax ```evml @lang:str.upper(s) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `s` | `string` | Source string | ## See Also - [@str.lower](str.lower.md) — convert to lowercase --- --- title: "@lang:unique" --- Remove duplicates from an array, preserving first-occurrence order. **Returns**: `array` ## Syntax ```evml @lang:unique(arr) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `arr` | `array` | Source array | ## See Also - [@filter](filter.md) — custom duplicate removal --- --- title: "@lang:unzip" --- Transpose an array of pairs into two separate arrays. **Returns**: `array` ## Syntax ```evml @lang:unzip(pairs) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `pairs` | `array` | Array of [a, b] pairs | ## See Also - [@zip](zip.md) — combine two arrays into pairs --- --- title: "@lang:zip" --- Combine two arrays element-wise into an array of pairs. **Returns**: `array` ## Syntax ```evml @lang:zip(a b) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `a` | `array` | First array to zip | | `b` | `array` | Second array | ## See Also - [@unzip](unzip.md) — split pairs into two arrays - [@enumerate](enumerate.md) — pair elements with indices --- # sim module Simulation module: fork chains and execute commands in a sandboxed environment using Anvil, Hardhat, Tenderly, EthereumJS or Revm (WASM) backends. Forks are multichain: `switch` moves between one fork per chain, and bridge transfers are auto-relayed to the destination fork. ```evml load sim ``` ## Commands | Command | Description | |---------|-------------| | [sim:expect](src/commands/expect.md) | Assert that a condition is true. | | [sim:fork](src/commands/fork.md) | Fork the blockchain and execute commands in a simulation. | | [sim:set-balance](src/commands/set-balance.md) | Set the ETH balance of an account in a fork simulation. | | [sim:set-code](src/commands/set-code.md) | Set the bytecode at an address in a fork simulation. | | [sim:set-storage-at](src/commands/set-storage-at.md) | Set a storage slot value at an address in a fork simulation. | --- --- title: "sim:expect" --- Assert that a condition is true. ## Syntax ```evml sim:expect ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `condition` | `bool` | Boolean condition to assert | ## Examples ```evml # Assert a simple condition sim:expect true # Assert with variables set $a 42 sim:expect @bool($a == 42) ``` ## Notes - If the condition is false, the script halts with an assertion error - Typically used inside `sim:fork` blocks to verify simulated outcomes ## See Also - [fork](fork.md) — simulate on a forked chain - [@bool](../../../std/src/helpers/bool.md) — boolean expressions --- --- title: "sim:fork" --- Fork the blockchain and execute commands in a simulation. ## Syntax ```evml sim:fork ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `block` | `block` | Commands to execute in the fork | ## Options | Name | Type | Description | |------|------|-------------| | `--block-number` | `number` | Block number to fork from | | `--from` | `address` | Default sender address | | `--auth-token` | `string` | RPC provider authentication token | | `--using` | `simulation-mode` | Simulation backend (anvil, hardhat, tenderly, tenderly-multichain, ethereumjs, revm) | ## Examples ```evml # Fork and set account balance sim:fork --using anvil ( sim:set-balance @me 100e18 ) ``` ## Notes - Supported backends: `anvil`, `hardhat`, `tenderly`, `tenderly-multichain`, `ethereumjs` (default), `revm` - The `ethereumjs` and `revm` backends run entirely in the browser — no external node needed - `revm` executes on the Rust EVM compiled to WebAssembly: much faster opcode execution than `ethereumjs` on compute-heavy simulations, with identical semantics (state still streams lazily from the upstream RPC) - All commands inside the fork block execute against the simulated state - Changes do not affect the real chain - `batch (...)` inside a fork simulates an EIP-7702 batch: if the sender EOA has no delegation yet, the fork installs a delegation to MetaMask's EIP7702StatelessDeleGator (`0x63c0c19a282a1B52b07dD5a65b58948A07DAE32B`) and executes all batched calls atomically in a single self-call transaction. An existing delegation on the EOA is reused as-is. ## Cross-chain simulation A fork is **multichain**: `switch` inside a fork block moves between one fork per chain instead of failing, and each chain keeps its own state, so switching back and forth is safe. ```evml load sim load bridges sim:fork --using anvil ( bridges:bridge 100e6 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 to base --using CCTPv2 switch base set $balance @get(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 "balanceOf(address)(uint256)" @me) sim:expect @bool($balance > 0) ) ``` Bridge transfers are **auto-relayed**. When a bridge transaction executes, the fork scans its receipt for the source event; switching to the destination chain then executes the destination leg there — a mocked Circle attestation driving the real `receiveMessage` mint for CCTP, an impersonated relayer fill for Across, an impersonated endpoint calling `lzReceive` for LayerZero, a replayed deposit for the canonical bridges. `bridges:claim` is therefore unnecessary inside a fork. Transfers whose destination chain the script never switches to are reported when the block ends. Each backend hosts the extra chains differently: | Backend | How it goes multichain | |---------|------------------------| | `ethereumjs` (default) | One in-memory fork per chain, created on the first `switch` | | `revm` | Same as `ethereumjs`: one in-memory (WASM) fork per chain | | `tenderly` | One Virtual TestNet per chain | | `tenderly-multichain` | A single multichain Virtual Environment holding every chain the script switches to (one dashboard, one teardown). Its networks are attached when the environment is created, so `switch` targets must be literal | | `anvil` / `hardhat` | The single local node is re-forked on each switch, saving and restoring each chain's state (needs `dumpState`/`loadState`, which Anvil supports) | Limitations: secondary chains fork at their latest block (`--block-number` pins only the starting chain), each fork keeps its own clock (`wait` advances the active one), and a delivered destination leg is not itself relayed onward. ## See Also - [set-balance](set-balance.md) — set account ETH balances - [expect](expect.md) — assert conditions - [wait](../../../std/src/commands/wait.md) — advance time --- --- title: "sim:set-balance" --- Set the ETH balance of an account in a fork simulation. ## Syntax ```evml sim:set-balance
``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Contract or account address | | `amount` | `number` | New balance in wei | ## Examples ```evml # Fund the connected wallet with 100 ETH sim:fork --using anvil ( sim:set-balance @me 100e18 ) ``` ## Notes - Can only be used inside a `sim:fork` block - The amount is in wei (use `e18` for ETH) ## See Also - [fork](fork.md) — create a simulation fork - [set-code](set-code.md) — set contract bytecode - [set-storage-at](set-storage-at.md) — set storage slots --- --- title: "sim:set-code" --- Set the bytecode at an address in a fork simulation. ## Syntax ```evml sim:set-code
``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `string` | Contract or account address | | `bytecode` | `string` | New bytecode to set | ## Examples ```evml # Replace contract bytecode in a fork sim:fork --using anvil ( sim:set-code 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6 0x600160005260206000f3 ) ``` ## See Also - [set-storage-at](set-storage-at.md) — override a storage slot - [fork](fork.md) — fork the chain - [@contracts:codeAt](../../../contracts/src/helpers/codeAt.md) — read bytecode --- --- title: "sim:set-storage-at" --- Set a storage slot value at an address in a fork simulation. ## Syntax ```evml sim:set-storage-at
``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Contract or account address | | `slot` | `bytes32` | Storage slot | | `value` | `string` | New 32-byte value | ## Examples ```evml # Set a storage slot value in a fork sim:fork --using anvil ( sim:set-storage-at 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6 0x0000000000000000000000000000000000000000000000000000000000000001 0x00000000000000000000000000000000000000000000000000000000000000ff ) ``` ## See Also - [set-code](set-code.md) — override contract bytecode - [fork](fork.md) — fork the chain - [@contracts:storageAt](../../../contracts/src/helpers/storageAt.md) — read a storage slot --- # http module HTTP and JSON helpers: fetch URLs, parse JSON, and construct JSON strings. ```evml load http ``` ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@http:fetch](src/helpers/fetch.md) | `string` | Fetch a URL and return the response body as a string. | | [@http:json](src/helpers/json.md) | `any` | Parse a JSON string and extract a value by path. | | [@http:json.format](src/helpers/json.format.md) | `string` | Construct a JSON string from a template and an array of values. | --- --- title: "@http:fetch" --- Fetch a URL and return the response body as a string. **Returns**: `string` ## Syntax ```evml @http:fetch(url method? body? auth?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `url` | `string` | Request URL | | `[method]` | `string` | HTTP method (`GET`, `POST`, etc.) | | `[body]` | `string` | Request body (JSON string) | | `[auth]` | `string` | Authorization header value | ## See Also - [@http:json](json.md) — parse JSON response - [@http:json.format](json.format.md) — build JSON request body --- --- title: "@http:json" --- Parse a JSON string and extract a value by path. **Returns**: `any` ## Syntax ```evml @http:json(data path) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `data` | `string` | JSON string to parse | | `path` | `json-path` | JSONPath expression (e.g. `data.items[0].name`) | ## See Also - [@http:fetch](fetch.md) — fetch a URL - [@http:json.format](json.format.md) — build JSON strings --- --- title: "@http:json.format" --- Construct a JSON string from a template and an array of values. **Returns**: `string` ## Syntax ```evml @http:json.format(template values) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `template` | `string` | Brace-wrapped template listing JSON object keys | | `values` | `array` | Values to substitute into template | ## See Also - [@http:json](json.md) — parse JSON strings - [@http:fetch](fetch.md) — fetch a URL --- # ens module ENS domain operations: renewal and content hash encoding. ```evml load ens ``` ## Commands | Command | Description | |---------|-------------| | [ens:register](src/commands/register.md) | Register a .eth name via the controller's commit/reveal flow (commits, waits and reveals in one go by default). | | [ens:renew](src/commands/renew.md) | Renew ENS domain registrations via bulk renewal. | | [ens:set-addr](src/commands/set-addr.md) | Set the address record of an ENS name. | | [ens:set-contenthash](src/commands/set-contenthash.md) | Set the content hash of an ENS name. | | [ens:set-primary-name](src/commands/set-primary-name.md) | Set the primary ENS name (reverse record) of the calling account. | | [ens:set-resolver](src/commands/set-resolver.md) | Set the resolver contract of an ENS name. | | [ens:set-text](src/commands/set-text.md) | Set a text record on an ENS name. | | [ens:transfer](src/commands/transfer.md) | Transfer ownership of an ENS name. For unwrapped .eth names this hands over both the registrant NFT and the Registry controller (reclaim); transferring to the current registrant just reclaims the controller role. | ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@ens:addr](src/helpers/addr.md) | `address` | Resolve an ENS name to an address, optionally per coin type. | | [@ens:available](src/helpers/available.md) | `bool` | Check whether a .eth name is available for registration. | | [@ens:avatar](src/helpers/avatar.md) | `string` | Get the avatar URI for an ENS name. | | [@ens:cointype](src/helpers/cointype.md) | `number` | ENSIP-11 coin type of an EVM chain, for multichain address records. | | [@ens:cointype.decode](src/helpers/cointype.decode.md) | `string` | Chain name of an ENSIP-11 coin type (the inverse of @ens:cointype). | | [@ens:contenthash](src/helpers/contenthash.md) | `bytes` | Encode a content hash (ipfs, ipns, skynet) for ENS records. | | [@ens:contenthash.of](src/helpers/contenthash.of.md) | `string` | Read the decoded content hash of an ENS name (e.g. ipfs://…). | | [@ens:expiry](src/helpers/expiry.md) | `number` | Registration expiry timestamp of a .eth name. | | [@ens:labelhash](src/helpers/labelhash.md) | `bytes32` | Compute the ENS labelhash of a single label. | | [@ens:name](src/helpers/name.md) | `string` | Reverse-resolve an address to its primary ENS name. | | [@ens:namehash](src/helpers/namehash.md) | `bytes32` | Compute the ENS namehash of a domain name. | | [@ens:normalize](src/helpers/normalize.md) | `string` | Normalize an ENS name per ENSIP-15. | | [@ens:owner](src/helpers/owner.md) | `address` | Get the owner of an ENS name (the real owner when the name is wrapped). | | [@ens:rentPrice](src/helpers/rentPrice.md) | `number` | Total price in wei to register or renew a .eth name for a duration. | | [@ens:resolver](src/helpers/resolver.md) | `address` | Get the resolver contract address of an ENS name. | | [@ens:text](src/helpers/text.md) | `string` | Read a text record from an ENS name. | --- --- title: "ens:register" --- Register a .eth name via the controller's commit/reveal flow (commits, waits and reveals in one go by default). ## Syntax ```evml ens:register ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | .eth name or label (e.g. mydao.eth or mydao) | | `owner` | `address` | Owner of the name | | `duration` | `number` | Registration duration, in time units (e.g. 1y) | ## Options | Name | Type | Description | |------|------|-------------| | `--secret` | `bytes32` | Commitment secret; must be identical across the commit and reveal steps | | `--resolver` | `address` | Resolver to set at registration (defaults to the chain's Public Resolver) | | `--reverse-record` | `bool` | Also set the owner's primary ENS name | | `--step` | `string` | Which part of the flow to run: commit-wait-reveal (default), only-commit, only-reveal, only-commit-and-wait, only-wait-and-reveal | ## Examples ```evml load ens # Commit, wait ~60s and reveal in one script (default) ens:register mydao @me 1y --secret @hash("my registration secret") --resolver 0xF29100983E058B709F3D539b0c765937B804AC15 --reverse-record true # Split the flow across two scripts (e.g. two DAO votes) ens:register mydao @me 1y --secret @hash("my registration secret") --step only-commit ens:register mydao @me 1y --secret @hash("my registration secret") --step only-reveal ``` ## Notes - Registration is a commit/reveal flow. By default the command emits the commit transaction, a real-time wait for the controller's minimum commitment age (plus a small margin), and the reveal transaction. In fork simulations the wait is instant — the fork's clock is warped instead. - `--step` selects which part runs: `commit-wait-reveal` (default), `only-commit`, `only-reveal`, `only-commit-and-wait`, `only-wait-and-reveal`. All steps must use identical arguments and `--secret`, otherwise the reveal won't find the commitment. - The reveal sends the rent price plus a 2% buffer; the controller refunds any excess. - `--reverse-record` also sets the owner's primary ENS name. ## See Also - [@ens:rentPrice](../helpers/rentPrice.md) — price a registration - [@ens:available](../helpers/available.md) — check availability first --- --- title: "ens:renew" --- Renew ENS domain registrations via bulk renewal. ## Syntax ```evml ens:renew ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `domains` | `string \| array` | ENS label(s) or names to renew | | `duration` | `number` | Renewal duration, in time units (e.g. 1y) | ## Examples ``` load ens # Renew a single domain for one year ens:renew "mydomain" 1y # Renew multiple domains at once ens:renew ["domain1" "domain2" "domain3"] 1y ``` ## Notes - Only works on Ethereum mainnet (chain ID 1) - Uses the ENS bulk renewal contract ## See Also - [@ens:contenthash](../helpers/contenthash.md) — encode content hashes - [@ens](../../../std/src/helpers/md) — resolve ENS names --- --- title: "ens:set-addr" --- Set the address record of an ENS name. ## Syntax ```evml ens:set-addr
[coinType] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. mydao.eth) | | `address` | `address` | Address to set | | `[coinType]` | `number` | ENSIP-9/11 coin type (defaults to 60, ETH; e.g. @cointype(optimism); only EVM-style addresses are supported) | ## Examples ```evml load ens # Point mydao.eth at the executing account ens:set-addr mydao.eth @me # Set the address for an EVM L2 (ENSIP-11 coin type) ens:set-addr mydao.eth 0x1234567890abcdef1234567890abcdef12345678 @ens:cointype(optimism) ``` ## Notes - Without a coin type the default ETH record (coin type 60) is set. - Only EVM-style (20-byte hex) addresses are supported for non-default coin types. ## See Also - [@ens:addr](../helpers/addr.md) — resolve an address record - [@ens:cointype](../helpers/cointype.md) — coin type of an EVM chain - [ens:set-primary-name](set-primary-name.md) — set the reverse record --- --- title: "ens:set-contenthash" --- Set the content hash of an ENS name. ## Syntax ```evml ens:set-contenthash ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. mydao.eth) | | `hash` | `string` | Content hash ("ipfs://Qm…", "ipns://…", "skynet://…" or encoded 0x bytes) | ## Examples ```evml load ens # Point mydao.eth at an IPFS CID ens:set-contenthash mydao.eth "ipfs://QmRAQB6YaCyidP37UdDnjFY5vQuiBrcqdyoW1CuDgwxkD4" # Point at an IPNS name ens:set-contenthash mydao.eth "ipns://k51qzi5uqu5dlvj2baxnqndepeb86cbk3ng7n3i46uzyxzyqj2xjonzllnv0v8" ``` ## Notes - Accepts `ipfs`, `ipns` and `skynet` URIs (`codec:hash` or `codec://hash`) or already-encoded EIP-1577 `0x` bytes (e.g. from `@ens:contenthash`). ## See Also - [@ens:contenthash](../helpers/contenthash.md) — encode a content hash - [@ens:contenthash.of](../helpers/contenthash.of.md) — read a content hash --- --- title: "ens:set-primary-name" --- Set the primary ENS name (reverse record) of the calling account. ## Syntax ```evml ens:set-primary-name ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. mydao.eth) | ## Options | Name | Type | Description | |------|------|-------------| | `--for` | `address` | Set the primary name of this contract instead (the caller must be the contract, its Ownable owner, or an approved operator) | ## Examples ```evml load ens # Name the executing account (e.g. a DAO agent or Safe running this script) ens:set-primary-name mydao.eth # Name a contract owned by the executing account ens:set-primary-name treasury.mydao.eth --for 0x1234567890abcdef1234567890abcdef12345678 ``` ## Notes - The reverse record only counts as a primary name when the forward record matches: make sure `mydao.eth` resolves to the account first (see `ens:set-addr`). - With `--for`, the caller must be the target contract itself, its `Ownable` owner, or an approved operator on the Reverse Registrar. ## See Also - [ens:set-addr](set-addr.md) — set the forward address record --- --- title: "ens:set-resolver" --- Set the resolver contract of an ENS name. ## Syntax ```evml ens:set-resolver ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. mydao.eth) | | `resolver` | `address` | Resolver address | ## Examples ```evml load ens # Switch mydao.eth to the latest public resolver ens:set-resolver mydao.eth 0xF29100983E058B709F3D539b0c765937B804AC15 ``` ## Notes - Wrapped names are handled automatically (the action goes through the NameWrapper instead of the registry). ## See Also - [@ens:resolver](../helpers/resolver.md) — read the current resolver --- --- title: "ens:set-text" --- Set a text record on an ENS name. ## Syntax ```evml ens:set-text ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. mydao.eth) | | `key` | `string` | Text record key (e.g. "url", "com.twitter") | | `value` | `string` | Text record value | ## Examples ```evml load ens # Set common text records on a name you own ens:set-text mydao.eth url "https://mydao.example" ens:set-text mydao.eth com.twitter "mydao" ens:set-text mydao.eth description "Community-owned treasury" ``` ## Notes - The action is sent to the name's current resolver; the executing account must own (or operate) the name. ## See Also - [@ens:text](../helpers/text.md) — read a text record --- --- title: "ens:transfer" --- Transfer ownership of an ENS name. For unwrapped .eth names this hands over both the registrant NFT and the Registry controller (reclaim); transferring to the current registrant just reclaims the controller role. ## Syntax ```evml ens:transfer ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. mydao.eth) | | `to` | `command` | Keyword `to` | | `newOwner` | `address` | New owner address | ## Examples ```evml load ens # Hand a name over to the DAO agent ens:transfer mydao.eth to 0x1234567890abcdef1234567890abcdef12345678 # Reclaim registry control of a name you received without a reclaim ens:transfer mydao.eth to @me ``` ## Notes - Wrapped names transfer the NameWrapper ERC-1155 token; everything that is neither wrapped nor a `.eth` second-level name uses `setOwner` on the registry. - Unwrapped `.eth` second-level names hand over both roles: the Registry controller (via `reclaim`) and the registrant NFT, in that order. - Transferring an unwrapped `.eth` name to its current registrant is a pure `reclaim`: it resets the Registry controller without moving the NFT — useful after receiving a name from someone who didn't reclaim. ## See Also - [@ens:owner](../helpers/owner.md) — read the current owner --- --- title: "@ens:addr" --- Resolve an ENS name to an address, optionally per coin type. **Returns**: `address` ## Syntax ```evml @ens:addr(name coinType?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. vitalik.eth) | | `[coinType]` | `number` | ENSIP-9/11 coin type (defaults to 60, ETH) | ## Examples ```evml # Resolve a name to an address set $addr @ens:addr("vitalik.eth") print $addr ``` ## See Also --- --- title: "@ens:available" --- Check whether a .eth name is available for registration. **Returns**: `bool` ## Syntax ```evml @ens:available(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | .eth name or label (e.g. vitalik.eth or vitalik) | ## Examples ```evml # Check availability before registering set $free @ens:available("mydao.eth") print $free ``` ## See Also --- --- title: "@ens:avatar" --- Get the avatar URI for an ENS name. **Returns**: `string` ## Syntax ```evml @ens:avatar(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. vitalik.eth) | ## Examples ```evml # Get the avatar for an ENS name set $avatar @ens:avatar("vitalik.eth") print $avatar ``` ## See Also - [@ens:name](name.md) — reverse-resolve an address - [@ens:text](text.md) — read a text record --- --- title: "@ens:cointype" --- ENSIP-11 coin type of an EVM chain, for multichain address records. **Returns**: `number` ## Syntax ```evml @ens:cointype(chain?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[chain]` | `chain` | Chain name or id (e.g. optimism, 10); defaults to the connected chain | ## Examples ```evml # Coin type for an L2 address record set $ct @ens:cointype(optimism) print $ct ``` ## See Also --- --- title: "@ens:cointype.decode" --- Chain name of an ENSIP-11 coin type (the inverse of @ens:cointype). **Returns**: `string` ## Syntax ```evml @ens:cointype.decode(coinType) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `coinType` | `number` | ENSIP-11 coin type (e.g. 60, 2147483658) | ## Examples ```evml # Find out which chain a coin type belongs to set $chain @ens:cointype.decode(2147483658) print $chain ``` ## See Also --- --- title: "@ens:contenthash" --- Encode a content hash (ipfs, ipns, skynet) for ENS records. **Returns**: `bytes` ## Syntax ```evml @ens:contenthash(input) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `input` | `string` | Content hash (e.g. "ipfs:Qm...") | ## Examples ```evml # Encode an IPFS content hash set $hash @ens:contenthash("ipfs:QmRAQB6YaCyidP37UdDnjFY5vQuiBrcqdyoW1CuDgwxkD4") print $hash ``` ## Notes - Supported codecs: `ipfs`, `ipns`, `skynet` - Format: `codec:hash` ## See Also - [ens:renew](../commands/renew.md) — renew ENS domains - [@ipfs](../../../std/src/helpers/ipfs.md) — upload content to IPFS --- --- title: "@ens:contenthash.of" --- Read the decoded content hash of an ENS name (e.g. ipfs://…). **Returns**: `string` ## Syntax ```evml @ens:contenthash.of(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. vitalik.eth) | ## Examples ```evml # Read the content hash behind a name set $hash @ens:contenthash.of("vitalik.eth") print $hash ``` ## See Also --- --- title: "@ens:expiry" --- Registration expiry timestamp of a .eth name. **Returns**: `number` ## Syntax ```evml @ens:expiry(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | .eth second-level name (e.g. vitalik.eth) | ## Examples ```evml # Check when a name expires set $expiry @ens:expiry("vitalik.eth") print $expiry ``` ## See Also --- --- title: "@ens:labelhash" --- Compute the ENS labelhash of a single label. **Returns**: `bytes32` ## Syntax ```evml @ens:labelhash(label) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `label` | `string` | Single ENS label (e.g. `vitalik`, no dots) | ## Examples ```evml # Hash a single ENS label set $label @ens:labelhash("vitalik") ``` ## See Also --- --- title: "@ens:name" --- Reverse-resolve an address to its primary ENS name. **Returns**: `string` ## Syntax ```evml @ens:name(address) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Address to resolve | ## Examples ```evml # Reverse-resolve an address to an ENS name set $name @ens:name(0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045) print $name ``` ## See Also - [@ens:avatar](avatar.md) — get the avatar URI - [@ens:text](text.md) — read a text record --- --- title: "@ens:namehash" --- Compute the ENS namehash of a domain name. **Returns**: `bytes32` ## Syntax ```evml @ens:namehash(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS domain name | ## Examples ```evml # Hash an ENS domain set $node @ens:namehash("vitalik.eth") ``` ## See Also --- --- title: "@ens:normalize" --- Normalize an ENS name per ENSIP-15. **Returns**: `string` ## Syntax ```evml @ens:normalize(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name to normalize | ## Examples ```evml # Normalize a mixed-case name set $name @ens:normalize("MyDAO.eth") print $name ``` ## See Also --- --- title: "@ens:owner" --- Get the owner of an ENS name (the real owner when the name is wrapped). **Returns**: `address` ## Syntax ```evml @ens:owner(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. vitalik.eth) | ## Examples ```evml # Get the owner of a name set $owner @ens:owner("vitalik.eth") print $owner ``` ## See Also --- --- title: "@ens:rentPrice" --- Total price in wei to register or renew a .eth name for a duration. **Returns**: `number` ## Syntax ```evml @ens:rentPrice(name duration) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | .eth name or label (e.g. vitalik.eth or vitalik) | | `duration` | `number` | Duration, in time units (e.g. 1y) | ## Examples ```evml # Price of one year of registration set $price @ens:rentPrice("mydao.eth" 1y) print $price ``` ## See Also --- --- title: "@ens:resolver" --- Get the resolver contract address of an ENS name. **Returns**: `address` ## Syntax ```evml @ens:resolver(name) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. vitalik.eth) | ## Examples ```evml # Get the resolver of a name set $resolver @ens:resolver("vitalik.eth") print $resolver ``` ## See Also --- --- title: "@ens:text" --- Read a text record from an ENS name. **Returns**: `string` ## Syntax ```evml @ens:text(name key) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `name` | `string` | ENS name (e.g. vitalik.eth) | | `key` | `string` | Text record key (e.g. "url", "com.twitter", "description") | ## Examples ```evml # Read a URL text record set $url @ens:text("vitalik.eth" "url") print $url # Read a Twitter handle set $twitter @ens:text("vitalik.eth" "com.twitter") print $twitter ``` ## See Also - [@ens:name](name.md) — reverse-resolve an address - [@ens:avatar](avatar.md) — get the avatar URI --- # token module Token operations: mint, burn, and approvals. ```evml load token ``` ## Commands | Command | Description | |---------|-------------| | [token:approve](src/commands/approve.md) | Approve a spender for an ERC20 token allowance. | | [token:burn](src/commands/burn.md) | Burn tokens from the connected account (ERC20Burnable burn function). | | [token:burn-from](src/commands/burn-from.md) | Burn tokens from another account, consuming the sender allowance (ERC20Burnable burnFrom function). | | [token:disperse](src/commands/disperse.md) | Transfer a token to multiple recipients, encoding one transfer per recipient. | | [token:mint](src/commands/mint.md) | Mint tokens to an account. Calls the mint(address,uint256) function commonly exposed by OpenZeppelin-based ERC20 tokens (usually role- or owner-gated). | | [token:permit](src/commands/permit.md) | Approve a spender through an EIP-2612 permit signed by the connected wallet, encoded as a permit() call anyone can submit. | | [token:set-approval-for-all](src/commands/set-approval-for-all.md) | Approve or revoke an operator for all ERC721 or ERC1155 tokens of the connected account. | | [token:transfer](src/commands/transfer.md) | Transfer ERC20 tokens from the connected account to a recipient. | | [token:transfer-from](src/commands/transfer-from.md) | Transfer ERC20 tokens from one account to another, consuming the sender allowance. | ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@token:allowance](src/helpers/allowance.md) | `number` | Fetch the allowance an owner has granted to a spender, in base units. | | [@token:amount](src/helpers/amount.md) | `number` | Convert a human-readable token amount to its base unit (applying decimals). | | [@token:balance](src/helpers/balance.md) | `number` | Fetch the token balance of an address in base units. | | [@token:decimals](src/helpers/decimals.md) | `number` | Return the number of decimals of a token. | | [@token:format](src/helpers/format.md) | `string` | Format a base-unit token amount as a human-readable string with the token symbol. | | [@token:symbol](src/helpers/symbol.md) | `string` | Return the symbol of a token. | | [@token:totalSupply](src/helpers/totalSupply.md) | `number` | Fetch the total supply of a token in base units. | --- --- title: "token:approve" --- Approve a spender for an ERC20 token allowance. ## Syntax ```evml token:approve ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `number` | Allowance in token units (wei) | | `token` | `address` | Token address | | `for` | `command` | Keyword `for` | | `spender` | `address` | Spender address | ## Examples ```evml load token set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb set $spender 0x4F2083f5fBede34C2714aFfb3105539775f7FE64 token:approve 100e18 $token for $spender # Revoke an allowance token:approve 0 $token for $spender ``` ## See Also - [token:burn-from](burn-from.md) / [token:set-approval-for-all](set-approval-for-all.md) --- --- title: "token:burn" --- Burn tokens from the connected account (ERC20Burnable burn function). ## Syntax ```evml token:burn ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `number` | Amount in token units (wei) | | `token` | `address` | Token address | ## Examples ```evml load token set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb token:burn 100e18 $token ``` ## Notes - Burns from the connected account (ERC20Burnable). ## See Also - [token:burn-from](burn-from.md) — burn from another account via allowance --- --- title: "token:burn-from" --- Burn tokens from another account, consuming the sender allowance (ERC20Burnable burnFrom function). ## Syntax ```evml token:burn-from ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `number` | Amount in token units (wei) | | `token` | `address` | Token address | | `from` | `command` | Keyword `from` | | `account` | `address` | Account to burn from | ## Examples ```evml load token set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb token:burn-from 100e18 $token from 0x4F2083f5fBede34C2714aFfb3105539775f7FE64 ``` ## Notes - Consumes the sender allowance on the burned account, like transferFrom. ## See Also - [token:approve](approve.md) — the account must approve the sender first --- --- title: "token:disperse" --- Transfer a token to multiple recipients, encoding one transfer per recipient. ## Syntax ```evml token:disperse ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `token` | `address` | Token address | | `recipients` | `array` | Recipient addresses | | `amounts` | `array \| number` | Per-recipient amounts in token units (wei), or a single amount sent to every recipient | ## Examples ```evml load token set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb set $alice 0x4F2083f5fBede34C2714aFfb3105539775f7FE64 set $bob 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6 # Pay each recipient its own amount token:disperse $token [$alice $bob] [100e18 50e18] # Send the same amount to every recipient token:disperse $token [$alice $bob] 10e18 ``` ## See Also - [token:transfer](transfer.md) - [loop](../../../std/src/commands/loop.md) — for payouts that need per-recipient logic --- --- title: "token:mint" --- Mint tokens to an account. Calls the mint(address,uint256) function commonly exposed by OpenZeppelin-based ERC20 tokens (usually role- or owner-gated). ## Syntax ```evml token:mint ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `number` | Amount in token units (wei) | | `token` | `address` | Token address | | `to` | `command` | Keyword `to` | | `account` | `address` | Recipient | ## Examples ```evml load token set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb token:mint 100e18 $token to @me ``` ## Notes - `mint(address,uint256)` is not part of the ERC20 standard — it exists only where the contract exposes it (OpenZeppelin Wizard-style tokens), usually gated by MINTER_ROLE or the owner. ## See Also - [acl:grant](../../../acl/src/commands/grant.md) — grant MINTER_ROLE first - [token:burn](burn.md) --- --- title: "token:permit" --- Approve a spender through an EIP-2612 permit signed by the connected wallet, encoded as a permit() call anyone can submit. ## Syntax ```evml token:permit ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `number` | Allowance in token units (wei) | | `token` | `address` | Token address | | `for` | `command` | Keyword `for` | | `spender` | `address` | Spender address | ## Options | Name | Type | Description | |------|------|-------------| | `--deadline` | `number` | Permit expiry as a Unix timestamp (defaults to no expiry) | The command reads the token nonce and EIP-712 domain, asks the connected wallet for a typed-data signature, and encodes the resulting `permit(owner, spender, value, deadline, v, r, s)` call. The signature only covers the connected account as owner, so the encoded call can be submitted by anyone — including inside a batch executed by another account. Only standard EIP-2612 permits are supported; tokens with nonstandard permit signatures (e.g. DAI-style `allowed` permits) are rejected. ## Examples ```evml load token set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb set $spender 0x4F2083f5fBede34C2714aFfb3105539775f7FE64 # Approve via signature instead of an approve transaction token:permit 100e18 $token for $spender # Permit that expires in one day token:permit 100e18 $token for $spender --deadline @date(now +1d) ``` ## See Also - [token:approve](approve.md) — transaction-based approval - [sign](../../../std/src/commands/sign.md) — sign arbitrary messages or typed data --- --- title: "token:set-approval-for-all" --- Approve or revoke an operator for all ERC721 or ERC1155 tokens of the connected account. ## Syntax ```evml token:set-approval-for-all ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `token` | `address` | Token address | | `operator` | `address` | Operator address | | `approved` | `bool` | true to approve, false to revoke | ## Examples ```evml load token set $nft 0x22C1f6050E56d2876009903609a2cC3fEf83B415 set $operator 0x4F2083f5fBede34C2714aFfb3105539775f7FE64 token:set-approval-for-all $nft $operator true # Revoke the operator token:set-approval-for-all $nft $operator false ``` ## Notes - Applies to all current and future ERC721 / ERC1155 tokens the connected account holds in the contract. --- --- title: "token:transfer" --- Transfer ERC20 tokens from the connected account to a recipient. ## Syntax ```evml token:transfer ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `number` | Amount in token units (wei) | | `token` | `address` | Token address | | `to` | `command` | Keyword `to` | | `recipient` | `address` | Recipient | ## Examples ```evml load token set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb set $recipient 0x4F2083f5fBede34C2714aFfb3105539775f7FE64 token:transfer 100e18 $token to $recipient # Transfer using a human-readable amount token:transfer @token:amount(DAI 50) @token(DAI) to $recipient ``` ## See Also - [token:transfer-from](transfer-from.md) / [token:disperse](disperse.md) - [@token:balance](../helpers/balance.md) --- --- title: "token:transfer-from" --- Transfer ERC20 tokens from one account to another, consuming the sender allowance. ## Syntax ```evml token:transfer-from ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `number` | Amount in token units (wei) | | `token` | `address` | Token address | | `from` | `command` | Keyword `from` | | `owner` | `address` | Account to debit | | `to` | `command` | Keyword `to` | | `recipient` | `address` | Recipient | ## Examples ```evml load token set $token 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb set $from 0x4F2083f5fBede34C2714aFfb3105539775f7FE64 # Pull previously approved tokens into the connected account token:transfer-from 100e18 $token from $from to @me ``` ## See Also - [token:transfer](transfer.md) / [token:approve](approve.md) - [@token:allowance](../helpers/allowance.md) --- --- title: "@token:allowance" --- Fetch the allowance an owner has granted to a spender, in base units. **Returns**: `number` ## Syntax ```evml @token:allowance(tokenSymbol owner spender) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `tokenSymbol` | `token-symbol` | Token symbol (e.g. `DAI`) or address | | `owner` | `address` | Owner address | | `spender` | `address` | Spender address | ## Examples ```evml # Query an allowance set $allowance @token:allowance(DAI @me 0x4F2083f5fBede34C2714aFfb3105539775f7FE64) # Top up an allowance only when it is too low set $spender 0x4F2083f5fBede34C2714aFfb3105539775f7FE64 if @bool(@token:allowance(DAI @me $spender) < @token:amount(DAI 100)) ( token:approve @token:amount(DAI 100) @token(DAI) for $spender ) ``` ## See Also - [@token:balance](balance.md) — token balance of an address - [@token:amount](amount.md) — convert to base units - [token:approve](../commands/approve.md) — grant an allowance --- --- title: "@token:amount" --- Convert a human-readable token amount to its base unit (applying decimals). **Returns**: `number` ## Syntax ```evml @token:amount(tokenSymbolOrAddress amount) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `tokenSymbolOrAddress` | `token-symbol` | Token symbol (e.g. `DAI`) or address | | `amount` | `number` | Human-readable amount | ## Examples ```evml # Convert 100 DAI to base units set $amount @token:amount(DAI 100) ``` ## See Also - [@token](../../../std/src/helpers/token.md) — resolve a token symbol to its address - [@token:balance](balance.md) — query token balance - [@token:format](format.md) — format base units as a human-readable string - [@num.parse](../../../lang/src/helpers/num.parse.md) — generic decimal parsing --- --- title: "@token:balance" --- Fetch the token balance of an address in base units. **Returns**: `number` ## Syntax ```evml @token:balance(tokenSymbol holder) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `tokenSymbol` | `token-symbol` | Token symbol (e.g. `DAI`) or address | | `holder` | `address` | Address to query | ## Examples ```evml # Query a token balance set $bal @token:balance(DAI @token(DAI)) ``` ## See Also - [@token](../../../std/src/helpers/token.md) — resolve a token symbol to its address - [@token:amount](amount.md) — convert to base units - [@token:format](format.md) — format base units as a human-readable string - [@get](../../../std/src/helpers/get.md) — generic contract reads --- --- title: "@token:decimals" --- Return the number of decimals of a token. **Returns**: `number` ## Syntax ```evml @token:decimals(tokenSymbol) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `tokenSymbol` | `token-symbol` | Token symbol (e.g. `DAI`) or address | ## Examples ```evml # Read the decimals of a token set $decimals @token:decimals(DAI) # Scale an amount manually set $base @num(25 * 10 ^ @token:decimals(DAI)) ``` ## See Also - [@token:amount](amount.md) — convert to base units applying decimals - [@token:format](format.md) — format base units as a human-readable string --- --- title: "@token:format" --- Format a base-unit token amount as a human-readable string with the token symbol. **Returns**: `string` ## Syntax ```evml @token:format(tokenSymbolOrAddress amount) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `tokenSymbolOrAddress` | `token-symbol` | Token symbol (e.g. `DAI`) or address | | `amount` | `number` | Amount in base units | ## Examples ```evml # Format a base-unit amount as a human-readable string print @token:format(DAI 500000000000000000) # Print a holder's balance in human-readable form print @token:format(DAI @token:balance(DAI @token(DAI))) ``` ## See Also - [@token](../../../std/src/helpers/token.md) — resolve a token symbol to its address - [@token:balance](balance.md) — query token balance - [@token:amount](amount.md) — convert human-readable amount to base units --- --- title: "@token:symbol" --- Return the symbol of a token. **Returns**: `string` ## Syntax ```evml @token:symbol(tokenSymbol) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `tokenSymbol` | `token-symbol` | Token address (or symbol) | ## Examples ```evml # Read the symbol of a token by address set $symbol @token:symbol(0x44fA8E6f47987339850636F88629646662444217) # The native token symbol print @token:symbol(0x0000000000000000000000000000000000000000) ``` ## See Also - [@token](../../../std/src/helpers/token.md) — resolve a symbol to its address (the inverse lookup) - [@token:decimals](decimals.md) --- --- title: "@token:totalSupply" --- Fetch the total supply of a token in base units. **Returns**: `number` ## Syntax ```evml @token:totalSupply(tokenSymbol) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `tokenSymbol` | `token-symbol` | Token symbol (e.g. `DAI`) or address | ## Examples ```evml # Query the total supply of a token set $supply @token:totalSupply(DAI) # Print the total supply in human-readable form print @token:format(DAI @token:totalSupply(DAI)) ``` ## See Also - [@token:balance](balance.md) - [@token:format](format.md) --- # aragonos module Aragon DAO operations: connect to DAOs, manage permissions, install and upgrade apps. ```evml load aragonos ``` ## Configuration variables Config variables are set with `set` (fully qualified, including the module prefix) and are only readable by their own module and the user script. | Variable | Type | Default | Description | |----------|------|---------|-------------| | `$aragonos:ensResolver` | `address` | — | Custom aragonID ENS resolver used to resolve DAO names (forks / testing). | ## Commands | Command | Description | |---------|-------------| | [aragonos:act](src/commands/act.md) | Execute an action on a target contract through an agent or vault. | | [aragonos:connect](src/commands/connect.md) | Connect to an Aragon DAO and execute commands within its context. | | [aragonos:forward](src/commands/forward.md) | Route actions through a chain of forwarder apps with optional context. | | [aragonos:grant](src/commands/grant.md) | Grant a permission on a DAO app to an entity, with an optional oracle. | | [aragonos:install](src/commands/install.md) | Install an Aragon app into the connected DAO. | | [aragonos:new-dao](src/commands/new-dao.md) | Create a new Aragon DAO and register it with an ENS name. | | [aragonos:new-token](src/commands/new-token.md) | Create a new MiniMe token with configurable name, symbol, and decimals. | | [aragonos:revoke](src/commands/revoke.md) | Revoke a permission from an entity on a DAO app, optionally removing the manager. | | [aragonos:upgrade](src/commands/upgrade.md) | Upgrade an installed Aragon app to a new version. | ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@aragonos:app](src/helpers/app.md) | `address` | Resolve an app name to its proxy address within the connected DAO. | | [@aragonos:aragonEns](src/helpers/aragonEns.md) | `address` | Resolve an Aragon ENS name to its address. | | [@aragonos:nextApp](src/helpers/nextApp.md) | `address` | Predict the address of the next app to be installed in the DAO. | --- --- title: "aragonos:act" --- Execute an action on a target contract through an agent or vault. ## Syntax ```evml aragonos:act [...params] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `agent` | `address` | Agent or vault forwarder address | | `target` | `address` | Target contract address | | `signature` | `write-abi` | Function signature to call | | `[...params]` | `any` | Function arguments | ## Examples ```evml # Execute a contract call through the DAO agent aragonos:connect 0x1fc7e8d8e4bbbef77a4d035aec189373b52125a8 ( aragonos:act @aragonos:app(agent) @aragonos:app(agent 2) "deposit((uint256,int256),uint256[][])" [1 -2] [[2 3] [4 5]] ) ``` ## Notes - The agent must have the necessary permissions to execute the action - Parameters are ABI-encoded from the function signature, just like `exec` ## See Also - [exec](../../../std/src/commands/exec.md) — direct contract calls (without DAO agent) - [forward](forward.md) — route through forwarder apps --- --- title: "aragonos:connect" --- Connect to an Aragon DAO and execute commands within its context. ## Syntax ```evml aragonos:connect ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `daoName` | `dao` | DAO kernel address or Aragonid ENS name | | `block` | `block` | Commands to execute in DAO context | ## Examples ```evml # Connect to a DAO and grant a permission aragonos:connect 0x1fc7e8d8e4bbbef77a4d035aec189373b52125a8 ( aragonos:grant TRANSFER_ROLE on @aragonos:app(agent) to @me ) ``` ## Notes - Inside a `connect` block, aragonos commands must be qualified (`aragonos:grant`) or imported through the load import list (`load aragonos [connect grant @app]`) to be used unqualified - The `@aragonos:app()` helper resolves app names within the connected DAO context - `connect` blocks cannot be nested. For cross-DAO operations, use sequential top-level `connect` blocks and share values through variables: `set` bindings persist after the block ends ## See Also - [grant](grant.md) — manage permissions - [install](install.md) — install apps - [@app](../helpers/app.md) — resolve app addresses --- --- title: "aragonos:forward" --- Route actions through a chain of forwarder apps with optional context. ## Syntax ```evml aragonos:forward [...forwarders] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[...forwarders]` | `app` | Forwarding path through apps | | `block` | `block` | Commands to forward | ## Options | Name | Type | Description | |------|------|-------------| | `--context` | `string` | Context string attached to the forwarding | | `--check-forwarder` | `bool` | Verify forwarder can forward before submitting | ## Examples ```evml # Forward through voting to modify permissions aragonos:connect 0x1fc7e8d8e4bbbef77a4d035aec189373b52125a8 ( aragonos:forward @aragonos:app(disputable-voting.open) ( aragonos:grant PAUSE_CONTRACT_ROLE on @aragonos:app(disputable-conviction-voting.open) to @aragonos:app(disputable-voting.open) @aragonos:app(disputable-voting.open) ) --context "Modify permissions" ) ``` ## Notes - Multiple forwarders create a chain: the action is forwarded through each in order - `--context` attaches a human-readable description to the forwarded action - `--check-forwarder` validates that each app can actually forward ## See Also - [grant](grant.md) / [revoke](revoke.md) — permission management - [connect](connect.md) — establish DAO context --- --- title: "aragonos:grant" --- Grant a permission on a DAO app to an entity, with an optional oracle. ## Syntax ```evml aragonos:grant [permissionManager] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `role` | `permission` | Permission identifier | | `on` | `command` | Keyword `on` | | `app` | `app` | Target app | | `to` | `command` | Keyword `to` | | `grantee` | `address` | Address to grant the permission to | | `[permissionManager]` | `app` | Entity managing this permission | ## Options | Name | Type | Description | |------|------|-------------| | `--oracle` | `address` | ACL oracle contract address | ## Examples ```evml # Grant a role to the connected wallet aragonos:connect 0x1fc7e8d8e4bbbef77a4d035aec189373b52125a8 ( aragonos:grant TRANSFER_ROLE on @aragonos:app(agent) to @me ) ``` ## See Also - [revoke](revoke.md) — remove permissions - [connect](connect.md) — establish DAO context - [@app](../helpers/app.md) — resolve app addresses --- --- title: "aragonos:install" --- Install an Aragon app into the connected DAO. ## Syntax ```evml aragonos:install [...params] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `variable` | `variable` | Variable name | | `identifier` | `repo` | App APM repository name | | `[...params]` | `any` | App initialization arguments | ## Options | Name | Type | Description | |------|------|-------------| | `--version` | `string` | Specific app version to install | ## Examples ```evml # Install a token-manager app aragonos:connect 0x1fc7e8d8e4bbbef77a4d035aec189373b52125a8 ( aragonos:install $tm token-manager @aragonos:app(agent) false 1000e18 ) ``` ## See Also - [upgrade](upgrade.md) — upgrade an installed app - [connect](connect.md) — establish DAO context first --- --- title: "aragonos:new-dao" --- Create a new Aragon DAO and register it with an ENS name. ## Syntax ```evml aragonos:new-dao ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `variable` | `variable` | Variable name | | `daoName` | `string` | ENS name for the DAO | ## Examples ```evml # Create a new DAO aragonos:new-dao $dao "my-dao" ``` ## See Also - [connect](connect.md) — connect to a DAO - [install](install.md) — install apps in a DAO --- --- title: "aragonos:new-token" --- Create a new MiniMe token with configurable name, symbol, and decimals. ## Syntax ```evml aragonos:new-token [decimals] [transferable] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `variable` | `variable` | Variable name | | `name` | `string` | Token name | | `symbol` | `string` | Token symbol | | `controller` | `address` | Token controller address | | `[decimals]` | `number` | Decimal places | | `[transferable]` | `bool` | Whether the token is transferable | ## Examples ```evml # Create a standard MiniMe token aragonos:new-token $token "My Token" "TKN" @me ``` ## See Also - [new-dao](new-dao.md) — create a DAO - [install](install.md) — install apps --- --- title: "aragonos:revoke" --- Revoke a permission from an entity on a DAO app, optionally removing the manager. ## Syntax ```evml aragonos:revoke [removeManager] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `role` | `permission` | Permission to revoke | | `on` | `command` | Keyword `on` | | `app` | `app` | Target app | | `from` | `command` | Keyword `from` | | `grantee` | `address` | Address whose permission is revoked | | `[removeManager]` | `bool` | Also remove the permission manager | ## Examples ```evml # Revoke a permission aragonos:connect 0x1fc7e8d8e4bbbef77a4d035aec189373b52125a8 ( aragonos:revoke CREATE_PERMISSIONS_ROLE on @aragonos:app(acl) from @aragonos:app(disputable-voting.open) ) ``` ## See Also - [grant](grant.md) — grant permissions - [connect](connect.md) — connect to a DAO --- --- title: "aragonos:upgrade" --- Upgrade an installed Aragon app to a new version. ## Syntax ```evml aragonos:upgrade [newAppAddress] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `apmRepo` | `repo` | APM repository name for the app package | | `[newAppAddress]` | `address \| string` | Implementation address or semantic version (e.g. 1.2.0) | ## Examples ```evml # Upgrade to latest version aragonos:connect 0x8ccbeab14b5ac4a431fffc39f4bec4089020a155 ( aragonos:upgrade disputable-conviction-voting.open ) ``` ## See Also - [install](install.md) — install new apps - [connect](connect.md) — connect to a DAO --- --- title: "@aragonos:app" --- Resolve an app name to its proxy address within the connected DAO. **Returns**: `address` ## Syntax ```evml @aragonos:app(appName index?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `appName` | `string` | App name (e.g. `vault`, `voting.open`) | | `[index]` | `number` | Instance index when multiple apps share a name (0 = first) | ## Examples ```evml # Resolve app address within a DAO aragonos:connect 0x1fc7e8d8e4bbbef77a4d035aec189373b52125a8 ( set $agent @aragonos:app(agent) print $agent ) ``` ## See Also - [connect](../commands/connect.md) — connect to a DAO - [@nextApp](nextApp.md) — predict next app address --- --- title: "@aragonos:aragonEns" --- Resolve an Aragon ENS name to its address. **Returns**: `address` ## Syntax ```evml @aragonos:aragonEns(ensName extra?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `ensName` | `string` | ENS name to resolve to an address | | `[extra]` | `string` | Additional ENS path segment | ## Examples ```evml # Resolve an Aragon ENS name set $addr @aragonos:aragonEns("test.aragonid.eth") print $addr ``` ## See Also - [@app](app.md) — resolve app addresses within a DAO - [@ens](../../../std/src/helpers/ens.md) — resolve general ENS names --- --- title: "@aragonos:nextApp" --- Predict the address of the next app to be installed in the DAO. **Returns**: `address` ## Syntax ```evml @aragonos:nextApp(offset?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[offset]` | `number` | Nonce offset from next install | ## Examples ```evml # Predict the next app address aragonos:connect 0x1fc7e8d8e4bbbef77a4d035aec189373b52125a8 ( set $next @aragonos:nextApp print $next ) ``` ## See Also - [install](../commands/install.md) — install apps in a DAO - [@app](app.md) — resolve existing app addresses --- # assertions module On-chain assertions backed by the assertions.eth contract: verify view return values and chain state atomically. Requires `load assertions`. ```evml load assertions ``` ## Configuration variables Config variables are set with `set` (fully qualified, including the module prefix) and are only readable by their own module and the user script. | Variable | Type | Default | Description | |----------|------|---------|-------------| | `$assertions:address` | `address` | — | Override the resolved assertions contract address (forks / testing). | ## Commands | Command | Description | |---------|-------------| | [assertions:assert](src/commands/assert.md) | Assert that a contract view return satisfies a comparison, on-chain. | | [assertions:assert-balance](src/commands/assert-balance.md) | Assert the native balance of an account, on-chain. | | [assertions:assert-block-number](src/commands/assert-block-number.md) | Assert the current block number, on-chain. | | [assertions:assert-chainid](src/commands/assert-chainid.md) | Assert the chain ID equals an expected value, on-chain. | | [assertions:assert-code](src/commands/assert-code.md) | Assert an address has deployed code, on-chain. | | [assertions:assert-codehash](src/commands/assert-codehash.md) | Assert an address has a specific code hash, on-chain. | | [assertions:assert-no-code](src/commands/assert-no-code.md) | Assert an address has no deployed code, on-chain. | | [assertions:assert-timestamp](src/commands/assert-timestamp.md) | Assert the current block timestamp, on-chain. | ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@assertions:codehash](src/helpers/codehash.md) | `bytes32` | Read the code hash of an address at script build time, with EXTCODEHASH semantics: `bytes32(0)` for a nonexistent account (zero nonce, balance and code), `keccak256` of the code otherwise. | --- --- title: "assertions:assert" --- Assert that a contract view return satisfies a comparison, on-chain. ## Syntax ```evml assertions:assert [operator] [expected] [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `call` | `expression` | A `::` call expression, e.g. `@token(WETH)::balanceOf(@me)` | | `[operator]` | `string` | Comparison operator: ==, !=, >, <, >=, <=, ~= | | `[expected]` | `any` | Expected value the return is compared against | | `[message]` | `string` | Revert message when the assertion fails | ## Options | Name | Type | Description | |------|------|-------------| | `--delta` | `number` | Allowed delta for the ~= (approximate) operator | ## Examples ```evml load assertions load token # Compare a view return against a value (named method; ABI fetched automatically) assertions:assert @token(WETH)::balanceOf(@me) >= @token:amount(WETH 10) "insufficient bal" # Inline ABI when the return type must be explicit (no ABI lookup) assertions:assert @token(WETH)::{balanceOf(address)(uint256) @me} >= @token:amount(WETH 10) "insufficient bal" # Select a tuple element with a destructure lens ($ marks the element) set $pool 0x44fA8E6f47987339850636F88629646662444217 assertions:assert $pool::{getReserves()(uint112,uint112,uint32)}[_ $ _] >= 1000 "low reserve" # Approximate comparison with an allowed delta set $oracle 0x0102030405060708090a0b0c0d0e0f1011121314 assertions:assert $oracle::{price()(uint256)} ~= 2000e8 --delta 50e8 "price out of range" # Bare boolean assertion (asserts the return is true) set $gov 0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1 assertions:assert $gov::{paused()(bool)} ``` ## Notes - The first argument must be a `::` call expression so the (contract, calldata, return type) can be captured without being evaluated off-chain. - Inside a `batch`, a failed assertion reverts the whole transaction. Run standalone, the assertion is evaluated as a read-only `eth_call`. - Operators map to the contract functions by return type: `uint` supports `== != > < >= <= ~=`; `address`/`bool`/`bytes32` support `== !=`. - Set `$assertions:address` to override the resolved contract (forks / testing). ## See Also --- --- title: "assertions:assert-balance" --- Assert the native balance of an account, on-chain. ## Syntax ```evml assertions:assert-balance [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `account` | `address` | Account to check | | `operator` | `string` | Comparison operator: ==, >, <, >=, <=, ~= | | `expected` | `number` | Expected balance in wei | | `[message]` | `string` | Revert message when the assertion fails | ## Options | Name | Type | Description | |------|------|-------------| | `--delta` | `number` | Allowed delta for the ~= (approximate) operator | ## Examples ```evml load assertions # Require an account to hold more than 1 ETH assertions:assert-balance @me > 1e18 "needs ETH" # Approximate balance within a delta assertions:assert-balance @me ~= 5e18 --delta 1e17 "balance drifted" ``` ## See Also --- --- title: "assertions:assert-block-number" --- Assert the current block number, on-chain. ## Syntax ```evml assertions:assert-block-number [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `operator` | `string` | Comparison operator: ==, >, <, >=, <= | | `expected` | `number` | Expected block number | | `[message]` | `string` | Revert message when the assertion fails | ## Examples ```evml load assertions assertions:assert-block-number >= 21000000 "too early" ``` ## See Also --- --- title: "assertions:assert-chainid" --- Assert the chain ID equals an expected value, on-chain. ## Syntax ```evml assertions:assert-chainid [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `expected` | `number` | Expected chain ID | | `[message]` | `string` | Revert message when the assertion fails | ## Examples ```evml load assertions # Ensure the transaction only executes on Ethereum mainnet assertions:assert-chainid 1 "wrong chain" ``` ## See Also --- --- title: "assertions:assert-code" --- Assert an address has deployed code, on-chain. ## Syntax ```evml assertions:assert-code [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `target` | `address` | Address to check | | `[message]` | `string` | Revert message when the assertion fails | ## Examples ```evml load assertions assertions:assert-code 0x6B175474E89094C44Da98b954EedeAC495271d0F "not deployed" ``` ## See Also --- --- title: "assertions:assert-codehash" --- Assert an address has a specific code hash, on-chain. ## Syntax ```evml assertions:assert-codehash [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `target` | `address` | Address to check | | `expected` | `bytes32` | Expected code hash (keccak256 of the runtime bytecode) | | `[message]` | `string` | Revert message when the assertion fails | ## Examples ```evml load assertions [@codehash] # Pin an implementation by its runtime code hash assertions:assert-codehash 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb @codehash(0xf8D1677c8a0c961938bf2f9aDc3F3CFDA759A9d9) "implementation changed" ``` ## See Also --- --- title: "assertions:assert-no-code" --- Assert an address has no deployed code, on-chain. ## Syntax ```evml assertions:assert-no-code [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `target` | `address` | Address to check | | `[message]` | `string` | Revert message when the assertion fails | ## Examples ```evml load assertions assertions:assert-no-code @me "expected an EOA" ``` ## See Also --- --- title: "assertions:assert-timestamp" --- Assert the current block timestamp, on-chain. ## Syntax ```evml assertions:assert-timestamp [message] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `operator` | `string` | Comparison operator: ==, >, <, >=, <= | | `expected` | `number` | Expected block timestamp (unix seconds) | | `[message]` | `string` | Revert message when the assertion fails | ## Examples ```evml load assertions assertions:assert-timestamp >= 1893456000 "unlock period not reached" ``` ## See Also --- --- title: "@assertions:codehash" --- Read the code hash of an address at script build time, with EXTCODEHASH semantics: `bytes32(0)` for a nonexistent account (zero nonce, balance and code), `keccak256` of the code otherwise. **Returns**: `bytes32` ## Syntax ```evml @assertions:codehash(address) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Address to read | ## Examples ```evml load assertions [@codehash] assertions:assert-codehash 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb @codehash(0xf8D1677c8a0c961938bf2f9aDc3F3CFDA759A9d9) "implementation changed" ``` ## See Also --- # contracts module Contract lifecycle commands and helpers for EVML scripts: deploy creation bytecode (CREATE, CREATE2, CREATE3, or mirroring an existing deployment), verify source code on Etherscan V2, inspect deployed code and storage, and compile Solidity from inline source or a URL with the @solidity helpers. ```evml load contracts ``` ## Commands | Command | Description | |---------|-------------| | [contracts:deploy](src/commands/deploy.md) | Deploy a contract from raw creation bytecode. Binds the predicted address to . Mirror an existing deployment with --mirror-chain / --mirror-address (fetches the original creation bytecode from Etherscan). | | [contracts:verify](src/commands/verify.md) | Submit Solidity Standard JSON Input source code to Etherscan V2 for verification at
. Mirror an existing verification with --mirror-chain / --mirror-address, or supply source explicitly with --source. Inside sim:fork this becomes a local dry-run: the source is compiled and checked against the fork's deployed bytecode instead of being sent to Etherscan. | ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@contracts:codeAt](src/helpers/codeAt.md) | `bytes` | Return the deployed bytecode at an address. | | [@contracts:next](src/helpers/next.md) | `address` | Predict the next contract address deployed by a given account. | | [@contracts:slot.array](src/helpers/slot.array.md) | `bytes32` | Derive the storage slot of element index of a dynamic array declared at a base slot: keccak256(base) + index. | | [@contracts:slot.erc7201](src/helpers/slot.erc7201.md) | `bytes32` | Derive the root slot of an ERC-7201 namespaced storage layout: keccak256(abi.encode(uint256(keccak256(id)) - 1)) & ~0xff. | | [@contracts:slot.mapping](src/helpers/slot.mapping.md) | `bytes32` | Derive the storage slot of mapping[key] for a mapping declared at a base slot: keccak256(h(key) . base). | | [@contracts:storageAt](src/helpers/storageAt.md) | `bytes32` | Read a raw storage slot of a contract. | --- --- title: "contracts:deploy" --- Deploy a contract from raw creation bytecode. Binds the predicted address to . Mirror an existing deployment with --mirror-chain / --mirror-address (fetches the original creation bytecode from Etherscan). ## Syntax ```evml contracts:deploy [bytecode] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `variable` | `variable` | Variable to bind the deployed contract address to | | `[bytecode]` | `bytes` | Creation bytecode. Constructor args are appended automatically when --constructor is set. Omit when using --mirror-chain / --mirror-address to mirror an existing deployment. | ## Options | Name | Type | Description | |------|------|-------------| | `--mirror-chain` | `chain` | Chain (id or viem name like `optimism`) to fetch the creation bytecode from (Etherscan V2). Defaults to the current chain when only --mirror-address is set. Requires --mirror-address. | | `--mirror-address` | `address` | Address of an existing deployment to mirror. The original creation bytecode (with constructor args already appended) is fetched from Etherscan and used as the init code for this deployment. | | `--constructor` | `string` | Constructor signature like `constructor(uint256,address)`. Requires --constructor-args. Mutually exclusive with --mirror-address. | | `--constructor-args` | `array` | Constructor arguments as an array literal, e.g. [100e18 @me true]. Requires --constructor. | | `--create2` | `bytes32` | Salt for CREATE2 deployment. Defaults to the Arachnid deterministic deployer; override factory with --via. | | `--create3` | `bytes32` | Salt for CREATE3 deployment. Defaults to the CreateX factory; override with --via. | | `--via` | `address` | Override the default factory address used by --create2 / --create3. | | `--from` | `address` | Sender address. Defaults to the connected wallet. For plain CREATE this is also the prediction deployer. | | `--value` | `number` | ETH to send with the deployment (in wei) | | `--gas` | `number` | Gas limit | | `--max-fee-per-gas` | `number` | Max fee per gas (EIP-1559) | | `--max-priority-fee-per-gas` | `number` | Max priority fee per gas (EIP-1559) | | `--nonce` | `number` | Transaction nonce override. For plain CREATE deployments it also pins the predicted contract address. | ## Examples ```evml load contracts # Plain CREATE deployment from raw bytecode contracts:deploy $addr 0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe # Deploy with constructor arguments contracts:deploy $token 0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe --constructor "constructor(string,string,uint8)" --constructor-args ["My Token" "MTK" 18] # CREATE2 via the Arachnid deterministic deployer (default) contracts:deploy $vault 0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe --create2 0x0000000000000000000000000000000000000000000000000000000000000001 # CREATE2 via a custom factory (must accept salt || initCode calldata) contracts:deploy $vault2 0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe --create2 0x0000000000000000000000000000000000000000000000000000000000000001 --via 0x4e59b44847b379578588920ca78fbf26c0b4956c # CREATE3 via the CreateX factory (default) contracts:deploy $proxy 0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe --create3 0x0000000000000000000000000000000000000000000000000000000000000002 --constructor "constructor(address)" --constructor-args [@me] # Mirror an existing deployment from another chain — fetches the # original creation bytecode (with constructor args already baked in) # from Etherscan and replays it byte-for-byte on the current chain. contracts:deploy $clone --mirror-chain 1 --mirror-address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 # Same flow, deterministically pinned to a CREATE2 address so the # clone lands at the same address on every chain that runs this script. contracts:deploy $clone2 --mirror-chain 1 --mirror-address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 --create2 0x0000000000000000000000000000000000000000000000000000000000000003 # Use the bound address in subsequent calls exec $token "transfer(address,uint256)" @me 1e18 ``` ## Modes - **CREATE** (default): the EVM derives the address from `(--from, nonce)`. The command uses an internal per-script nonce counter so multiple deploys in the same script chain correctly. - **CREATE2** (`--create2 `): tx is sent to a CREATE2 factory with calldata `salt(32) || initCode`. The default factory is the Arachnid deterministic deployer at `0x4e59b44847b379578588920ca78fbf26c0b4956c`. The predicted address depends on `(factory, salt, initCode)` only, so changing `--from` does not affect it. - **CREATE3** (`--create3 `): tx calls `deployCreate3(bytes32,bytes)` on a CreateX-compatible factory (default `0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed`). The deployed address depends only on `(factory, salt)`, not on the bytecode. Permissioned salts (first 20 bytes equal `--from`, or zero-prefixed with `0x01` in byte 20) are rejected so client-side prediction stays deterministic. - **Mirror** (`--mirror-address [--mirror-chain ]`): fetches the original creation bytecode of an existing deployment from Etherscan V2's `getcontractcreation` endpoint and uses it as the init code for this deployment. The fetched bytecode already includes the original ABI-encoded constructor arguments, so `--constructor` / `--constructor-args` are not allowed in this mode. Combine with `--create2` / `--create3` to pin the cloned contract to a deterministic address. Requires `VITE_ETHERSCAN_API_KEY`. ## Caveats - A command and all of its options must be written on a single line — EVML has no `\` line continuation. - A `deploy` action is a CREATE transaction (no `to` field) when neither `--create2` nor `--create3` is set. Such actions cannot be executed inside a `batch (...)` block via EIP-5792 wallet batching — use `--create2` or `--create3` if you need to batch deployments together with other calls. ## See Also - [@contracts:next](../helpers/next.md) — predict the next CREATE address for an account - [exec](../../../std/src/commands/exec.md) — call a contract function on the deployed address - [send](../../../std/src/commands/send.md) — send a pre-encoded transaction or value transfer to an existing address --- --- title: "contracts:verify" --- Submit Solidity Standard JSON Input source code to Etherscan V2 for verification at
. Mirror an existing verification with --mirror-chain / --mirror-address, or supply source explicitly with --source. Inside sim:fork this becomes a local dry-run: the source is compiled and checked against the fork's deployed bytecode instead of being sent to Etherscan. ## Syntax ```evml contracts:verify
``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Deployed contract address on the current chain to verify. | ## Options | Name | Type | Description | |------|------|-------------| | `--mirror-chain` | `chain` | Chain (id or viem name like `optimism`) to mirror an existing verification from. Defaults to the current chain when only --mirror-address is set. | | `--mirror-address` | `address` | Existing verified contract to mirror. Defaults to
when only --mirror-chain is set. | | `--source` | `string` | Solidity Standard JSON Input text including language, sources, and settings. Required for explicit (non-mirror) mode. | | `--contract-name` | `string` | Qualified contract name `path/File.sol:ContractName`. Required for explicit mode. | | `--compiler` | `string` | Solidity compiler version, e.g. `0.8.20+commit.a1b79de6`. Required for explicit mode. | | `--license` | `string` | SPDX license identifier (e.g. MIT, Apache-2.0). Defaults to `None` in explicit mode; mirrored in mirror mode. | | `--constructor` | `string` | Constructor signature like `constructor(uint256,address)`. Requires --constructor-args. | | `--constructor-args` | `array` | Constructor arguments as an array literal, e.g. [100e18 @me]. Requires --constructor. | | `--constructor-args-hex` | `bytes` | Pre-encoded ABI constructor arguments as hex. Mutually exclusive with --constructor / --constructor-args. | | `--timeout` | `number` | Maximum time to wait for verification to complete, in time units (default 60s). | | `--poll-interval` | `number` | Time between status polls, in time units (default 3s). | ## Simulation dry-run Inside `sim:fork`, `verify` never talks to Etherscan. It performs a local dry-run instead: the Standard JSON Input is compiled with the pinned compiler and diffed against the bytecode deployed on the fork (metadata hashes and immutable values are ignored, exactly like a verifier would). A match logs `would verify on Etherscan`; a mismatch aborts the simulation naming the reason (wrong optimizer runs and a missing `via-ir` are the usual suspects). No `VITE_ETHERSCAN_API_KEY` is needed for the dry-run — mirror mode still needs one, since it reads the source from Etherscan. ```evml load sim load contracts sim:fork ( set $src <<`. The other selector defaults so all three combinations are reachable: - same address, different chain → only `--mirror-chain` - different address, same chain → only `--mirror-address` - different address, different chain → both Settings (optimizer, evmVersion, libraries) and the original constructor arguments are preserved by default; supply `--constructor` / `--constructor-args` to override per-deployment differences (e.g. immutable `owner` set to `@me` on the new chain). - **Explicit mode** is the default when no mirror selector is set. It accepts a Solidity Standard JSON Input via `--source` plus the qualified `--contract-name` and `--compiler`. The JSON itself encodes optimizer, evmVersion, and libraries — there are intentionally no separate `--evm-version` or `--optimizer-runs` opts. ## Source format `verify` only supports **Solidity Standard JSON Input** for explicit-mode submissions. The JSON encodes everything Etherscan needs to compile: ```json { "language": "Solidity", "sources": { "src/Foo.sol": { "content": "// SPDX ..." } }, "settings": { "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris" } } ``` This is exactly what foundry and hardhat emit out of the box (foundry: `metadata.solcInput` in `out/.sol/.json`; hardhat: `input` in `artifacts/build-info/*.json`). For mirror mode the source is fetched from the source chain — no source format choice is exposed because the command always submits `solidity-standard-json-input` after normalising whatever shape Etherscan returns. ### Delivering `--source` DSL string literals come in two flavors and **neither supports escapes**: `"..."` cannot contain `"`, and `'...'` cannot contain `'`. The two practical patterns: 1. Fetch via `@fetch` from the `http` module — recommended for any non-trivial input: ```evml load contracts load http [@fetch] set $src @fetch("https://gist.githubusercontent.com/me/abc/raw/input.json") contracts:verify 0x44fA8E6f47987339850636F88629646662444217 --source $src --contract-name "src/Foo.sol:Foo" --compiler "0.8.20+commit.a1b79de6" ``` 2. Inline single-quoted multi-line literal — fine for tiny payloads, provided no `'` appears anywhere inside the JSON: ```evml load contracts contracts:verify 0x44fA8E6f47987339850636F88629646662444217 --source '{ "language": "Solidity", "sources": { "Foo.sol": { "content": "// SPDX ..." } }, "settings": { "optimizer": { "enabled": true, "runs": 200 } } }' --contract-name "Foo.sol:Foo" --compiler "0.8.20+commit.a1b79de6" ``` ## Caveats - A command and all of its options must be written on a single line — EVML has no `\` line continuation. (Quoted strings may span lines, as in the inline `--source` example above.) - Requires the `VITE_ETHERSCAN_API_KEY` environment variable. The same key is used by hover-card lookups; Etherscan V2's free tier covers 60+ chains under one key. - The `deploy` transaction must be **mined** before `verify` runs — Etherscan reads the deployed runtime bytecode at `
`. In practice this means `verify` should not appear inside a `batch (...)` block alongside the deploy; run it as a follow-up command after the deploy confirms. - Verification is opaque to the deployment method. CREATE, Arachnid CREATE2, and CreateX CREATE3 deployments all verify identically because Etherscan compares deployed runtime bytecode rather than replaying the deployment transaction. - For deterministic cross-chain re-deploys (CREATE2 / CREATE3), compile identically on every chain (same Standard JSON, same compiler version). Any divergence in metadata-affecting settings changes the metadata hash embedded in the deployed bytecode — and therefore the contract address. - The poll loop waits up to `--timeout` seconds (default 60) and polls every `--poll-interval` seconds (default 3). Increase `--timeout` for large standard JSONs that take Etherscan longer to compile. ## See Also - [deploy](deploy.md) — deploy a contract whose address you can then pass to `verify` - [@fetch](../../../http/src/helpers/fetch.md) — fetch a Standard JSON Input from a URL for `--source` --- --- title: "@contracts:codeAt" --- Return the deployed bytecode at an address. **Returns**: `bytes` ## Syntax ```evml @contracts:codeAt(address) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Contract or account address | ## See Also - [@contracts:storageAt](storageAt.md) — read a storage slot - [sim:set-code](../../../sim/src/commands/set-code.md) — override bytecode in simulation --- --- title: "@contracts:next" --- Predict the next contract address deployed by a given account. **Returns**: `address` ## Syntax ```evml @contracts:next(creator offset?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `creator` | `address` | Deployer address | | `[offset]` | `number` | Nonce offset from current | ## See Also - [@contracts:codeAt](codeAt.md) — read deployed bytecode --- --- title: "@contracts:slot.array" --- Derive the storage slot of element index of a dynamic array declared at a base slot: keccak256(base) + index. **Returns**: `bytes32` ## Syntax ```evml @contracts:slot.array(base index) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `base` | `bytes32` | Declared slot of the array | | `index` | `number` | Element index | ## Examples ```evml # Slot of the first element of a dynamic array at slot 2 set $slot @contracts:slot.array(2 0) ``` ## See Also --- --- title: "@contracts:slot.erc7201" --- Derive the root slot of an ERC-7201 namespaced storage layout: keccak256(abi.encode(uint256(keccak256(id)) - 1)) & ~0xff. **Returns**: `bytes32` ## Syntax ```evml @contracts:slot.erc7201(id) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `id` | `string` | Namespace id, e.g. "openzeppelin.storage.Ownable" | ## Examples ```evml # Root slot of an ERC-7201 namespaced layout set $slot @contracts:slot.erc7201("openzeppelin.storage.Ownable") ``` ## See Also --- --- title: "@contracts:slot.mapping" --- Derive the storage slot of mapping[key] for a mapping declared at a base slot: keccak256(h(key) . base). **Returns**: `bytes32` ## Syntax ```evml @contracts:slot.mapping(base key) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `base` | `bytes32` | Declared slot of the mapping | | `key` | `any` | Mapping key | ## Examples ```evml # Slot of balanceOf[account] for a mapping at slot 3 set $slot @contracts:slot.mapping(3 0x64c007ba4ab6184753dc1e8e7263e8d06831c5f6) ``` ## See Also --- --- title: "@contracts:storageAt" --- Read a raw storage slot of a contract. **Returns**: `bytes32` ## Syntax ```evml @contracts:storageAt(address slot) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `address` | `address` | Contract or account address | | `slot` | `bytes32` | Storage slot index | ## See Also - [@contracts:codeAt](codeAt.md) — read bytecode - [sim:set-storage-at](../../../sim/src/commands/set-storage-at.md) — override a slot in simulation --- # giveth module Giveth protocol operations: donations, GIVpower staking, and GIVstream claims. ```evml load giveth ``` ## Commands | Command | Description | |---------|-------------| | [giveth:boost](src/commands/boost.md) | Allocate your GIVpower across Giveth projects by percentage. With --with (or no option) it replaces your entire existing allocation; with --by it changes the listed projects by percentage points and the rest of your allocation absorbs the difference proportionally. Off-chain: signs you in to Giveth with the connected wallet (SIWE) and updates the allocation through the Giveth API; no transaction is sent, so it cannot be batched, and inside sim:fork the update is only logged, never sent. | | [giveth:claim](src/commands/claim.md) | Harvest GIV rewards: collect the accrued GIVpower staking rewards (when the chain has a staking contract) and claim the GIV the GIVstream has already released. Does nothing when there is nothing to claim. | | [giveth:donate](src/commands/donate.md) | Donate to Giveth projects and record the donation in Giveth's database (project totals, GIVbacks). A single project gets a direct wallet transfer; several projects ([amounts] to [slugs]) donate through the DonationHandler contract in one transaction. Signs you in to Giveth (SIWE) and sends the transactions immediately to report their hashes, so it cannot be batched. The zero address (@token(ETH), @token(XDAI)...) donates the chain's native token. | | [giveth:lock](src/commands/lock.md) | Lock staked GIV for a number of GIVpower rounds (2 weeks each) to multiply its GIVpower. Pass `max` as the amount to lock all staked GIV that is not already locked; a zero amount does nothing. Locked GIV cannot be unstaked until the last round ends and it is unlocked. | | [giveth:stake](src/commands/stake.md) | Stake GIV for GIVpower, approving the staking contract automatically when needed. Pass `max` as the amount to stake the full GIV balance; a zero amount does nothing. On Gnosis GIV is wrapped into gGIV through the GIVgarden (which auto-stakes it); on Optimism and Polygon zkEVM it is staked directly. Staked GIV earns GIVstream rewards and can be locked for more GIVpower. | | [giveth:unlock](src/commands/unlock.md) | Unlock GIV locks that ended at the given GIVpower round, making the tokens unstakeable again. Anyone can unlock for any account once the round is over; the round must be earlier than the current one (see @giveth:round). | | [giveth:unstake](src/commands/unstake.md) | Unstake GIV from GIVpower: unwrap gGIV on Gnosis, withdraw from the staking contract on Optimism and Polygon zkEVM. Pass `max` as the amount to unstake everything the contract allows right now — staked GIV minus locks, where locks whose round already ended still count until giveth:unlock frees them (see @giveth:unlockable). A zero amount does nothing. | ## Helpers | Helper | Returns | Description | |--------|---------|-------------| | [@giveth:boostedBy](src/helpers/boostedBy.md) | `array` | Projects an account boosts with its GIVpower, as a pair of same-length arrays [slugs percentages] sorted by percentage descending. Empty arrays when the account has no boosts. | | [@giveth:claimable](src/helpers/claimable.md) | `number` | GIV an account can claim from the GIVstream right now (see giveth:claim). Counts a pending giveth:claim earlier in the script as already claimed. | | [@giveth:givpower](src/helpers/givpower.md) | `number` | GIVpower balance of an account: staked GIV plus the extra power gained from locking. | | [@giveth:lockable](src/helpers/lockable.md) | `number` | Staked GIV an account can lock (or unstake) right now: staked GIV minus everything the GIVpower contract counts as locked, including ended locks that were never unlocked (see @giveth:unlockable). Counts pending stake/lock actions earlier in the script — what `lock max` resolves to. | | [@giveth:project](src/helpers/project.md) | `address` | Resolve a Giveth project slug to its donation recipient address on the current chain. | | [@giveth:round](src/helpers/round.md) | `number` | The current GIVpower round number (rounds last 2 weeks; locks unlock when their round is over). | | [@giveth:stakable](src/helpers/stakable.md) | `number` | GIV in an account's wallet that giveth:stake can stake for GIVpower. Counts pending claim/stake/unstake actions earlier in the script — what `stake max` resolves to. | | [@giveth:staked](src/helpers/staked.md) | `number` | Raw GIV an account has staked for GIVpower: the gGIV balance on Gnosis, the deposit balance on Optimism and Polygon zkEVM. Includes locked GIV (see @giveth:unstakable) and counts pending giveth:stake/giveth:unstake actions earlier in the script. | | [@giveth:unlockable](src/helpers/unlockable.md) | `number` | GIV in locks whose GIVpower round has ended but that giveth:unlock hasn't freed yet. Until unlocked, the GIVpower contract still counts it as locked, so it can be neither locked again nor unstaked. Time-aware inside sim:fork: after a wait, newly ended locks show up here. | | [@giveth:unstakable](src/helpers/unstakable.md) | `number` | GIV an account can unstake at the current chain time: staked GIV minus the locks whose GIVpower round hasn't finished yet. Locks whose round has ended count as unstakable — unlocking is permissionless — but still need a giveth:unlock before giveth:unstake accepts them. Time-aware inside sim:fork: after a wait, ended locks drop out of the locked amount. Counts pending stake/unstake/lock actions earlier in the script. | --- --- title: "giveth:boost" --- Allocate your GIVpower across Giveth projects by percentage. With --with (or no option) it replaces your entire existing allocation; with --by it changes the listed projects by percentage points and the rest of your allocation absorbs the difference proportionally. Off-chain: signs you in to Giveth with the connected wallet (SIWE) and updates the allocation through the Giveth API; no transaction is sent, so it cannot be batched, and inside sim:fork the update is only logged, never sent. ## Syntax ```evml giveth:boost ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `projects` | `array \| giveth-project` | Giveth project URL slugs | ## Options | Name | Type | Description | |------|------|-------------| | `--with` | `array` | GIVpower percentage per project, matching and summing to 100; replaces your entire allocation. Defaults to an equal split | | `--by` | `array` | Percentage-point change per project (e.g. [20 -20]), matching ; the net change is absorbed proportionally by your other boosted projects | ## Examples ```evml # Boost two projects 70/30 giveth:boost [evmcrispr wayback-machine] --with [70 30] # Split your GIVpower evenly across three projects giveth:boost [evmcrispr wayback-machine the-giveth-community-of-makers] # Move 20 percentage points from wayback-machine to evmcrispr, # leaving the rest of your allocation untouched giveth:boost [evmcrispr wayback-machine] --by [20 -20] # Give a project 10 more percentage points; every other boosted # project shrinks proportionally to make room giveth:boost [evmcrispr] --by [10] ``` ## How it works Boosting is not an on-chain operation: Giveth stores boost allocations in its backend and recomputes project ranks from them every GIVbacks round. The command signs you in to Giveth with a Sign-In-With-Ethereum message (one wallet signature per run) and calls the `setMultiplePowerBoosting` API with the resolved project ids. With `--with` (or no option) the call **replaces your whole allocation**: any project you previously boosted but leave out of `` drops to 0%, and the percentages must sum to 100. Read the current allocation first with [@giveth:boostedBy](../helpers/boostedBy.md). With `--by` the listed projects are **shifted by percentage points** relative to your current allocation. If the changes sum to 0 every other boosted project keeps its share; otherwise the rest of your allocation shrinks (net increase) or grows (net decrease) proportionally to absorb the difference. A project not boosted yet starts from 0%, a project reduced to exactly 0% is dropped, reducing a project below 0% fails, and a net increase larger than what the other projects hold fails. Giveth accepts at most 20 boosted projects, percentages use 2 decimals, and the account needs staked GIV for the boost to carry weight (see [giveth:stake](stake.md)). ## See Also - [@giveth:boostedBy](../helpers/boostedBy.md) - [@giveth:givpower](../helpers/givpower.md) - [giveth:stake](stake.md) - [giveth:lock](lock.md) --- --- title: "giveth:claim" --- Harvest GIV rewards: collect the accrued GIVpower staking rewards (when the chain has a staking contract) and claim the GIV the GIVstream has already released. Does nothing when there is nothing to claim. ## Syntax ```evml giveth:claim ``` ## Examples ```evml load giveth giveth:claim ``` The command reads your position first and emits at most one transaction — and none when there is nothing to claim, so no `if` guard is needed. When staking rewards have accrued it emits a single `getReward()`: harvesting assigns the rewards to your GIVstream, and the GIVstream immediately pays out everything it has released so far (the rest keeps streaming until December 2026), so a separate `TokenDistro.claim()` would find nothing left and revert. Only when no staking rewards are pending does the command claim the released GIVstream balance directly. ## See Also - [@giveth:claimable](../helpers/claimable.md) - [giveth:stake](stake.md) --- --- title: "giveth:donate" --- Donate to Giveth projects and record the donation in Giveth's database (project totals, GIVbacks). A single project gets a direct wallet transfer; several projects ([amounts] to [slugs]) donate through the DonationHandler contract in one transaction. Signs you in to Giveth (SIWE) and sends the transactions immediately to report their hashes, so it cannot be batched. The zero address (@token(ETH), @token(XDAI)...) donates the chain's native token. ## Syntax ```evml giveth:donate ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `array \| number` | Donation amount in token base units, or one amount per project (a single amount with several projects donates that amount to each) | | `token` | `address` | Token to donate (use @token(SYM); the native token resolves to the zero address) | | `to` | `command` | Keyword `to` | | `projects` | `array \| giveth-project` | Giveth project URL slug, or several slugs | ## Options | Name | Type | Description | |------|------|-------------| | `--tip` | `number` | Extra donation to Giveth itself as a percentage of the total amount (0-100), added on top | | `--anonymous` | `bool` | Hide your identity on the recorded donation | | `--no-approve` | `bool` | Skip the automatic allowance check and approve action | ## Examples ```evml # Donate 100 GIV to one project (direct wallet transfer) set $std:tokenlist https://tokens.honeyswap.org giveth:donate 100e18 @token(GIV) to evmcrispr # Donate native xDAI with a 5% tip to Giveth on top giveth:donate 10e18 @token(XDAI) to evmcrispr --tip 5 # Donate to several projects in one DonationHandler transaction set $std:tokenlist https://tokens.honeyswap.org giveth:donate [100e18 50e18] @token(GIV) to [evmcrispr wayback-machine] # Same amount to each project giveth:donate 10e18 @token(XDAI) to [evmcrispr wayback-machine] ``` ## How it works Both shapes mirror Giveth's own frontends: giveth.io sends direct transfers, qf.giveth.io batches through the DonationHandler contract — and in both cases the frontend must report the donation to Giveth's API afterwards, because nothing indexes the chain on its own. A donation that skips the API call never shows up in project totals, GIVbacks or QF matching. That report needs the transaction hash and an authenticated user, so the command signs you in with a Sign-In-With-Ethereum message (one wallet signature per run), executes the transactions immediately, waits for confirmation, and calls `createDonation` for every project with the resulting hash. This is why `donate` cannot go inside `batch` or a Safe. Inside `sim:fork` the transactions simulate on the fork and the sign-in and database recording are skipped, so simulated donations are never reported to Giveth. The project must have a recipient address on the current chain (see [@giveth:project](../helpers/project.md)); the DonationHandler is deployed on Mainnet, Gnosis, Polygon, Optimism, Arbitrum, Base and Celo, while direct donations work on any chain the project has an address for. For recurring donations, use [giveth:donate-recurring](donate-recurring.md), which streams to the project's anchor contract and records the stream in Giveth's database. ## See Also - [@giveth:project](../helpers/project.md) - [@giveth:anchor](../helpers/anchor.md) - [giveth:donate-recurring](donate-recurring.md) - [giveth:boost](boost.md) --- --- title: "giveth:lock" --- Lock staked GIV for a number of GIVpower rounds (2 weeks each) to multiply its GIVpower. Pass `max` as the amount to lock all staked GIV that is not already locked; a zero amount does nothing. Locked GIV cannot be unstaked until the last round ends and it is unlocked. ## Syntax ```evml giveth:lock ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `command \| number` | Amount of staked GIV to lock in base units (wei), or the keyword `max` for all staked GIV not already locked (see @giveth:lockable) | | `rounds` | `number` | Number of rounds to lock for (each round lasts 2 weeks) | ## Examples ```evml # Lock 100 staked GIV for 26 rounds (a year) to multiply its GIVpower giveth:lock 100e18 26 # Lock all staked GIV that is not already locked giveth:lock max 26 ``` ## Power multiplier Locking multiplies GIVpower: `amount * sqrt(rounds + 1)` instead of a 1x weight. Each round lasts two weeks; the lock releases at the end of its last round, after which [giveth:unlock](unlock.md) makes the tokens unstakeable again. ## See Also - [giveth:unlock](unlock.md) - [@giveth:round](../helpers/round.md) - [@giveth:givpower](../helpers/givpower.md) --- --- title: "giveth:stake" --- Stake GIV for GIVpower, approving the staking contract automatically when needed. Pass `max` as the amount to stake the full GIV balance; a zero amount does nothing. On Gnosis GIV is wrapped into gGIV through the GIVgarden (which auto-stakes it); on Optimism and Polygon zkEVM it is staked directly. Staked GIV earns GIVstream rewards and can be locked for more GIVpower. ## Syntax ```evml giveth:stake ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `command \| number` | Amount of GIV to stake in base units (wei), or the keyword `max` for the full GIV balance (see @giveth:stakable) | ## Options | Name | Type | Description | |------|------|-------------| | `--no-approve` | `bool` | Skip the automatic allowance check and approve action | ## Examples ```evml # Stake 100 GIV for GIVpower (auto-approves) giveth:stake 100e18 # Stake every GIV in the wallet giveth:stake max ``` ## GIVpower lifecycle Staked GIV earns rewards (harvest them with [giveth:claim](claim.md)) and counts as GIVpower you can use to boost projects on giveth.io. Lock it with [giveth:lock](lock.md) to multiply its power. On Gnosis staking wraps GIV into gGIV through the GIVgarden; on Optimism and Polygon zkEVM it deposits into the UnipoolGIVpower contract. Commands that produce nothing (claiming with nothing accrued, staking a zero balance) simply emit no transaction, and `max` amounts count the pending effects of earlier commands in the same script. Maxing out GIVpower on a chain therefore needs no guards or bookkeeping: ```evml load giveth giveth:claim giveth:stake max giveth:lock max 26 ``` ## See Also - [giveth:unstake](unstake.md) - [giveth:lock](lock.md) - [giveth:claim](claim.md) - [@giveth:givpower](../helpers/givpower.md) --- --- title: "giveth:unlock" --- Unlock GIV locks that ended at the given GIVpower round, making the tokens unstakeable again. Anyone can unlock for any account once the round is over; the round must be earlier than the current one (see @giveth:round). ## Syntax ```evml giveth:unlock [...account] ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `round` | `number` | The round the locks ended at (must be earlier than the current round) | | `[...account]` | `address` | Accounts to unlock (defaults to the connected account) | ## Examples ```evml # Unlock your GIV locks that ended at the previous round giveth:unlock @num(@giveth:round - 1) ``` ## See Also - [giveth:lock](lock.md) - [giveth:unstake](unstake.md) - [@giveth:round](../helpers/round.md) --- --- title: "giveth:unstake" --- Unstake GIV from GIVpower: unwrap gGIV on Gnosis, withdraw from the staking contract on Optimism and Polygon zkEVM. Pass `max` as the amount to unstake everything the contract allows right now — staked GIV minus locks, where locks whose round already ended still count until giveth:unlock frees them (see @giveth:unlockable). A zero amount does nothing. ## Syntax ```evml giveth:unstake ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `amount` | `command \| number` | Amount of GIV to unstake in base units (wei), or the keyword `max` for everything not locked | ## Examples ```evml # Unstake 100 GIV from GIVpower giveth:unstake 100e18 # Unstake everything that is not locked giveth:unstake max ``` ## See Also - [giveth:stake](stake.md) - [giveth:unlock](unlock.md) --- --- title: "@giveth:boostedBy" --- Projects an account boosts with its GIVpower, as a pair of same-length arrays [slugs percentages] sorted by percentage descending. Empty arrays when the account has no boosts. **Returns**: `array` ## Syntax ```evml @giveth:boostedBy(account?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[account]` | `address` | Account to inspect (defaults to the connected account) | ## Examples ```evml # Print the projects you are boosting and their percentages print @giveth:boostedBy(@me) # Show your boosts as a table print @giveth:boostedBy(@me) --headers [Project Percentage] ``` ## See Also - [giveth:boost](../commands/boost.md) - [@giveth:givpower](../helpers/givpower.md) --- --- title: "@giveth:claimable" --- GIV an account can claim from the GIVstream right now (see giveth:claim). Counts a pending giveth:claim earlier in the script as already claimed. **Returns**: `number` ## Syntax ```evml @giveth:claimable(account?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[account]` | `address` | Account to inspect (defaults to the connected account) | ## Examples ```evml # Print the GIV your GIVstream has already released print "Claimable GIV:" @giveth:claimable() ``` ## See Also - [giveth:claim](../commands/claim.md) --- --- title: "@giveth:givpower" --- GIVpower balance of an account: staked GIV plus the extra power gained from locking. **Returns**: `number` ## Syntax ```evml @giveth:givpower(account?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[account]` | `address` | Account to inspect (defaults to the connected account) | ## Examples ```evml # Print your GIVpower balance print "GIVpower:" @giveth:givpower() ``` ## See Also - [giveth:stake](../commands/stake.md) - [giveth:lock](../commands/lock.md) --- --- title: "@giveth:lockable" --- Staked GIV an account can lock (or unstake) right now: staked GIV minus everything the GIVpower contract counts as locked, including ended locks that were never unlocked (see @giveth:unlockable). Counts pending stake/lock actions earlier in the script — what `lock max` resolves to. **Returns**: `number` ## Syntax ```evml @giveth:lockable(account?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[account]` | `address` | Account to inspect (defaults to the connected account) | ## Examples ```evml # Print the staked GIV you could lock right now print "Lockable GIV:" @giveth:lockable() ``` ## Lockable vs unstakable Both [giveth:lock](../commands/lock.md) and [giveth:unstake](../commands/unstake.md) are gated by the same contract check — staked balance minus `totalAmountLocked` — which is what this helper returns. [@giveth:unstakable](unstakable.md) differs by following the round clock instead: it already counts locks whose round ended but that still need a [giveth:unlock](../commands/unlock.md) ([@giveth:unlockable](unlockable.md) shows that portion). ## See Also - [giveth:lock](../commands/lock.md) - [@giveth:unlockable](unlockable.md) - [@giveth:unstakable](unstakable.md) - [@giveth:staked](staked.md) --- --- title: "@giveth:project" --- Resolve a Giveth project slug to its donation recipient address on the current chain. **Returns**: `address` ## Syntax ```evml @giveth:project(slug) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `slug` | `giveth-project` | Giveth project slug | ## Examples ```evml # Print the recipient address of a Giveth project print "evmcrispr project address:" @giveth:project(evmcrispr) ``` ## See Also - [giveth:donate](../commands/donate.md) - [@giveth:anchor](anchor.md) --- --- title: "@giveth:round" --- The current GIVpower round number (rounds last 2 weeks; locks unlock when their round is over). **Returns**: `number` ## Syntax ```evml @giveth:round ``` ## Examples ```evml # Print the current GIVpower round print "Current round:" @giveth:round() ``` ## See Also - [giveth:lock](../commands/lock.md) - [giveth:unlock](../commands/unlock.md) --- --- title: "@giveth:stakable" --- GIV in an account's wallet that giveth:stake can stake for GIVpower. Counts pending claim/stake/unstake actions earlier in the script — what `stake max` resolves to. **Returns**: `number` ## Syntax ```evml @giveth:stakable(account?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[account]` | `address` | Account to inspect (defaults to the connected account) | ## Examples ```evml # Print the GIV you could stake right now print "Stakable GIV:" @giveth:stakable() ``` ## See Also - [giveth:stake](../commands/stake.md) - [@giveth:staked](staked.md) - [@giveth:lockable](lockable.md) - [@giveth:claimable](claimable.md) --- --- title: "@giveth:staked" --- Raw GIV an account has staked for GIVpower: the gGIV balance on Gnosis, the deposit balance on Optimism and Polygon zkEVM. Includes locked GIV (see @giveth:unstakable) and counts pending giveth:stake/giveth:unstake actions earlier in the script. **Returns**: `number` ## Syntax ```evml @giveth:staked(account?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[account]` | `address` | Account to inspect (defaults to the connected account) | ## Examples ```evml # Print your staked GIV print "Staked GIV:" @giveth:staked() ``` ## See Also - [@giveth:unstakable](unstakable.md) - [@giveth:givpower](givpower.md) - [giveth:stake](../commands/stake.md) --- --- title: "@giveth:unlockable" --- GIV in locks whose GIVpower round has ended but that giveth:unlock hasn't freed yet. Until unlocked, the GIVpower contract still counts it as locked, so it can be neither locked again nor unstaked. Time-aware inside sim:fork: after a wait, newly ended locks show up here. **Returns**: `number` ## Syntax ```evml @giveth:unlockable(account?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[account]` | `address` | Account to inspect (defaults to the connected account) | ## Examples ```evml # Print the GIV a giveth:unlock would free print "Unlockable GIV:" @giveth:unlockable() ``` ## See Also - [giveth:unlock](../commands/unlock.md) - [@giveth:round](round.md) - [@giveth:lockable](lockable.md) - [@giveth:unstakable](unstakable.md) --- --- title: "@giveth:unstakable" --- GIV an account can unstake at the current chain time: staked GIV minus the locks whose GIVpower round hasn't finished yet. Locks whose round has ended count as unstakable — unlocking is permissionless — but still need a giveth:unlock before giveth:unstake accepts them. Time-aware inside sim:fork: after a wait, ended locks drop out of the locked amount. Counts pending stake/unstake/lock actions earlier in the script. **Returns**: `number` ## Syntax ```evml @giveth:unstakable(account?) ``` ## Arguments | Name | Type | Description | |------|------|-------------| | `[account]` | `address` | Account to inspect (defaults to the connected account) | ## Examples ```evml # Print how much GIV you could unstake right now print "Unstakable GIV:" @giveth:unstakable() ``` ## Reading the future from a fork The GIVpower contract doesn't expose per-round lock amounts through any view, so the helper reads them straight from contract storage and compares each lock's end round against `currentRound()`. Because `currentRound()` follows the block timestamp, warping time on a fork moves the answer: ```evml load sim sim:fork ( wait 2419200 print "Unstakable in 4 weeks:" @giveth:unstakable() ) ``` Locks that ended but were never unlocked count as unstakable because anyone can unlock them; to actually withdraw, run [giveth:unlock](../commands/unlock.md) for the finished round before [giveth:unstake](../commands/unstake.md). ## See Also - [@giveth:staked](staked.md) - [giveth:lock](../commands/lock.md) - [giveth:unlock](../commands/unlock.md) - [giveth:unstake](../commands/unstake.md)