Protocol

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

System

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.

Client

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.

index.htmlhtml
<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.

WGSL

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.

kernels/sha256.wgsl (excerpt)wgsl
@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.

Trust

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.

attestation.record.jsonjson
{
  "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.

Control

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.

scheduler/sample.tsts
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.

Ledger

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.

contracts/SolarPayout.sol (excerpt)solidity
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.

JavaScript

08 · SDK

The @solar/runtime package exposes a small surface. All methods return promises; all events go through a strongly typed EventEmitter.

node_modules/@solar/runtime/index.d.tsts
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.

Gateway

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.

MethodDirectionPurpose
session.helloop → gwhandshake, returns session key
session.attestop → gwpost attestation record
job.assigngw → opdispatch a job frame
job.receiptop → gwsubmit signed receipt
job.retractgw → opcancel an unstarted job
ledger.epochgw → oppost cohort epoch root
ledger.proofop → gwrequest merkle proof for balance
telemetry.tickop → gw1 Hz counters (hash-rate, temp)
session.hello.requestjson
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.hello",
  "params": {
    "wallet":  "0x8f4e07c1a2b6d3f5e9c07d1a2b6d3f5e9c07d1a2",
    "runtime": "0.9.14-rc3",
    "nonce":   "0x9c2f...",
    "sig":     "0x1c8f..."
  }
}
Terminal

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.

terminalbash
$ 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.48
Guide

11 · 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 maxPower in the SDK or use --power 0.9 in 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 screen wake lock while on call. If your OS still sleeps the display, jobs continue but the CPU may throttle.
  • Withdraw threshold. Balances below $1.00 USDC cannot 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.
Threat

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.

ThreatMitigation
Operator returns garbage output3-of-3 quorum + bandit downweighting
Operator replays another op's receiptreceipts HMAC'd with session key
Gateway forges a receiptsession key never leaves operator device
Gateway withholds payoutepoch root is public; claim() is permissionless
Kernel exfiltrates datakernels are content-addressed and audited
Malicious extension injects into pageruntime lives in a same-origin Worker with a CSP
Wallet phishingruntime 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.

Common

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.

Releases

14 · Changelog

0.9.14-rc32026-07-18
  • 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
0.9.132026-06-02
  • kernels: promote int8 matmul out of audit, +21% network capacity
  • gateway: region fra2 added (Frankfurt)
  • sdk: typed events for throttle and adapter-lost
0.9.122026-04-14
  • settlement: cohort epoch cut from 1800s to 900s
  • attestation: adapter descriptor now bound to session key
0.9.112026-03-01
  • 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