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

Conditional Actions

Conditional actions allow a route to execute different sets of actions based on runtime conditions. They use an if/else syntax within the action list.

Syntax

if condition => [
    // actions when true
] else [
    // actions when false
]

The else branch is optional:

if condition => [
    // actions when true
]

Basic Usage

Execute an action only when a condition is met:

routes {
    forward() => [
        if msg::value > 0 => [
            ~> m_recipient with { value: msg::value }
        ]
    ]
}

If/Else

Choose between two action sequences:

routes {
    forward() => [
        if msg::value >= m_threshold => [
            emit LargeTransfer(msg::sender, msg::value);
            ~> m_cold_wallet with { value: msg::value }
        ] else [
            ~> m_hot_wallet with { value: msg::value }
        ]
    ]
}

Conditions

The condition can be any boolean expression:

Comparisons

if m_balance >= amount => [
    ~> recipient with { value: amount }
]

Macro Calls

if @is_owner() => [
    ~> m_treasury with { value: m_balance }
]

Member State

if m_status == Status::Active => [
    process(data) ~> m_processor
] else [
    enqueue(data) ~> m_queue
]

Compound Conditions

if amount > 0 && m_balance >= amount => [
    ~> msg::sender with { value: amount }
]

Nested Conditionals

Conditional actions can be nested for multi-branch logic:

routes {
    categorize(score: u64) => [
        if score >= 90 => [
            award("gold") ~> m_rewards
        ] else [
            if score >= 70 => [
                award("silver") ~> m_rewards
            ] else [
                award("bronze") ~> m_rewards
            ]
        ]
    ]
}

Conditional Sends

A common pattern is conditionally sending a refund. An if condition reads the members after the route’s transforms, so the previous bid and bidder are bound in an earlier phase, before the transforms overwrite them:

entity Auction {
    routes {
        bid()
            where msg::value > m_highest_bid : throw 100
        => [
            snap: [
                let prev_bid = m_highest_bid;
                let prev_bidder = m_highest_bidder;
            ]
            refund: [
                if prev_bid > 0 => [
                    ~> prev_bidder with { value: prev_bid }
                ]
            ]
        ]
    }

    m_highest_bid: U256 {
        in bid() => refund: msg::value
    }

    m_highest_bidder: address {
        in bid() => refund: msg::sender
    }
}

This refunds the previous highest bidder only if there was a previous bid.

Conditional Deploy

Deploy an entity only under certain conditions:

routes {
    ensure_vault(user: address) => [
        if !m_vaults.exists(user) => [
            deploy UserVault(user) with { value: 1_000_000 }
        ]
    ]
}

Conditionals with Let Bindings

Let bindings can precede conditional actions:

routes {
    distribute() => [
        let fee = msg::value * 3 / 100;
        let net = msg::value - fee;
        if fee > 0 => [
            ~> m_treasury with { value: fee }
        ]
        ~> m_recipient with { value: net }
    ]
}

Complete Example

entity Escrow {
    event Resolved(indexed deal_id: u64, approved: bool);

    routes {
        #[factory_only]
        init setup(deal_id: u64, buyer: address, seller: address, arbiter: address) => []

        deposit()
            where msg::sender == m_buyer : throw 201
        => []

        resolve(approved: bool)
            where msg::sender == m_arbiter : throw 200
            && !m_resolved : throw 202
        => [
            if approved => [
                ~> m_seller with { value: m_amount }
                emit Resolved(m_deal_id, true);
            ] else [
                ~> m_buyer with { value: m_amount }
                emit Resolved(m_deal_id, false);
            ]
        ]
    }

    m_deal_id: u64 {
        in setup(deal_id, _, _, _) => deal_id
    }
    m_buyer: address {
        in setup(_, buyer, _, _) => buyer
    }
    m_seller: address {
        in setup(_, _, seller, _) => seller
    }
    m_arbiter: address {
        in setup(_, _, _, arbiter) => arbiter
    }
    m_amount: U256 {
        in deposit() => m_amount + msg::value
    }
    m_resolved: bool {
        in resolve(approved) => true
    }
}