Host APIs
Lyquid code runs inside the Lyquor VM's sandboxed environment, but it sometimes needs capabilities that live outside the guest program: randomness, cryptography primitives, HTTP egress, UPC, sequencing, and other node-side services. Here, the host is the Lyquor VM that runs the program, whereas the guest is the Lyquid code running inside that sandbox.
lyquor_api is the bridge the guest uses to call those host-provided services. Every host function
returns LyquidResult<T>, so handle the error or call them with ?.
Some host functions are wrapped by user-friendly macros; prefer those wrappers when they exist, and
see Macro-Wrapped APIs for the mapping. Several APIs are called directly,
including signature primitives, random generation, time, HTTP, identity lookups, and
sequencer/oracle lookup helpers.
Function Category Restrictions
Many host APIs are restricted to one function category, and the restriction is enforced at runtime:
calling a restricted API from the wrong category returns LyquidError::LyquorRuntime(...). This
protects determinism for network functions: they cannot read the clock, draw randomness, sign with
the node key, or make an HTTP request.
In the tables below, the Category column is one of:
instance: only available in instance functions,network: only available in network functions,any: allowed in both categories and deterministic.
Directly Called APIs
| API | Signature | Category | Description |
|---|---|---|---|
sign | sign(msg: Bytes, cipher: Cipher) -> Bytes | instance | Sign a message with the node's key for the given Cipher |
verify | verify(msg: Bytes, cipher: Cipher, sig: Bytes, pubkey: Bytes) -> bool | any | Verify a signature (deterministic) |
random_bytes | random_bytes(length: usize) -> Vec<u8> | instance | Node-local randomness |
systime | systime() -> u64 | instance | Current node time as Unix milliseconds |
http_request | http_request(request: http::Request, options: Option<http::RequestOptions>) -> http::Response | instance | Perform an outbound HTTP(S) request |
eth_contract | eth_contract() -> Option<Address> | any | The EVM contract address bound to this Lyquid, if any |
sequence_backend_id | sequence_backend_id() -> SequenceBackendID | any | Identifier of the active sequence backend |
fetch_oracle_info | fetch_oracle_info(topic: String, target: OracleTarget, full_config: bool) -> Option<OracleEpochInfo> | instance | Read oracle epoch and committee info for a topic and target |
version | version() -> LyquidNumber | any | Current network state version |
chain_pos | chain_pos() -> ChainPos | any | Current chain position |
get_ed25519_qxy | get_ed25519_qxy(pubkey: [u8; 32]) -> (U256, U256) | any | Decompress an ed25519 public key to curve coordinates |
get_address_by_ed25519 | get_address_by_ed25519(pubkey: [u8; 32]) -> Option<Address> | any | Resolve the bartender-registered address for an ed25519 node ID at the current chain position |
get_ed25519_by_address | get_ed25519_by_address(address: Address) -> Option<NodeID> | any | Resolve the bartender-registered ed25519 node ID for an address at the current chain position |
Cipher is Ed25519 or Secp256k1. Note the asymmetry between sign (instance only, uses the
node key) and verify (deterministic, allowed in network functions).
Macro-Wrapped APIs
| Macro | Host function | Category | Description |
|---|---|---|---|
call! | inter_lyquid_call | network | Atomic inter-Lyquid network call; aborts the slot on failure |
upc! | universal_procedural_call | instance | Aggregation-style inter-Lyquid call across hosting nodes |
submit_certified_call! | submit_call | instance | Submit a certified call to the sequence backend |
trigger! | trigger | any | Schedule a function; TriggerMode::Commit mode is network only |
log! | log | network | Emit a Lyte log (EVM-event-like) |
print! / println! / eprint! / eprintln! | console_output | any | Lyquid console output |
state_set and state_get also exist in host APIs but are emitted by the generated state! code.
Do NOT call them directly; use declared state variables instead.
HTTP Request Example
An instance function can fetch external data over HTTP, and decode the response body with serde_json or
any other parser in Rust.
use lyquid::prelude::*;
use lyquid::http::{Method, Request, RequestOptions};
#[method::instance]
fn fetch_price(_ctx: &mut _, symbol: String) -> LyquidResult<U256> {
let req = Request {
method: Method::Get,
url: format!("https://api.example.com/ticker?symbol={symbol}"),
headers: vec![],
body: None,
};
let resp = lyquor_api::http_request(req, Some(RequestOptions { timeout_ms: Some(1000) }))?;
if resp.status != 200 {
return Err(LyquidError::LyquorRuntime(format!("HTTP {}", resp.status)));
}
// ... (parse resp.body, store into instance state, or return a value)
Ok(U256::ZERO)
}
http::Request carries method, url, headers: Vec<Header>, and body: Option<Vec<u8>>.
http::Response carries status: u16, headers: Vec<Header>, and body: Vec<u8>.
http_request is instance-only, so results that need to reach network state must go through a
certified call; see Sequence Backend & Certified Calls.