Rivellum

Rivellum Portal

Download Wallet (Chrome)
Checking...
mainnet

Mist Language Reference

Complete reference for the Mist smart contract language — every keyword, type, operator, statement, and expression form.

Overview

Mist is an indentation-based, statically typed language purpose-built for value-safe smart contracts on Rivellum. Contracts written in Mist produce PVI (Proof-Verified Invocation) graphs — typed DAGs of value operations verified by the UVL engine before any state change occurs.

Mist Source → Parser → AST → Type Check → Value IR → Static Analysis → MCE → PVI Graph → Bundle

Mist enforces value safety at the language level. You cannot directly mutate balances — all value movement flows through seven primitives (hold, pay, release, refund, split, mint, burn) that the compiler and runtime verify for conservation, linearity, and correctness.

Contract Structure

Every Mist file defines exactly one contract. A contract contains state declarations, function definitions, and event declarations:

contract MyContract
    state count: Int
    state owner: Address

    event CountChanged(new_count: Int, who: Address)

    function init()
        count = 0
        owner = caller
        emit CountChanged(count, caller)

    function increment()
        require caller == owner
        count = count + 1
        emit CountChanged(count, caller)

Indentation Rules

Mist uses Python-style significant whitespace. Blocks are defined by indentation level, not braces or end keywords.

  • Only spaces are allowed — tabs cause a compile error (MixedIndentation)
  • Increasing indentation opens a new block
  • Decreasing indentation closes the block
  • The indentation level must match a previously opened block — mismatched levels cause an IndentationMismatch error
  • Blank lines and comment-only lines are ignored during indentation processing
contract Example
    # This is indented one level — the contract body

    function foo()
        # Two levels — the function body
        if count > 0
            # Three levels — the if body
            count = count - 1
        else
            # Three levels — the else body
            count = 0

Comments

Line comments start with # and extend to the end of the line:

# This is a comment on its own line
count = count + 1  # This is an inline comment

There are no block comments.

Types

Mist has 7 concrete types:

TypeKeyword(s)DescriptionSize
IntInt, U128Unsigned 128-bit integer16 bytes
BoolBoolBoolean (true / false)1 byte
StringStringUTF-8 stringVariable
AddressAddress32-byte account address32 bytes
TimestampTimestamp, U64Unsigned 64-bit integer (milliseconds)8 bytes
ValueValue, VaultRefReference to a value vault (linear type)Opaque
AssetAssetAsset identifier32 bytes

Integer Semantics

All integers in Mist are unsigned 128-bit (u128). There are no signed integers, floating-point numbers, or smaller integer types at the language level. Arithmetic overflow causes a runtime error (MIST_E023), and division by zero causes MIST_E024.

The Value Type

Value (also written VaultRef) is a linear type — it represents a vault holding assets. Vaults must be consumed exactly once (via pay, release, refund, split, or burn). The compiler's static analysis phase will reject contracts that leave vaults unconsumed (MIST_E_LOCKED_FUNDS) or consume them more than once.

Gradual Typing

The type checker uses a Unknown type for values whose type cannot be statically determined (oracle reads, state reads, field accesses). Unknown is compatible with any concrete type — this allows oracle-dependent logic to typecheck without explicit casts.

State Declarations

State variables persist across function calls and are declared at the top of the contract body:

contract Vault
    state balance: Int
    state owner: Address
    state name: String
    state locked: Bool
    state escrow_vault: Value

State variables are accessed and assigned by name within functions:

function deposit(amount: Int)
    balance = balance + amount

Event Declarations

Events are declared with a name and typed fields, then emitted from functions:

contract Token
    event Transfer(from: Address, to: Address, amount: Int)
    event Approval(owner: Address, spender: Address, amount: Int)

    function transfer(to: Address, amount: Int)
        require amount > 0
        emit Transfer(caller, to, amount)

Events become on-chain log entries searchable via the events API.

Functions

Functions are declared with function, an optional parameter list, and an optional return type:

# No parameters, no return
function init()
    count = 0

# With parameters
function transfer(to: Address, amount: Int)
    require amount > 0

# With return type
function get_count() -> Int
    return count

# With parameters and return type
function add(a: Int, b: Int) -> Int
    return a + b

The init Function

The init function is called exactly once when the contract is deployed. It initializes state and can take constructor arguments:

function init(initial_supply: Int)
    require initial_supply > 0
    owner = caller
    total_supply = initial_supply

The caller Intrinsic

caller returns the Address of the account that submitted the current intent. It is the primary mechanism for access control:

function admin_only()
    require caller == owner, "Only owner can call this"

Statements

Variable Binding (let)

let x = 42
let name = "hello"
let is_valid = true
let addr = caller

Type annotations are optional — the type is inferred from the expression:

let x: Int = 42
let name: String = "hello"

Assignment

count = count + 1
owner = caller
name = "updated"

Conditional (if / else)

if count > 0
    count = count - 1
else
    count = 0

else is optional. Conditions must be Bool.

Guards (require / assert)

require and assert halt execution if the condition is false. An optional message string provides context:

require caller == owner
require amount > 0, "Amount must be positive"
assert balance >= amount, "Insufficient balance"

Both compile to the same VIR pattern: a branch that panics on the false path. At runtime, a failed require produces error code MIST_E021 and a failed assert produces MIST_E022.

Return

function get_count() -> Int
    return count

function early_exit()
    if done == true
        return
    count = count + 1

Emit

emit Transfer(caller, recipient, amount)
emit Initialized(owner)

The event name must match a declared event, and arguments must match the event's field count and types.

Expressions

Literals

42              # Int (u128)
0               # Int
1000000000      # Int (1 RIVL in base units, 9 decimals)
"hello world"   # String (double quotes)
'hello world'   # String (single quotes — identical to double)
true            # Bool
false           # Bool

Escape sequences in strings: \\, \n, \t, \", \'

Integer literals are decimal only — no hex (0x), octal, binary, or underscore separators.

Arithmetic Operators

OperatorNameExampleNotes
+Additiona + bBoth operands must be Int
-Subtractiona - bBoth operands must be Int
*Multiplicationa * bBoth operands must be Int
/Divisiona / bInteger division (truncates). Division by zero → MIST_E024
%Moduloa % bRemainder after division

Comparison Operators

OperatorNameExample
==Equala == b
!=Not equala != b
<Less thana < b
<=Less or equala <= b
>Greater thana > b
>=Greater or equala >= b

Arithmetic comparisons (<, <=, >, >=) require Int operands. Equality (==, !=) requires the same type on both sides.

Logical Operators

OperatorNameExample
&&Logical ANDa && b
``
!Logical NOT!flag

All operands must be Bool.

Unary Operators

OperatorNameExample
-Negation-x
!Logical NOT!flag

Operator Precedence (Lowest to Highest)

LevelOperatorsAssociativity
1`
2&&Left
3==, !=Left
4<, <=, >, >=Left
5+, -Left
6*, /, %Left
7!, - (unary)Right
8.field, [index], (args)Left

Use parentheses to override precedence:

let result = (a + b) * c
let check = (x > 0) && (y < 100)

Field Access and Indexing

let price = obj.field
let item = arr[0]

Function Calls

let result = compute(x, y)

Function calls use simple identifier syntax — method-style calls (obj.method()) are not supported.

Intrinsics

Built-in values and functions available in any function body:

IntrinsicTypeDescription
callerAddressAddress of the intent sender
nowTimestampCurrent block commit time (milliseconds since epoch)
oracle.price("PAIR")IntOracle spot price for the given pair (1e18 fixed-point)
block_heightIntCurrent block height
block_timeIntCurrent block timestamp

Oracle Reads

Two equivalent syntax forms:

let btc_price = oracle.price("BTC_USD")
let eth_price = oracle("ETH_USD").price

Oracle prices are 1e18 fixed-point integers. For example, if BTC is $60,000, then oracle.price("BTC_USD") returns 60000000000000000000000 (60000 × 10^18).

Oracle data is committed to the execution receipt. If the oracle snapshot is stale (more than 256 blocks old), UVL verification rejects the intent with UVL_F010.

Value Operations

Value operations are the core of Mist — they define how assets move between accounts through typed, verifiable primitives. The compiler and UVL engine guarantee that every value operation conserves assets ( $\sum \text{inputs} = \sum \text{outputs} + \text{fees}$ ).

hold — Lock Assets in a Vault

hold my_vault = 1000 asset "RIVL" from caller

Creates a new vault named my_vault containing 1000 units of asset "RIVL" locked from the caller's balance. The vault must be consumed before the function returns.

Syntax: hold <vault_name> = <amount> asset <asset_expr> from <address_expr>

pay — Transfer Assets to an Address

# Direct pay (from caller's balance)
pay 500 asset "RIVL" to recipient

# Pay from a vault
pay 500 asset "RIVL" to recipient from my_vault

Transfers assets to the specified address, either from the caller's balance or from a named vault.

Syntax: pay <amount> asset <asset_expr> to <address_expr> [from <vault_name>]

release — Return Vault Contents to an Address

release vault escrow_vault to seller

Releases the entire contents of a vault to the specified address. Consumes the vault.

Syntax: release vault <vault_name> to <address_expr>

refund — Return Vault Contents (Refund Semantics)

refund vault escrow_vault to buyer

Semantically identical to release but indicates a refund flow. The PVI graph records it differently for auditability.

Syntax: refund vault <vault_name> to <address_expr>

split — Divide Vault Among Recipients

split vault payment into [800 to seller, 200 to platform_fee_addr]

Splits a vault's contents among multiple recipients. The sum of split amounts must equal the vault's total — the compiler checks this statically when possible. Rounding uses TruncateRemainderToLast policy.

Syntax: split vault <vault_name> into [<amount> to <addr>, <amount> to <addr>, ...]

mint — Create New Assets

mint token_vault = 1000 asset asset_id authority owner

Creates new asset units. Requires a valid mint authority — UVL verification rejects unauthorized mints with UVL_F007.

Syntax: mint <vault_name> = <amount> asset <asset_expr> authority <authority_expr>

Mint authority must be declared via can_mint policy (see Policies section).

burn — Destroy Assets

burn vault token_vault

Permanently destroys the contents of a vault. Requires burn authority.

Syntax: burn vault <vault_name>

Value Operation Guarantees

The Mist compiler and UVL engine enforce these invariants at compile time and settlement:

InvariantCheckError Code
Conservation — total value in equals total value out plus feesCompile + UVLUVL_F002
No negative balances — no account goes below zeroUVLUVL_F003
No locked funds — all vaults consumed before function returnsCompile + UVLUVL_F004
Split correctness — split amounts sum to vault totalCompile + UVLUVL_F005
Split rounding — rounding follows TruncateRemainderToLastUVLUVL_F006
Mint authority — only authorized accounts can mintUVLUVL_F007
Determinism — same inputs always produce the same PVI graphCompileStatic analysis

Keywords Reference

Structure Keywords

KeywordUsage
contractDeclares a contract: contract Name
stateDeclares state variable: state x: Int
functionDeclares a function: function name(params) -> ReturnType
eventDeclares an event: event Name(fields)

Control Flow Keywords

KeywordUsage
ifConditional: if condition
elseAlternative branch: else
returnReturn value: return expr
letVariable binding: let x = expr
requireGuard: require condition, "message"
assertGuard: assert condition, "message"
emitEmit event: emit EventName(args)

Value Operation Keywords

KeywordUsage
holdLock assets: hold v = amount asset "X" from addr
payTransfer: pay amount asset "X" to addr
releaseRelease vault: release vault v to addr
refundRefund vault: refund vault v to addr
splitSplit vault: split vault v into [...]
mintMint assets: mint v = amount asset id authority auth
burnBurn assets: burn vault v

Intrinsic Keywords

KeywordUsage
nowCurrent timestamp
oracleOracle read: oracle.price("PAIR")
callerIntent sender address

Contextual Keywords

These are used in specific syntactic positions within value operations:

asset, from, to, vault, into, authority, price

Error Codes

Compile-Time Errors

CodeMeaning
MIST_E_LOCKED_FUNDSA vault is created but never consumed (pay/release/refund/split/burn)
MIST_E_CONSERVATIONValue inputs don't equal value outputs plus fees
MIST_E_SPLIT_SUMSplit amounts don't sum to the vault total
MIST_E_MINT_AUTHORITYMint without valid authority
MIST_E_BURN_INVALIDBurn on invalid vault
MIST_E_NON_DETERMINISTICContract uses non-deterministic operations
MIST_E_UNUSED_VAULTVault created but never used
MIST_E_DIRECT_BALANCE_MUTATIONAttempted to mutate balances without value operations
MIST_E_NON_DETERMINISTIC_FEEFee computation is not deterministic
MIST_E_UNBOUNDED_LOOPLoop without provable bound

Runtime Errors

CodeMeaning
MIST_E001Invalid bundle format
MIST_E003Code hash mismatch (bundle tampered)
MIST_E005Contract already deployed at this address
MIST_E010Contract not found
MIST_E011Function not found on contract
MIST_E012Wrong number of arguments
MIST_E020General execution failure
MIST_E021require condition failed
MIST_E022assert condition failed
MIST_E023Integer overflow
MIST_E024Division by zero

UVL Settlement Errors

CodeMeaning
UVL_F001PVI commitment mismatch
UVL_F002Value conservation violation
UVL_F003Negative balance would result
UVL_F004Locked funds detected (unconsumed vault)
UVL_F005Split sum mismatch
UVL_F006Split rounding violation
UVL_F007Unauthorized mint
UVL_F008Fee commitment mismatch
UVL_F009Oracle commitment mismatch
UVL_F010Oracle snapshot stale (>256 blocks old)
UVL_F011Unsupported protocol version
UVL_F012Compiler not in allowlist

Use mistc explain <CODE> to see detailed explanations for any error code.