Skip to main content

Functions

Functions in Lyquid are declared with the lyquid::method! macro and are split into two categories, each mapping naturally to one of the two state categories:

🔹 Network Functions (Lyquid-level Execution)​

  • Every node hosting the same Lyquid executes the identical, deterministic sequence of calls to network functions.
  • Can only read and write network state.
  • Similar to Solidity's public or external functions.
lyquid::method! {
network fn transfer(&mut ctx, to: Address, amount: U256) -> LyquidResult<bool> {
let from = ctx.caller.clone();
transfer(&mut ctx.network, from, to, amount)?;
Ok(true)
}

network fn approve(&mut ctx, spender: Address, value: U256) -> LyquidResult<bool> {
approve(&mut ctx.network, ctx.caller, spender, value, true)?;
Ok(true)
}
}

🔸 Instance Functions (Node-level Execution)​

If you're coming from Solidity, think of instance functions as supercharged view functions with much more power.

  • Like view functions, they can read network state, but not modify it.
  • Unlike Solidity, they can also read/write instance state and handle events that may differ from node to node, such as network messages.

In Lyquid, instance functions are a first-class concept that unlock entirely new design patterns:

  • Resilient API request and response (via UPC)
  • Heavy-lifting computation
  • Local caching and performance metrics
lyquid::method! {
instance fn balance_of(&ctx, account: Address) -> LyquidResult<U256> {
// Can function like a regular `view` function as in Solidity, &ctx promises not to modify any state.
Ok(get_balance(&ctx.network, &account).clone())
}

instance fn party_sign(&mut ctx, tx: Transaction) -> LyquidResult<Option<Signature>> {
Ok(if validate(tx) {
ctx.multi_sig_key.map(|| key.sign(tx.digest()))
} else {
None
})
}

instance fn record_transaction(&mut ctx, tx: Transaction) -> LyquidResult<()> {
ctx.instance.tx_history.push(tx);
Ok(())
}

instance fn analyze_trading_pattern(&mut ctx, user: Address) -> LyquidResult<Analysis> {
let history = &ctx.instance.tx_history;
let user_txs: Vec<_> = history.iter()
.filter(|tx| tx.user == user)
.collect();
Ok(analyze_transactions(&user_txs))
}
}

💡 Unlike Solidity, instance functions can access node-local state and react to off-chain events. You can even define functions that aggregate results across multiple nodes via UPC, enabling powerful new architectures, like customized oracle and bridging, decentralized order matching, multi-party computation, and so on.

See lyquid::method! for full syntax and advanced UPC forms.