Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Local State

Local state manages temporary variables used within Ursus functions. Unlike contract fields (which persist on the blockchain), local variables exist only during function execution.

What is Local State?

Local state is a type-indexed container that holds temporary values during function execution. It's managed through the UseLocal command.

Key properties:

  • Temporary - Exists only during function execution
  • Type-safe - All local variables are type-checked
  • Scoped - Variables are scoped to their function
  • Efficient - No blockchain storage costs

UseLocal Command

The UseLocal command declares which types can be used for local variables in the contract.

Syntax

UseLocal Definition _ := [
    type1;
    type2;
    ...
    typeN
].

Example

UseLocal Definition _ := [
    boolean;
    address;
    uint256;
    string;
    (mapping address uint256);
    (optional uint256)
].

Important: Include all types you'll use for local variables, including:

  • Primitive types
  • Composite types (mappings, optionals, arrays)
  • User-defined types

Declaring Local Variables

Using var Notation

Syntax:

::// var 'name : type := value .

Examples:

::// var 'balance : uint256 := {1000} .
::// var 'sender : address := msg->sender .
::// var 'active : boolean := @true .

Using new Notation

Syntax:

refine // new 'name : type @ "name" := value ; _ //.

Example:

refine // new 'x : uint256 @ "x" := {42} ; _ //.

Difference:

  • var - Modern, recommended syntax
  • new - Older syntax, allows chaining in one line

Using Local Variables

Reading Variables

Local variables can be used in expressions:

::// var 'x : uint256 := {10} .
::// var 'y : uint256 := {20} .
::// var 'sum : uint256 := x + y .

Modifying Variables

Assign new values to local variables:

::// var 'counter : uint256 := {0} .
::// counter := counter + {1} .
::// counter := counter * {2} .

Scope

Local variables are scoped to their block:

{
    ::// var 'x : uint256 := {10} .
    ::// if x > {5} then { ->> } else { ->> } | .
    {
        ::// var 'y : uint256 := x + {5} .  (* x is visible *)
        ::// result := y |.
    }
    {
        ::// result := x |.  (* x is visible, y is not *)
    }
}

Local vs Contract State

AspectLocal VariablesContract Fields
LifetimeFunction executionPersistent
StorageMemoryBlockchain
CostLowHigh (gas)
ScopeFunction-localContract-wide
Declarationvar / newRecord Contract

Complete Example

#[translation = on]
#[language = solidity]
Contract Calculator ;
Sends To ;
Types ;
Constants ;

Record Contract := {
    last_result: uint256
}.

SetUrsusOptions.

UseLocal Definition _ := [
    uint256;
    boolean
].

#[pure, returns=_result]
Ursus Definition add (a: uint256) (b: uint256): UExpression uint256 false.
{
    ::// var 'sum : uint256 := a + b .
    ::// _result := sum |.
}
return.
Defined.
Sync.

#[returns=_result]
Ursus Definition complex_calc (x: uint256): UExpression uint256 false.
{
    ::// var 'temp1 : uint256 := x * {2} .
    ::// var 'temp2 : uint256 := temp1 + {10} .
    ::// var 'is_large : boolean := temp2 > {100} .

    ::// if is_large then { ->> } else { ->> } | .
    {
        ::// _result := temp2 |.
    }
    {
        ::// _result := {0} |.
    }
}
return.
Defined.
Sync.

Advanced Patterns

Temporary Mappings

UseLocal Definition _ := [
    (mapping address uint256)
].

Ursus Definition process_balances: UExpression PhantomType false.
{
    ::// var 'temp_balances : mapping address uint256 := {} .
    ::// temp_balances[[msg->sender]] := {1000} .
    ::// var 'bal : uint256 := temp_balances[[msg->sender]] |.
}
return.
Defined.

Temporary Arrays

UseLocal Definition _ := [
    (array uint256)
].

Ursus Definition collect_values: UExpression PhantomType false.
{
    ::// var 'values : array uint256 := [] .
    ::// values->push({10}) .
    ::// values->push({20}) .
    ::// var 'first : uint256 := values[[{0}]] |.
}
return.
Defined.

Temporary Records

Types
  Record TempData := {
      value: uint256;
      flag: boolean
  };

UseLocal Definition _ := [
    (_ResolveName "TempData")
].

Ursus Definition process_data: UExpression PhantomType false.
{
    ::// var 'data : TempData := [$ {42} ⇒ value ; @true ⇒ flag $] .
    ::// var 'v : uint256 := data->value |.
}
return.
Defined.

Best Practices

1. Declare All Used Types

Good:

UseLocal Definition _ := [
    uint256;
    address;
    boolean;
    (mapping address uint256)
].

Avoid:

UseLocal Definition _ := [
    uint256
].
(* Missing types will cause compilation errors *)

2. Use Meaningful Names

Good:

::// var 'sender_balance : uint256 := balances[[msg->sender]] .
::// var 'is_sufficient : boolean := sender_balance >= amount .

Avoid:

::// var 'x : uint256 := balances[[msg->sender]] .
::// var 'y : boolean := x >= amount .

3. Minimize Local State

Good:

::// var 'balance : uint256 := balances[[msg->sender]] .
::// balances[[msg->sender]] := balance - amount |.

Avoid:

::// var 'temp1 : uint256 := balances[[msg->sender]] .
::// var 'temp2 : uint256 := temp1 .
::// var 'temp3 : uint256 := temp2 - amount .
::// balances[[msg->sender]] := temp3 |.

4. Use Local Variables for Clarity

Good:

::// var 'sender_balance : uint256 := balances[[msg->sender]] .
::// var 'recipient_balance : uint256 := balances[[recipient]] .
::// var 'new_sender_balance : uint256 := sender_balance - amount .
::// var 'new_recipient_balance : uint256 := recipient_balance + amount .

::// balances[[msg->sender]] := new_sender_balance .
::// balances[[recipient]] := new_recipient_balance |.

Avoid:

::// balances[[msg->sender]] := balances[[msg->sender]] - amount .
::// balances[[recipient]] := balances[[recipient]] + amount |.

Common Errors

Missing Type in UseLocal

Error:

Type not found in local state

Solution: Add the missing type to UseLocal:

UseLocal Definition _ := [
    uint256;
    address  (* Add missing type *)
].

Type Mismatch

Error:

Type mismatch: expected uint256, got boolean

Solution: Ensure variable types match their usage:

::// var 'count : uint256 := {0} .  (* Not boolean *)

See Also