Reference

Oyster Pool docs

Everything you need to mine, query, or audit Oyster Pool. The miner JSON-RPC is what the binary speaks to the pool; the REST + WebSocket API is what the dashboard reads — and what you can build on.

01

What Oyster Pool is

Oyster Pool is a Pearl-blockchain mining pool. Pearl is a Proof-of-Useful-Work chain whose PoW is matrix multiplication verified by a Plonky2 SNARK. Oyster Pool's job is to give your miner work, validate the proofs it ships back, find blocks, and route the rewards.

  • 3 % fee. PPLNS over the trailing 2 hours of difficulty-weighted shares.
  • 1 PRL minimum payout, K = 20 confirmations for maturity.
  • Server-side vardiff. Per-GPU telemetry. Open REST + WebSocket API.
  • One static Linux binary (~7 MB), one Docker image. (Windows: run the Docker image via Docker Desktop.)
02

Connect

Outbound TCP, TLS-wrapped JSON-RPC. The DNS name resolves to the nearest edge via anycast. No inbound ports.

endpoint
stratum+tls://stratum.oysterpool.com:4444

Quickstart on Linux + NVIDIA — replace prl1q…YOUR_WALLET:

install + run
curl -fSL https://oysterpool.com/install.sh \
  | bash -s -- prl1q...YOUR_WALLET rig-01

Docker, Windows, systemd, multi-GPU pinning, and static-difficulty overrides live on the Get started page.

03

Miner protocol

Line-delimited JSON-RPC 2.0 over TLS TCP. A connection lasts as long as the miner stays online. Method names are case-sensitive.

hello
miner → pool
{"jsonrpc":"2.0","id":1,"method":"hello","params":{
  "client":{
    "name":"oysterpool-miner","version":"0.1.0",
    "wallet":"prl1q...","worker":"rig-01",
    "gpus":[{"model":"H100 SXM","vram_gb":80,"sm":"sm_90"}]
  }
}}
response
{"jsonrpc":"2.0","id":1,"result":{
  "worker_id":123,
  "server_time":1780000000,
  "supported_shapes":["hopper-r1024","blackwell-r128","ada-r512", ...],
  "assigned_shape":"hopper-r1024",
  "initial_difficulty":64
}}
getMiningParams
miner → pool
{"jsonrpc":"2.0","id":2,"method":"getMiningParams","params":{}}
response
{"jsonrpc":"2.0","id":2,"result":{
  "shape_id":"hopper-r1024",
  "m":65536,"n":65536,"k":16384,"rank":1024,
  "rows_pattern":"dense","cols_pattern":"dense",
  "mma_type":"Int7xInt7ToInt32",
  "hash_tile_h":128,"hash_tile_w":256,"rounded_common_dim":16384,
  "difficulty":64
}}
getMiningInfo
miner → pool
{"jsonrpc":"2.0","id":3,"method":"getMiningInfo","params":{}}
response
{"jsonrpc":"2.0","id":3,"result":{
  "incomplete_header_bytes":"AAAAAB...",   // base64, 76 bytes
  "target":"4849...0000"                   // decimal, share-target
}}
submitPlainProof
miner → pool
{"jsonrpc":"2.0","id":4,"method":"submitPlainProof","params":{
  "plain_proof":"<base64>",
  "mining_job":{"incomplete_header_bytes":"<base64>","target":"<decimal>"}
}}
response
{"jsonrpc":"2.0","id":4,"result":"submitted"}
telemetry
miner → pool (every 10 s)
{"jsonrpc":"2.0","id":5,"method":"telemetry","params":{
  "hashrate_5s":7.4e9,"hashrate_1m":7.2e9,
  "accepted":421,"rejected":0,"uptime_s":13800,
  "miner_version":"0.1.0","shape_id":"hopper-r1024",
  "gpus":[{"idx":0,"model":"H100 SXM",
    "temp_c":67,"power_w":612,"fan_pct":72,"util_pct":99,
    "vram_used_mb":71400,"clock_mhz":1830,"throttle":null}]
}}
response
{"jsonrpc":"2.0","id":5,"result":"ok"}
event
pool → miner
// pushed when the pool retunes your difficulty (vardiff) or
// reassigns your shape after a chain advance:
{"jsonrpc":"2.0","method":"event","params":{
  "type":"set_difficulty",
  "difficulty":128
}}
04

REST API

Everything the dashboard reads is in the public API. No auth, no rate cap below 60 req/min/IP, JSON only. Versioned under /api/v1/.

EndpointReturns
GET /api/v1/pool/statsPool hashrate, network share, fee, last block.
GET /api/v1/pool/blocks?limit=50Recent blocks with reward + confirmations.
GET /api/v1/miner/{address}Per-address hashrate (5m / 1h / 24h), unpaid, paid, last block.
GET /api/v1/miner/{address}/workersPer-worker rows with reported + measured hashrate, GPU telemetry, miner version.
GET /api/v1/miner/{address}/paymentsPayment history (queued / sent / confirmed / failed, with tx id).
GET /api/v1/miner/{address}/found-blocksBlocks this address finished off (= got the network-hit share).
GET /api/v1/miner/{address}/advantageEarnings vs each competitor — fee-delta + benchmark scaling.
GET /api/v1/blocks/{height}/creditsPPLNS credit allocation per address for that block. Verifiable.
GET /api/v1/benchmarksLab benchmarks + live fleet medians per (gpu_model, miner_name).
GET /api/v1/compare?gpu=...&kwh_usd=0.10Expected PRL/day on each pool for that GPU at that power price.

OpenAPI JSON lives at /api/openapi.json.

05

WebSocket

Two streams: pool overview (one frame ~every 2 s) and per-address telemetry (one frame per worker push, ~every 10 s).

pool stats stream
wscat -c wss://api.oysterpool.com/ws/pool
// → {"hashrate_1h_hs":3.42e9,"network_share_pct":12.4,
//    "workers_online":1207,"blocks_24h":438,...}
per-address worker telemetry
wscat -c wss://api.oysterpool.com/ws/miner/prl1q...
// → {"worker_id":42,"hashrate_1m":7.2e9,
//    "gpus":[{"model":"H100 SXM","temp_c":67,"power_w":612,...}],
//    "observed_at":"..."}

Reconnect with exponential backoff. The dashboard ships with a small client at apps/web/src/lib/live.ts — copy it if you're building your own UI.

06

Economics

Pool fee
3.0 %
No dev cut. No surprise sub-percentages.
Payout scheme
PPLNS — 2 h window
Difficulty-weighted shares over the last 2 hours. Window itself is the variance cap.
Minimum payout
1 PRL
Confirmations
K = 20
Balance moves from balance_sats → mature_sats after 20 confirmations. Orphans rewind atomically.
Payout sweeper
every 10 min
On every tick: addresses whose (mature_sats − paid_sats) ≥ 1 PRL get a sendmany.

Each block's allocation is published at /api/v1/blocks/{height}/credits. Any miner can replay their share log and verify their cut.

07

Hardware

The miner auto-detects every supported card. The pool publishes one shape per GPU family — your miner is routed to the right one based on the GPU it declares in hello.

  • NVIDIA Volta → Blackwell + Hopper.
  • AMD MI300X / MI300A (preview, ROCm 6 backend).
  • Pre-Volta (GTX 10-series and older) is not supported — no tensor cores.
  • CPU mining is not supported — Pearl PoW needs MMA cores.

See the full grid + per-card recommended difficulty on the Get started page.

08

Operations

Is there a dev fee?

No. 3 % flat. We don't inject a hidden dev cut into the binary.

What happens during a chain reorg?

Oyster Pool watches every pending block for K = 20 confirmations. If a reorg invalidates a block, the matching pplns_credits rows are reversed from balance_sats in a single transaction. Already-mature credits are immutable, but we keep K high enough that this rarely triggers.

My measured hashrate doesn't match what my miner reports.

Both numbers are exposed on the dashboard. Measured is Σ difficulty × 2³² / window derived from accepted shares. Reported comes straight from the miner's 10-second telemetry frame. Some short-term divergence is normal; sustained divergence usually means rejected shares (network flakiness) or a stale fixed difficulty.

Vardiff isn't ratcheting fast enough on my rig.

Pin a static difficulty with --difficulty (or PEARL_DIFFICULTY=… in Docker). The dashboard's table on Get started lists per-card recommended values.

Where do my keys go?

Your wallet seed never leaves your wallet app. The pool only ever sees the bech32m P2TR address you provide. Payouts are sent to that address by the pool's hot wallet; no withdrawal flow, no balance you have to claim.

How do I report a bug?

Open an issue on GitHub or ping us on Discord. Real humans, fast replies.