Regular Routes
Regular routes are the default route kind. They can read and modify entity state, send messages, deploy entities, and run other route actions. Most routes in a typical Cambrian entity are regular routes.
Syntax
A regular route has no keyword modifier:
routes {
deposit(amount: U256) => [
// actions
]
}
Parameters
Route parameters are typed and positional:
transfer(to: address, amount: U256) => [
// to and amount are available here
]
Parameters are available in the action list and are referenced by name in member transforms. A route with no parameters uses empty parentheses:
increment() => []
State Access
Regular routes have full access to entity state through members. State changes are expressed in member transforms, not in the route body itself:
entity Counter {
routes {
add(value: u64) => []
}
m_total: u64 {
in add(value) => m_total + value
}
}
The route body contains actions (sends, deploys, conditionals); state mutation is handled by the member system.
Actions
The action list can contain any combination of sends, deploys, conditionals,
let bindings, emits, and evm:: intrinsics:
routes {
purchase(item_id: u64)
where msg::value >= m_prices[item_id] : throw 100
=> [
let price = m_prices[item_id];
let change = msg::value - price;
if change > 0 => [
~> msg::sender with { value: change }
],
Sold(item_id, msg::sender) ~> m_ledger
]
}
With Preconditions
Regular routes commonly use where clauses to enforce invariants:
withdraw(amount: U256)
where msg::sender == m_owner : throw 101
&& m_balance >= amount : throw 102
=> [
~> msg::sender with { value: amount }
]
If any where condition is false, the transaction reverts with the specified
error code, and no state changes or actions take effect.
With Sender Verification
The from clause restricts which entity or caller may invoke the route:
credit(account: address, amount: U256)
from Shop(_)
=> []
See From Clause for details.
Complete Example
A token transfer route combining parameters, preconditions, actions, and member transforms:
entity Token {
routes {
transfer(to: address, amount: U256)
where m_balances[msg::sender] >= amount : throw 100
&& to != msg::sender : throw 101
=> []
}
m_balances: HashMap<address, U256> {
in transfer(to, amount) => {
let from = msg::sender;
let from_bal = m_balances[from];
let to_bal = m_balances.get(to).unwrap_or(0);
m_balances
.set(from, from_bal - amount)
.set(to, to_bal + amount)
}
}
}
The route body is [] (empty) because the state change is entirely expressed
in the member transform. This is a common and idiomatic pattern.