01 · Overview
SOLAR is a permissionless, browser-native compute network. Idle GPU and CPU cycles on consumer devices are turned into a verifiable stream of work-units that clear against a fixed price ledger. Operators earn $0.12 USDC per verified job. Settlement is executed on the Robinhood Chain USDC contract with an off-chain batching layer that amortizes gas across cohorts of roughly 4,096 operators.
This document is the canonical protocol reference. It covers the runtime, the kernel format, attestation, the scheduler, payout mechanics, the JavaScript SDK, the RPC surface, the CLI, the operator handbook, and the security model. All numbers, constants, and code paths on this page are the same ones exercised by the reference client shipped in the @solar/runtime package.
Verified jobs / 24h
8.42M
Active operators
42,318
Median job latency
612 ms
Cohort settlement
every 900s
Pay per verified job
$0.12
Network hashrate
94.1 TF/s
02 · Architecture
The network is split into four planes: Operator (browser), Gateway(edge), Scheduler (control), and Settlement (ledger). Traffic between planes is authenticated with per-session Ed25519 keys derived from the operator's signed enrollment challenge. Nothing leaves the operator's device except kernel I/O tensors, telemetry counters, and receipts.
+----------------------+ wss (mTLS) +--------------------+
| Operator (browser) | <----------------> | Gateway (edge) |
| WebGPU + WASM | job frames | region-pinned |
+----------+-----------+ +---------+----------+
| |
| receipts | job assign
v v
+----------------------+ +--------------------+
| Settlement ledger | <---- receipts ---- | Scheduler |
| Robinhood Chain | | bandit + quorum |
+----------------------+ +--------------------+
Every job is dispatched to three independent operators. Their receipts are compared on the gateway with a Merkle equality check; a job is only marked "verified" and paid when at least 2 of 3 receipts match on the output root. Non-matching operators are silently downweighted by the scheduler's Thompson-sampling bandit.
03 · Runtime
The runtime is a 41 KB gzipped ES module that boots inside any Chromium-based browser (Chrome 121+, Edge 121+, Brave 1.63+, Arc 1.44+). It negotiates a WebGPU adapter, allocates a persistent command encoder, and opens a WebSocket to the nearest gateway region. There is nothing to install.
<script type="module">
import { Solar } from "https://cdn.solar.compute/runtime/0.9.14/solar.mjs";
const s = await Solar.connect({
wallet: "0x8f4e...", // linked EVM address
region: "auto", // iad1 / fra2 / sin1 / auto
kernels: ["sha256", "phash", "blur", "matmul"],
maxPower: 0.55, // 0..1, thermal cap
});
s.on("job", (j) => console.log("job", j.id, j.kernel));
s.on("clear", (r) => console.log("+ $0.12", r.jobId));
s.on("throttle", () => console.log("thermal throttle"));
await s.online();
</script>The runtime is single-threaded from the page's point of view. All heavy work runs inside a dedicated Worker that owns the WebGPU device; the page thread only ferries frames and paints UI. This is why the tab stays responsive at 100% job throughput.
04 · Kernels
A kernel is a signed WGSL program with a pinned input shape, output shape, and expected receipt format. Kernels are content-addressed by BLAKE3 and pre-audited; the runtime refuses to execute anything whose hash is not on the current allow-list published at gateway.solar.compute/.well-known/kernels.json.
@group(0) @binding(0) var<storage, read> input : array<u32>;
@group(0) @binding(1) var<storage, read_write> output : array<u32, 8>;
const K : array<u32, 64> = array<u32, 64>(
0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u,
0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
// ...
);
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
var w : array<u32, 64>;
// schedule + compress ...
}The current allow-list contains four kernels: sha256 (content hashing for indexing pipelines), phash (perceptual image hashing),blur (separable Gaussian, used for content-moderation pre-processing), and matmul (int8 general matrix multiply, 128x128 tiles). New kernels go through a 14 day audit window before being flipped on.
05 · Attestation
At enrollment the operator signs a nonce challenge with the linked EVM key. The signed nonce, the WebGPU adapter descriptor, the SHA-256 micro-benchmark result, and the runtime build hash are packed into an Attestation record and stored under the operator's device ID. Attestation is re-run silently every 6 hours or whenever the adapter changes.
{
"device": "d_9f31c0b2a4e7",
"wallet": "0x8f4e07c1a2b6d3f5e9c07d1a2b6d3f5e9c07d1a2",
"adapter": { "vendor": "apple", "arch": "apple-m3", "device": "M3 Pro" },
"bench": { "sha256": 812_453_120, "unit": "H/s" },
"runtime": "0.9.14-rc3",
"hash": "b3:8f4e07c1a2b6d3f5e9c07d1a2b6d3f5e9c07d1a2b6d3f5e9c07d1a2b6d3f5e9c",
"sig": "0x1c8f...",
"ts": 1737249120
}Receipts are much smaller. Each carries the job ID, the BLAKE3 root of the output tensor, the wall-clock duration, and an HMAC over the tuple keyed by the session key. Gateways discard receipts whose HMAC does not verify against the session key currently bound to the operator's device.
06 · Scheduler
The scheduler is a Thompson-sampling multi-armed bandit over operator cohorts. Each cohort of ~4,096 operators keeps a Beta(a, b) posterior on receipt agreement rate. Jobs are drawn from the pending queue and assigned to the top-3 sampled cohorts, then to the top-scoring operators inside those cohorts weighted by recent latency.
function sampleCohort(cohorts: Cohort[]): Cohort {
let best: Cohort | undefined;
let bestDraw = -Infinity;
for (const c of cohorts) {
const draw = betaSample(c.alpha, c.beta) * c.availability;
if (draw > bestDraw) { bestDraw = draw; best = c; }
}
return best!;
}Non-matching receipts do not slash. They decrement the cohort's alpha and increment its beta, which lowers the probability that the cohort is picked next round. Over time, dishonest or broken operators simply stop being scheduled.
07 · Payouts
Pay is fixed at $0.12 USDC per verified job. There is no bid, no auction, and no dynamic fee. Cleared receipts accumulate on the gateway's payout table. At the end of every 900-second cohort epoch the gateway posts a Merkle root of the cohort's payout table to the Robinhood Chain USDC settlement contract.
function claim(
uint256 epoch,
uint256 amount,
bytes32[] calldata proof
) external {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));
require(MerkleProof.verify(proof, roots[epoch], leaf), "bad proof");
require(!claimed[epoch][msg.sender], "already claimed");
claimed[epoch][msg.sender] = true;
USDC.transfer(msg.sender, amount);
emit Claimed(msg.sender, epoch, amount);
}Withdraw is available once the operator's balance clears $1.00 USDC. The runtime constructs the Merkle proof client-side from the epoch dump and submitsclaim(). There are no custodial funds: an operator's balance is always redeemable from the current epoch root without the gateway's cooperation.
08 · SDK
The @solar/runtime package exposes a small surface. All methods return promises; all events go through a strongly typed EventEmitter.
export interface ConnectOptions {
wallet: `0x${string}`;
region?: "auto" | "iad1" | "fra2" | "sin1";
kernels?: KernelId[];
maxPower?: number; // 0..1
}
export interface Session {
online(): Promise<void>;
offline(): Promise<void>;
status(): Promise<Status>;
balance(): Promise<number>;
withdraw(): Promise<TxReceipt>;
on<K extends keyof Events>(k: K, cb: (e: Events[K]) => void): void;
}
export declare namespace Solar {
function connect(opts: ConnectOptions): Promise<Session>;
}Every method that touches the wallet requires an active EIP-1193 provider. The runtime never stores private keys and never signs anything the operator has not explicitly approved through the wallet's own UI.
09 · RPC
The gateway speaks JSON-RPC 2.0 over WebSocket. Every message is size-prefixed and gzip-compressed. The full method table is short.
| Method | Direction | Purpose |
|---|---|---|
| session.hello | op → gw | handshake, returns session key |
| session.attest | op → gw | post attestation record |
| job.assign | gw → op | dispatch a job frame |
| job.receipt | op → gw | submit signed receipt |
| job.retract | gw → op | cancel an unstarted job |
| ledger.epoch | gw → op | post cohort epoch root |
| ledger.proof | op → gw | request merkle proof for balance |
| telemetry.tick | op → gw | 1 Hz counters (hash-rate, temp) |
{
"jsonrpc": "2.0",
"id": 1,
"method": "session.hello",
"params": {
"wallet": "0x8f4e07c1a2b6d3f5e9c07d1a2b6d3f5e9c07d1a2",
"runtime": "0.9.14-rc3",
"nonce": "0x9c2f...",
"sig": "0x1c8f..."
}
}10 · CLI
The CLI is a thin wrapper over the SDK, useful for running the runtime on a headless workstation via a bundled Chromium. Install once with npm, then drive from a shell.
$ npm i -g @solar/cli
$ solar login --wallet 0x8f4e07c1a2b6d3f5e9c07d1a2b6d3f5e9c07d1a2
$ solar start --region auto --kernels sha256,phash,matmul --power 0.55
[solar] gateway iad1 rtt 38ms
[solar] adapter apple-m3 22 CU 16 GB
[solar] attest b3:8f4e07... OK
[solar] job 8f2c sha256 612ms +$0.12 bal $0.36
[solar] job 3a91 matmul 740ms +$0.12 bal $0.48
[solar] epoch 41 root 0x7a4d... claimable $0.4811 · Operator handbook
You do not need to configure anything to get started. Open the site, press Beam in, complete the six-step enrollment, and the runtime will start receiving jobs. The operator handbook below documents the small number of things you might want to tune.
- Thermals. The runtime caps GPU utilization at 55% by default. Raise
maxPowerin the SDK or use--power 0.9in the CLI if your machine has active cooling. - Backgrounding. While the tab is hidden Chrome throttles WebGPU to about 8% of its foreground rate. Pin the SOLAR tab, or use the CLI which runs a persistent Chromium.
- Wake lock. The runtime holds a
screenwake lock while on call. If your OS still sleeps the display, jobs continue but the CPU may throttle. - Withdraw threshold. Balances below
$1.00 USDCcannot be claimed on-chain because the fixed portion of gas exceeds the payout. Balances accrue indefinitely. - One session per device. Attestation binds one active session to one device fingerprint. Opening a second tab silently takes over the first.
12 · Security model
SOLAR treats the operator's browser as untrusted, the gateway as semi-trusted, and the settlement contract as trusted. This is the same threat hierarchy used by most rollup-style protocols.
| Threat | Mitigation |
|---|---|
| Operator returns garbage output | 3-of-3 quorum + bandit downweighting |
| Operator replays another op's receipt | receipts HMAC'd with session key |
| Gateway forges a receipt | session key never leaves operator device |
| Gateway withholds payout | epoch root is public; claim() is permissionless |
| Kernel exfiltrates data | kernels are content-addressed and audited |
| Malicious extension injects into page | runtime lives in a same-origin Worker with a CSP |
| Wallet phishing | runtime never asks the wallet to sign a tx, only messages |
Full disclosures, audit reports (Zellic, 2025-04; Trail of Bits, 2025-08), and the bug-bounty scope are published at solar.compute/security. Please do not test on the live network; a devnet is available atdevnet.solar.compute.
13 · FAQ
Is this mining?
No. There is no proof-of-work coin. Operators run useful WebGPU compute (hashing, matmul, image transforms) dispatched by paying customers, and are settled in USDC.
Why $0.12 per job and not a variable rate?
Fixed pricing removes the auction attack surface and makes payouts trivially predictable. Customers pay a small margin above $0.12 that funds the gateway and settlement gas.
Does my computer stay usable?
Yes. The runtime caps GPU utilization and yields on every frame. Video calls, games, and design tools remain responsive; jobs run in the slack.
What data leaves my machine?
Only kernel input/output tensors for the job you are executing, 1 Hz telemetry counters, and signed receipts. No files, screen contents, keystrokes, or accounts.
Can I run this in a headless server?
Yes, with the CLI. It bundles a headless Chromium with WebGPU enabled via the Vulkan backend on Linux and the Metal backend on macOS.
What happens if I lose my wallet?
Your accrued balance is still claimable from any device that can produce a signature for the linked EVM address. There is no recovery path without that signature.
14 · Changelog
- scheduler: swap UCB1 for Thompson sampling, +6% verified throughput
- runtime: fix WebGPU adapter loss on Chrome 128 tab discard
- cli: bundle Chromium 128 with vulkan backend on Linux
- kernels: promote int8 matmul out of audit, +21% network capacity
- gateway: region fra2 added (Frankfurt)
- sdk: typed events for throttle and adapter-lost
- settlement: cohort epoch cut from 1800s to 900s
- attestation: adapter descriptor now bound to session key
- initial public devnet, sha256 and phash kernels only
Next
Ready to run a node?
Enrollment takes about 90 seconds. You will need a browser that supports WebGPU and an EVM wallet with a Robinhood Chain address.
Beam in