Host APIs
Lyquid guest code reaches the node through the lyquor_api host bridge. Every host function returns
LyquidResult<T>, so call them with ?. Most are wrapped by higher-level macros — call!, upc!,
trigger!, submit_certified_call!, log!, println! — and you should prefer the macro. A handful
are called directly: signing, randomness, time, HTTP, identity lookups, and oracle/sequencer
metadata.
Context Restrictions
Many host APIs are restricted to one method category, and the restriction is enforced at runtime:
calling a restricted API from the wrong context returns LyquidError::LyquorRuntime(...) instead of
executing. This is how determinism is protected — a network method physically cannot read the clock,
draw randomness, sign with the node key, or make an HTTP request.
In the tables below, the Context column is one of:
instance— instance methods only (errors from a network context)network— network methods only (errors from an instance context)any— allowed in both, deterministic
Directly Called APIs
| API | Signature | Context | Purpose |
|---|---|---|---|
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 sequencing backend |
fetch_oracle_info | fetch_oracle_info(topic: String, target: OracleTarget, full_config: bool) -> Option<OracleEpochInfo> | instance | Read oracle epoch/committee metadata 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 | Map an ed25519 public key to its address |
get_ed25519_by_address | get_ed25519_by_address(address: Address) -> Option<NodeID> | any | Map an address to its node ID |
Cipher is Ed25519 or Secp256k1. Note the asymmetry between sign (instance only, uses the
node key) and verify (deterministic, allowed in network methods).
Macro-Wrapped APIs
Prefer the macro; it encodes/decodes named fields and applies the correct semantics. The underlying host function is listed for reference.
| Macro | Host function | Context | Notes |
|---|---|---|---|
call! | inter_lyquid_call | network | Atomic inter-Lyquid network call; aborts the slot on failure |
upc! | universal_procedural_call | instance | Off-chain inter-Lyquid call across hosting nodes |
submit_certified_call! | submit_call | instance | Submit a certified call to the sequencing backend |
trigger! | trigger | any | Schedule a function; TriggerMode::Commit 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 on the bridge but are emitted by the generated state! code.
Do not call them directly; use declared state variables instead.
HTTP Request Example
An instance method can fetch external data over HTTP. Decode the response body with serde_json or
any other parser.
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>. Because
http_request is instance-only, results that must reach network state have to go through an
oracle/certified-call flow — see Oracles and Certified Calls.