API Reference
Every interface the Liqua binaries expose, in one place — the miner/chain HTTP+SSE API, the Ethash pool, the EVM JSON-RPC, the validator staking API, and the peer control plane. These are local devnet servers: each section names the binary that serves it and the port it listens on.
Conventions
- Base URL —
http://localhost:<port>. Each service is independent; start the one you need (see its tutorial). - Bodies — JSON in, JSON out.
POSTbodies areapplication/json. - CORS — the pool and validator send
Access-Control-Allow-Origin: *so a file-served page can call them; the miner is same-origin to its dashboard. - SSE — streaming endpoints are
text/event-stream; events arrive asevent: <name>\ndata: <json>\n\n. - Errors — a non-2xx status or a body
{ ok:false, reason }/{ error }.
Services & ports
| Service | Binary | Default port | Section |
|---|---|---|---|
| Miner / chain | miner/server.mjs (cli.mjs run) | :8010 HTTP | Miner |
| Ethash pool | pool/server.mjs | :8030 HTTP · :3333 Stratum | Pool |
| EVM JSON-RPC | pool/server.mjs | :8030/rpc | JSON-RPC |
| Validator | miner/validator.mjs | :7100 HTTP | Validator |
| Peer node + dashboard | node/server.mjs · liqctl.mjs | :8040 HTTP · port +1000 TCP | Peer |
| Exchange · self-mine | orderbook-dex/relayer/server.js | :8080 HTTP | Self-mine |
Miner / chain API :8010
Served by miner/server.mjs. Drives the SOMA-PoW miner and exposes the chain it produces. The
mining CLI is a thin client over POST /api/control.
The live control dashboard (miner/dashboard.html).
The block explorer UI (miner/explorer.html).
A full engine snapshot. The shape:
{
"chainId": 8888, "symbol": "LIQUA", "genesis": "0x…",
"height": 142, "headRoot": "0x…",
"running": true, "paused": false,
"bits": 18, "autoDiff": true, "targetBlockMs": 2500,
"hashCap": 0, "hps": 14820, "hashes": 1922334,
"supply": 284.51, "emissionNow": 1.998,
"posture": 0.2, "marker": "CALM",
"validators": 4, "mempool": 0, "uptimeMs": 95120,
"recent": [{ "height", "root", "ts", "nonce", "tries",
"reward", "witnesses", "K", "blockMs", "hps" }]
}Recent blocks (newest first). limit caps at 500.
One block by height (?h=142) or by SOMA root (?id=0x…).
Live stream. event: state fires ~every 600 ms with the gauge snapshot; event: log fires per log line ({ t, level, msg }, level ∈ info·ok·warn·mine·block·ctl·err).
Drive the miner. Body { "action": "<a>", "value": <v> }; replies { ok:true, state } with the fresh snapshot.
| action | value | effect |
|---|---|---|
speed | factor (def 1.5) | multiply the hash cap (faster) |
slow | factor (def 1.5) | divide the hash cap (slower) |
unthrottle | — | remove the cap (CLI max) |
cap | H/s (0 = off) | set an exact hashrate ceiling |
bits | integer | set PoW difficulty bits |
auto | bool | enable/disable difficulty auto-retarget |
target | ms (≥250) | target block time for auto-retarget |
pause · resume | — | halt / continue production |
addtx | tx field | inject a tx into the mempool |
Pool API :8030 stratum :3333
Served by pool/server.mjs — HTTP/SSE for the dashboard, a dual-dialect Stratum TCP listener for
miners, and an EVM JSON-RPC for wallets.
Pool stats + payout ledger + L1 bridge + connect info: { …engine.stats(), ledger, l1, connect }. l1 carries the bridged chain height + on-chain balances; ledger carries off-chain PPLNS balances + history.
Everything a miner needs to connect, with the pool's detected LAN IP pre-filled:
{
"url": "stratum+tcp://192.168.1.20:3333",
"stratumPort": 3333, "httpPort": 8030,
"hosts": ["192.168.1.20", …], "bestHost": "192.168.1.20",
"algo": "ethash", "epoch": 0,
"shareDiff": 6000000, "networkDiff": 500000000,
"payoutMode": "pplns", "reward": 2, "symbol": "LIQUA",
"username": "YOUR_LIQUA_ADDRESS.worker",
"examples": { "sim": "node pool/sim-miner.mjs …",
"lolminer": "lolMiner --algo ETHASH …",
"teamred": "teamredminer -a ethash …" }
}Sealed pool blocks — list, or one by height / id. Same shape family as the miner's.
Live pool stream — emits event: state (full pool state) and event: xstate (explorer view) ~every 1 s.
Operator controls for the pool engine (difficulty, payout mode, etc.).
Real Stratum, two dialects (auto-detected). The username a miner authorizes with is its payout address. Methods handled:
- Simple / NiceHash —
mining.subscribe·mining.authorize·mining.submit·mining.extranonce.subscribe(the server repliesmining.set_difficulty+mining.notify). - ethproxy —
eth_submitLogin·eth_getWork·eth_submitWork·eth_submitHashrate.
Each accepted share is verified for real (@ethereumjs/ethash hashimoto-light); a share clearing the network target seals a block, splits PPLNS, and bridges to L1.
EVM JSON-RPC :8030/rpc
A minimal Ethereum JSON-RPC over the L1 bridge world-state, so a standard wallet (e.g. the L8 wallet) can read
Liqua balances. POST /rpc (or POST /), standard { jsonrpc, id, method, params }.
| Method | Returns |
|---|---|
eth_chainId | chain id (hex) — bridge genesis chain |
net_version | chain id (decimal string) |
web3_clientVersion | "liqua-pool-bridge/0.1" |
eth_blockNumber | current L1 height (hex) |
eth_getBalance | on-chain LIQUA balance of the address (hex wei) |
eth_getBlockByNumber | a minimal block header for the current height |
eth_gasPrice · eth_estimateGas | 1 gwei · 21000 (static devnet values) |
eth_getTransactionCount · eth_getCode · eth_call | 0x0 / 0x (read-only bridge surface) |
eth_syncing | false |
This RPC exposes the bridge's settled
balances for wallets to read. It is not a general execution endpoint — eth_call / eth_getCode
return empty. Contract interaction happens through the chain's own tx path, not here.
Validator API :7100
Served by miner/validator.mjs. Consumed by the validator connect page.
Read endpoints are GET; staking + attestation are POST.
Chain + stake parameters that drive the connect UI:
{
"chainId": 8888, "symbol": "LIQUA", "decimals": 18,
"veLock": { "dMaxYears": 4, "boostMax": 0.5, … },
"emission": {…}, "governance": { "quorum": 0.98 }, "reward": {…},
"policy": { "minStake", "maxLockYears": 4, "boostMax": 0.5, "maxLockSeconds" },
"height", "somaRoot", "genesis",
"stake": { "token", "ve", "faucetAmount": 100000 },
"set": { "count", "totalStaked", "totalVe", "online" }
}The full validator set, ranked by ve-weight, with per-validator stake, lock, weight, share, online status, and blocks co-signed.
Your validator record, if registered: { found, validator }.
Staking config (token/ve/min) · your on-chain lock: { balance, locked, stake, veWeight, unlockAt, expired }.
Current head ({ height, somaRoot, … }) · chain summary · node status (also at /api/state): chainId, height, supply, validators, tally, set, miners[].
Devnet — grant test LIQUA. Body { address } → { ok, granted }.
Two-step signed staking. build with { from, action, amount, duration }
(action ∈ approve · createLock · withdraw) returns { ok, tx, hash }; sign the
hash and submit { tx, from, sig, v } → { ok, … }.
Join the set. Body is a signed LIQUA-VALIDATOR-REGISTER message — either
{ scheme:"native", address, pubkey, stake, lockSeconds, nonce, sig, rec } or
{ scheme:"eip191", address, stake, lockSeconds, nonce, sig } → { ok, validator }.
Co-sign the live head. Body { pubkey, head, sig, rec } (sign the head's somaRoot)
→ { ok, blocksCosigned }. This is the §1e proof-of-participation tick.
Peer control plane node port + 1000
A running full node (node/full.mjs) exposes an admin control plane on its node port + 1000
as line-delimited JSON over TCP. The operator handle is liqctl;
it sends { cmd, args } and reads back { ok, result }.
| cmd | args | result |
|---|---|---|
status | — | { name, lnode, height, head:{hash}, stateRoot, evmPeers, peersConnected, peersDiscovered, miner } |
head | — | the current canonical head block |
chain | — | chain summary |
peers | — | discovered / connected / EVM peers |
produce | { n } | produce N blocks (operator-driven) |
stop | — | graceful shutdown |
# the CLI adds 1000 to the node port to reach the control socket
node node/liqctl.mjs --port 30303 status # → control:31303
node node/liqctl.mjs --port 30303 produce '{"n":1}'
Peer dashboard :8040 HTTP
A browser can't reach the raw-TCP control plane, so node/server.mjs boots a full node in-process and
bridges it to HTTP/SSE — this is what the peer dashboard talks to.
The node snapshot:
{
"name", "id", "lnode", "miner",
"chainId": 8888, "genesis": "0x…",
"height": 6, "head": { "number", "hash" }, "stateRoot": "0x…",
"peersDiscovered", "peersConnected", "evmPeers",
"peers": [{ "id", "head" }],
"controlPort", "httpPort", "port", "uptimeMs",
"recent": [{ "height", "soma", "txs" }]
}Live stream — event: state (~every 1.5 s) + event: log per event
({ t, level, msg }, level ∈ discover·peer·reject·drop·tx·block·produce·sync·err·sys). GET /api/log returns the buffered log.
Body { "action": "produce", "n": 1 } produces N blocks locally and gossips them;
{ "action": "stop" } shuts the node down. Returns { ok, produced, state }.
Self-mine · exchange :8080
The self-mine → locked liquidity feature runs on the orderbook-DEX. Its relayer
(orderbook-dex/relayer/server.js, :8080) serves the deploy config + the
/self-mine.html UI; the SelfMineLiquidity contract holds
positions and is read on-chain (positionOf · page · previewZap ·
totalLpLocked). The driver that delivers mined emission is
orderbook-dex/scripts/self-mine-relayer.js — npm run self-mine
(--demo · --once · --miner/--amount).
Full walkthrough: Self-Mine into Locked Liquidity.
See also
- Run a Peer — the node, discovery, and
liqctlin context. - Mining — the miner CLI and pool, driving these endpoints.
- Become a Validator — the staking flow over the validator API.
- The Spec (§0–§8) — what the numbers mean.