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.
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.)
Connect
Outbound WebSocket Secure to the public stratum path. Cloudflare terminates TLS and forwards to the current pool core. No inbound ports.
wss://api.oysterpool.com/stratumQuickstart on Linux + NVIDIA — replace prl1p…YOUR_WALLET:
curl -fSL https://oysterpool.com/install.sh \
| bash -s -- prl1p...YOUR_WALLET rig-01Docker, Windows, systemd, multi-GPU pinning, and static-difficulty overrides live on the Get started page.
Miner protocol
JSON-RPC envelopes over WSS text frames. A connection lasts as long as the miner stays online. Method names are case-sensitive.
{"id":null,"method":"pearl.challenge","params":{
"seed":"<32-byte hex>",
"difficulty":1
}}{"id":1,"method":"pearl.challenge_response","params":{
"seed":"<same seed>",
"nonce":"0000000000000001"
}}{"id":1,"result":true,"error":null}{"id":2,"method":"mining.configure","params":[["pearl/v1"],{}]}
{"id":3,"method":"mining.subscribe","params":["prl-miner/oysterpool;profile=h100;shape=hopper-r1024"]}{"id":2,"result":{"pearl/v1":true},"error":null}
{"id":3,"result":[null,null,4],"error":null}{"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
}]}{"id":4,"method":"mining.authorize","params":[
"prl1p...YOUR_WALLET.rig-01",
"x"
]}{"id":4,"result":true,"error":null}{"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
]}{"id":5,"method":"mining.submit","params":[
"prl1p...YOUR_WALLET.rig-01",
"job-id",
"<plain_proof_base64>"
]}{"id":5,"result":true,"error":null}{"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
}]
}}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/.
| Endpoint | Returns |
|---|---|
| GET /api/v1/pool/stats | Pool hashrate, network share, fee, last block. |
| GET /api/v1/pool/blocks?limit=50 | Recent blocks with reward + confirmations. |
| GET /api/v1/miner/{address} | Per-address hashrate (5m / 1h / 24h), unpaid, paid, last block. |
| GET /api/v1/miner/{address}/workers | Per-worker rows with measured + reported hashrate, GPU telemetry, miner version. |
| GET /api/v1/miner/{address}/payments | Payment history (queued / sent / confirmed / failed, with tx id). |
| GET /api/v1/miner/{address}/found-blocks | Blocks this address finished off (= got the network-hit share). |
| GET /api/v1/miner/{address}/advantage | Earnings vs each competitor — fee-delta + benchmark scaling. |
| GET /api/v1/blocks/{height}/credits | PPLNS credit allocation per address for that block. Verifiable. |
| GET /api/v1/benchmarks | Published lab benchmarks per (gpu_model, miner_name). |
| GET /api/v1/compare?gpu=...&kwh_usd=0.10 | Expected PRL/day on each pool for that GPU at that power price. |
OpenAPI JSON lives at /api/openapi.json.
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.
wscat -c wss://api.oysterpool.com/ws/pool
// → {"hashrate_1h_hs":0.0,"network_share_pct":0.0,
// "workers_online":0,"blocks_24h":0,...}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.
Economics
Each block's allocation is published at /api/v1/blocks/{height}/credits. Any miner can replay their share log and verify their cut.
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.
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.