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

Send Messages (~>)

The ~> action is how Cambrian expresses outbound calls and value transfers. On EVM, typed sends lower to external calls; plain transfers lower to native currency sends.

Named (typed) send

Invoke a route on a destination whose type is known:

transfer(amount) ~> m_token
Token::transfer(to, amount) ~> m_token_address

The destination should be an Address<Entity> (or a predicted Entity.address(...)). Named sends to a plain address are rejected (V23). The target entity must be in the project or declared extern entity (E22 otherwise).

Capturing a return value

var bal = balanceOf(who) ~> m_token;

This is a synchronous call: the callee runs, and bal binds the returned value for later actions, transforms, or a per-phase where. Captures are the usual reason to introduce phases; unphased routes already flush storage updates before external calls (checks-effects-interactions).

Plain value transfer

~> recipient with { value: amount }

Transfers native currency without calling a function on the destination.

Message options (with)

On EVM the meaningful option is value — wei attached to the CALL / CREATE:

Worker::start() ~> worker with { value: amount }
~> msg::sender with { value: amount }

Destinations

Notify(data) ~> m_observer
~> to with { value: amount }
~> msg::sender with { value: amount }
Ping() ~> Token.address(token_id)

Multiple sends

distribute(amount: U256) => [
    let share = amount / 3;
    ~> m_partner_a with { value: share },
    ~> m_partner_b with { value: share },
    ~> m_partner_c with { value: amount - share * 2 }
]

Example

entity Token {
    routes {
        transfer(to: address, amount: U256)
            where m_balances[msg::sender] >= amount : throw InsufficientBalance(m_balances[msg::sender], amount)
        => [
            TransferNotification(msg::sender, to, amount) ~> m_observer
        ]
    }

    m_balances: HashMap<address, U256> {
        in transfer(to, amount) => {
            let from = msg::sender;
            m_balances
                .set(from, m_balances[from] - amount)
                .set(to, m_balances.get(to).unwrap_or(0) + amount)
        }
    }

    m_observer: Address<Observer> {
        in init(_, observer) => observer
    }
}