✍️ Writing the Code
If you just want to try out the code immediately, jump to Build and Deploy.
Defining State
Lyquid explicitly separates on-chain ("network") and off-chain ("instance") state.
use lyquid::prelude::*;
state! {
network greeting: String = String::new();
network greet_count: u64 = 0;
// Off-chain state
instance per_user_count: HashMap<Address, u64> = new_hashmap();
}
network greetingandgreet_countclosely match Solidity's public storage variables.instance per_user_countintroduces a completely new capability: node-local persistent state, which Solidity does not support.
A Simple, Familiar Constructor
Just like Solidity, our Lyquid constructor initializes global state:
#[method::network(export = eth)]
fn constructor(ctx: &mut _, greeting: String) {
*ctx.network.greeting = greeting;
}
This closely mirrors Solidity’s constructor:
constructor(string memory _greeting) {
greeting = _greeting;
}
Updating the Greeting (set_greeting)
Next, we implement a simple function to update our greeting message:
#[method::network(export = eth)]
fn set_greeting(ctx: &mut _, greeting: String) -> LyquidResult<bool> {
*ctx.network.greeting = greeting;
Ok(true)
}
Solidity equivalent:
function setGreeting(string calldata _greeting) external {
greeting = _greeting;
}
Both versions are concise. Lyquid’s explicit state model clearly indicates that this function
modifies global on-chain state (network), enhancing clarity and correctness.
Tracking Greetings (greet)
Every greeting increments a global counter:
#[method::network(export = eth)]
fn greet(ctx: &mut _) -> LyquidResult<bool> {
*ctx.network.greet_count += 1;
Ok(true)
}
Solidity equivalent:
function greet() external {
greetCount += 1;
}
Again, the logic aligns directly, but Lyquid explicitly scopes this change to global state, reinforcing clear ownership and intention.
Efficiently Formatting Messages (get_greeting_message)
The Lyquid version simplifies formatted message generation:
// This network function only reads network state (`&ctx`), so it's like a "view" function in
// Solidity. You can also write `instance fn` instead, but since we don't use any instance
// state here it's good to be conservative, so you can't touch upon instance state accidentally.
#[method::network(export = eth)]
fn get_greeting_message(ctx: &_) -> LyquidResult<String> {
Ok(format!(
"{} I've greeted {} times to on-chain users",
ctx.network.greeting, ctx.network.greet_count
))
}
Solidity’s version is verbose, requiring external libraries (OpenZeppelin) or manual conversions:
function getGreetingMessage() external view returns (string memory) {
return string(
abi.encodePacked(
greeting,
"I've greeted",
greetCount.toString(),
" times to on-chain users"
)
);
}
Lyquid leverages Rust’s native format! macro, providing concise, efficient, and highly readable code.
Extending Solidity with Off-Chain Power (greet_me)
Now comes the most exciting feature unique to Lyquid. We'd like to also keep some per-user, off-chain state at each node so the computation knows how many times the user calls this method to the node.
// The off-chain computation below CANNOT be done by Solidity/EVM.
#[method::instance(export = eth)]
fn greet_me(ctx: &mut _) -> LyquidResult<String> {
let mut per_user_count = ctx.instance.per_user_count.write();
let user = per_user_count.entry(ctx.caller).or_default();
*user += 1;
Ok(format!(
"{} I've greeted {} times to on-chain users, and {} times to you",
ctx.network.greeting, ctx.network.greet_count, *user
))
}
Solidity Equivalent: Not Possible!
This function shows Lyquid's off-chain power: node-local, persistent state per user. In this example it's used for personalized interactions (per-user counters) and off-chain analytics. But with off-chain network requests and also UPC, one can build any distributed system, and enjoy the on-chain state management to programmably control the nodes' off-chain behavior seamlessly.
Lyquid keeps the simple, readable style of Solidity, but adds off-chain power, enabling richer and more efficient decentralized services, without extra complexity.
You write less, clearly see state management, and achieve far more.