Reference

Oyster Pool docs

Everything you need to mine, query, or audit Oyster Pool. The miner stratum 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 work-weighted shares.
  • 1 PRL minimum payout, K = 20 confirmations for maturity.
  • Server-side vardiff. Per-GPU telemetry. Open REST + WebSocket API.
  • One CUDA-enabled Linux miner bundle, one Docker image. (Windows: run the Docker image via Docker Desktop.)
02

Connect

Outbound WebSocket Secure to the public stratum path. Cloudflare terminates TLS and forwards to the current pool core. No inbound ports.

endpoint
wss://api.oysterpool.com/stratum

Quickstart on Linux + NVIDIA — replace prl1p…YOUR_WALLET:

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

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

03

Miner protocol

JSON-RPC envelopes over WSS text frames. A connection lasts as long as the miner stays online. Method names are case-sensitive.

pearl.challenge
pool → miner
{"id":null,"method":"pearl.challenge","params":{
  "seed":"<32-byte hex>",
  "difficulty":1
}}
pearl.challenge_response
miner → pool
{"id":1,"method":"pearl.challenge_response","params":{
  "seed":"<same seed>",
  "nonce":"0000000000000001"
}}
response
{"id":1,"result":true,"error":null}
mining.configure / mining.subscribe
miner → pool
{"id":2,"method":"mining.configure","params":[["pearl/v1"],{}]}
{"id":3,"method":"mining.subscribe","params":["prl-miner/oysterpool;profile=h100;shape=hopper-r1024"]}
response
{"id":2,"result":{"pearl/v1":true},"error":null}
{"id":3,"result":[null,null,4],"error":null}
pearl.set_mining_params
pool → miner
{"id":null,"method":"pearl.set_mining_params","params":[{
  "shape_id":"hopper-r1024",
  "m":65536,"n":65536,"k":16384,"rank":1024,
  "rows_pattern":[0,32],
  "cols_pattern":[0,1,2,...,63],
  "mma_type":"Int7xInt7ToInt32",
  "difficulty_adjustment_factor":2097152
}]}
mining.authorize
miner → pool
{"id":4,"method":"mining.authorize","params":[
  "prl1p...YOUR_WALLET.rig-01",
  "x"
]}
response
{"id":4,"result":true,"error":null}
mining.set_difficulty / mining.notify
pool → miner
{"id":null,"method":"mining.set_difficulty","params":[1048576]}
{"id":null,"method":"mining.notify","params":[
  "job-id",
  "<prev_hash_hex>",
  "<incomplete_header_hex>",
  65266,
  "665a1f00",
  "1d00ffff",
  true
]}
mining.submit
miner → pool
{"id":5,"method":"mining.submit","params":[
  "prl1p...YOUR_WALLET.rig-01",
  "job-id",
  "<plain_proof_base64>"
]}
response
{"id":5,"result":true,"error":null}
telemetry
miner → pool notification, every ~10 s
{"method":"telemetry","params":{
  "hashrate_5s":4.1e11,
  "hashrate_1m":4.0e11,
  "accepted":12,
  "rejected":0,
  "uptime_s":600,
  "miner_version":"prl-miner/oysterpool",
  "shape_id":"blackwell-r512-49x32",
  "gpus":[{
    "idx":0,
    "model":"RTX 5090",
    "temp_c":67,
    "power_w":475,
    "fan_pct":72,
    "util_pct":99,
    "vram_used_mb":24576,
    "clock_mhz":2500,
    "hashrate_hs":4.0e11,
    "throttle":null
  }]
}}
04

REST API

Everything the dashboard reads is in the public API. No auth; token bucket rate limits apply (about 30 req/s per IP with burst 60). 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 measured + reported 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/benchmarksPublished lab benchmarks 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 roughly every 2 s) and per-address telemetry frames whenever the miner publishes its default ~10-second report.

pool stats stream
wscat -c wss://api.oysterpool.com/ws/pool
// → {"hashrate_1h_hs":0.0,"network_share_pct":0.0,
//    "workers_online":0,"blocks_24h":0,...}
per-address worker telemetry
wscat -c wss://api.oysterpool.com/ws/miner/prl1p...
// → {"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
Work-weighted shares over the last 2 hours. Window itself is the variance cap.
Minimum payout
1 PRL
Confirmations
K = 20
balance_sats tracks live credited blocks; mature_sats unlocks 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 advertises its supported GPU profile during subscribe. The pool publishes one shape per GPU family and routes the connection from that user-agent metadata.

  • NVIDIA Ampere RTX 30-series, Ada RTX 40-series, Hopper H100/H200, and Blackwell RTX 50-series.
  • Data-center Ampere sm80 and Blackwell B-series require separate miner artifacts and are not advertised by the public installer.
  • AMD/ROCm mining is not shipped in the public miner bundle.
  • 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 pending and confirmed blocks for rollbacks. If a reorg invalidates a block, the matching pplns_credits rows are deleted and the credited amount is subtracted from balance_sats. If the block had already matured, mature_sats is reversed too. If an already-paid block is orphaned, paid_sats remains as the on-chain fact and future credits first repay the negative owed balance before another payout is sent.

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 from the miner telemetry stream. 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 --password "x;d=VALUE" (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.