v2.8 · RNG PRE-SUBMISSION PACKAGE v1.2

THE RAIN SDK v2.1 — SEVEN PACKAGES, TAKE WHAT YOU NEED

From “just the randomness” to “a whole casino or market in my product”. Each layer depends only on the one below it. Current version 2.1.0 (“lab-grade draws, Web2 latency”) — changelog.

NPM: READY, UNPUBLISHED — OWNER DECIDES SCOPESOURCE: sdk-v2 MIRROR BRANCH ON GITHUBRUNS IN PRODUCTION ON 2 DEPLOYMENTSPRE-AUDIT

npm status, exactly: npm pack --dry-run is clean for rng-core (24 files, 21.8 kB), rng-session (13, 20.8 kB), rng-node (34, 35.4 kB); @rain/* names are free (404) but the rain org's ownership can't be read anonymously — alternatives @rain-risk-markets/*, @rainriskmarkets/* verified free. Publishing is one command away and is the owner's decision (PUBLISHING). Until then: github.com/Quecko-Org/rain-playmarket-fe-dev · sdk-v2 ↗ (mirror branch; dedicated repo pending).

v1 shipped one package, @rain/risk-markets-sdk, with four modules (games · predictions · vaults · core). v2 splits it along the trust boundary so an integrator can adopt RAIN RNG alone without inheriting the casino. See the v1 → v2 changelog.

PACKAGEWHAT IT DOESWHO IT'S FORSTATUS
@rain/rng-coreThe formula and nothing else: outcome(), verifyRound(), chain-link check, typed inputs. Pure functions, zero I/O, zero dependencies beyond keccak. MIT + attribution.Anyone who wants to verify or reuse RAIN RNG — casinos, auditors, agent builders.LIVE (same code as the house nodes)
@rain/rng-sessionTwo-party session: hash-chain generation (default 65,536-deep since 2.1, WebCrypto secret, automatic rotation at 90 %), commit-reveal choreography, pipelining (prefetch(), maxInFlight), seed derivation from one wallet signature, EIP-712 signing helpers, snapshot/restore. Transport-agnostic.Products that run their own counterparty (house node, agent, matchmaking server).LIVE
@rain/rng-node NEW 2.1The house counterparty as a service: HTTP + WebSocket + long-poll transports, persist-before-reveal store (memory / Postgres), runtime KATs before first reveal and every 24 h (/selftest, /healthz.kat, 503 in error state), fingerprint self-check against lab/FINGERPRINTS.json, Dockerfile. This is what ran the real-network latency test.Operators hosting their own RNG node; labs (it is the unit under test).BUILT · lab-tested · not yet in a reference deployment
rng-py (rain_rng) NEW 2.1Pure-Python, stdlib-only mirror of rng-core: keccak-f[1600], the ceremony, HMAC_DRBG, ChaCha20, intBelow/shuffle. Byte-identical to the TypeScript on shared vectors (26 pytest). engine/rng.py drop-in.Python game servers and auditors who want a second implementation.BUILT · vectors cross-checked
@rain/channelsTyped client for ChannelManager V4 / ChannelManagerAA: open (EOA or ERC-1271 smart account with session key), act() dual-signed states, checkpoint, cooperativeClose, forceClose / challenge / finalize, reclaimStale, self-heal. Token-agnostic deployment registry with EIP-55 validation (v1 core).Operators running an instance; products that want on-chain-enforced settlement.LIVE
@rain/gamesRules engines that byte-mirror the on-chain verifiers: blackjack, roulette, baccarat, crash, dice, quick slots, Engine V2 slot runtime (KeccakRng), Craps, step games. IRulesVerifier scaffolding + differential-fuzz harness for new games.Game studios; white-label operators adding titles.LIVE (13 + 8 + Craps + Crash in production)
@rain/marketsPari-mutuel Outperform client (CryptoRace v1.1: enter, quote, claim, round state, oracle attestation decoding) + the unmodified rain-sdk-v2 passthrough for Rain prediction markets (v1 predictions). Calls labelled trustless vs api-backed.Trading firms, market builders, parametric-cover distributors.LIVE (Outperform) · LIVE via Rain markets

Trustless vs api-backed — labelled on every call. Channel opens/closes/disputes, every tx builder, every vault/bond/verifier read: trustless (direct contract, your RPC). Listings, order books, price feeds, profiles: api-backed (rain.one API, house node, or the Outperform keeper) — convenience reads, never settlement.

▸INSTALL

# npm: ready, unpublished (owner decides the scope) — until then clone the sdk-v2 branch and consume as a workspace/tarball dependency
#   git clone -b sdk-v2 https://github.com/Quecko-Org/rain-playmarket-fe-dev.git && npm ci && npm run build
npm i @rain/rng-core                       # just the formula + verifier + drbg()/intBelow/shuffle (2.1)
npm i @rain/rng-core @rain/rng-session     # run your own two-party sessions (pipelining, rotation)
npm i @rain/rng-node                       # host the counterparty (HTTP/WS, KATs, Postgres)
pip install ./packages/rng-py              # Python mirror (rain_rng)
npm i @rain/channels @rain/games           # open channels on Arbitrum + mirror the live games
npm i @rain/markets                        # Outperform + rain-sdk-v2 passthrough
# peer: ethers ^6

▸QUICKSTART — BY PERSONA

A · CASINO / AUDITOR — VERIFY A ROUND (rng-core)

import { outcome, verifyRound } from '@rain/rng-core';

const r   = outcome({ pRev, hRev, sessionSeed, channelId, k });   // uint256 — same keccak as the verifiers
const ok  = verifyRound({ pRev, hRev, sessionSeed, channelId, k, hAnchor, claimed: r }); // true ⇔ VERIFIED
console.log(r % 37n, ok);                                        // e.g. roulette number, and whether the house told the truth

B · AI-AGENT BUILDER — A FAIR COIN BETWEEN TWO MACHINES (rng-session)

import { RngSession } from '@rain/rng-session';

const me = await RngSession.create({ role: 'player', secret: crypto.getRandomValues(new Uint8Array(32)) });
const open = me.commit();                               // { seed, chainRoot } — send to the counterparty, receive theirs
me.open({ theirCommit: peer.commit, theirChainRoot: peer.chainRoot, channelId });   // fixes sessionSeed
const { myReveal } = me.nextReveal();                   // round k — send with your decision
const r = me.settle({ theirReveal });                   // verifies their chain link, returns uint256 r (throws on a bad reveal)

C · OPERATOR / PRODUCT — ONE CHANNEL, ALL GAMES (channels + games)

import { registerDeployment, ChannelSession } from '@rain/channels';
import { dice } from '@rain/games';

const PLAYMARKET = registerDeployment({ name: 'playmarket-usdttt', chainId: 42161,
  channelManager: '0x60743006c2a5Dd5b9907CA37e7381854ff860959', houseBond: '0x3D2d25373836C9d102E83f4200e87d087B29b998',
  token: '0x528F42C8560BBDa048690fB0982B07A9Ae52551A', tokenDecimals: 6,
  verifiers: { mux: '0xDf214594D021a36bD61aB398c20c4A14cDD0b48e', engineV2: '0x5d6048AB261e6151AB44fE6053e7AEb35Cb5C1B1' } });

const s = new ChannelSession({ deployment: PLAYMARKET, account: smartAccount /* ERC-1271 + session key */, wsUrl });
await s.open({ deposit: 100_000_000n });               // one tx (gas-sponsored on #2), channel Active + sessionSeed emitted
const { game, fairness } = await s.act('dice', dice.BET, { line: 50, stake: 1_000_000n });  // 1 RTT, dual-signed, verified locally
await s.close();                                       // CASH OUT ALL — one settle tx

D · TRADING FIRM — 5-MINUTE OUTPERFORM MARKETS (markets)

import { Outperform } from '@rain/markets';
const op = new Outperform({ chainId: 42161, address: '0x340991442B5BFCD80a46D709748be28b788414B7', signer });
const round = await op.current();                       // trustless read: coins, open prices, pool, lock time
const q = await op.quote({ coin: 'BNB', stake: 5_000_000n });     // shares @ current curve, dividend to earlier holders
await op.enter({ coin: 'BNB', stake: 5_000_000n });     // on-chain; settlement by keeper + house-signed oracle v1 (not provably fair — disclosed)

API names above are the v2 surface as built; signatures may still move before npm publication. Every example runs against the live Arbitrum One contracts listed on the front page.

▸TOKEN-AGNOSTIC DEPLOYMENT CONFIG

The protocol is token-agnostic by construction: ChannelManager takes the settlement token and vault as constructor parameters. Deployment #1 runs RUSD (0x260c7019E760763988843Bc5b873d749b5937469), deployment #2 runs USDTTT (0x528F42C8560BBDa048690fB0982B07A9Ae52551A) — both play-money. Register your own:

import { registerDeployment, RainVault } from "@rain/channels";

const acme = registerDeployment({
  name: "acme-usdc-arbitrum", chainId: 42161,
  token: "0x...USDC", tokenDecimals: 6,
  channelManager: "0x...", houseBond: "0x...",
  verifiers: { mux: "0x..." },
  rpcUrl: "https://arb1.arbitrum.io/rpc",
});
const limits = await new RainVault(acme).currentLimits(); // trustless: unitCap = float × 1733 ppm, bond/32, liquidity/8

Every address is EIP-55 checksum-validated on load — the repo has had two past checksum bugs, so validation is mandatory, not optional.

▸GAME-BUILDER GUIDE — THE IRulesVerifier CONTRACT

A game is three artifacts: an on-chain pure referee, a byte-identical client engine (in @rain/games), and house-node support.
interface IRulesVerifier {
    struct ChannelCtx { bytes32 channelId; bytes32 sessionSeed; bytes32 playerChainRoot; bytes32 houseChainRoot; }
    struct FinFields  { uint96 playerBal; uint96 houseBal; uint96 feeAccrued; uint96 lostGross; uint96 grossAtRisk; uint8 phase; }
    function verifyTransition(ChannelCtx calldata ctx, bytes calldata prevGame, bytes calldata nextGame,
                              uint8 action, bytes32[] calldata reveals)
        external view returns (bool valid, FinFields memory prevFin, FinFields memory nextFin);
    function finOf(bytes calldata game) external view returns (FinFields memory);
}
  • Pure and deterministic. No storage, no oracle, no block data — it's a fraud-proof court, not a game server.
  • Randomness only from reveals. r = keccak256(pRev, hRev, sessionSeed, channelId, k); for engine-driven games seed a deterministic engine with r and commit engineHash on-chain (Engine V2 pattern: 192 BET / 193 SETTLE in the mux).
  • Bet before randomness. BET dual-signs the wager with grossAtRisk = stake and a solvency lock (maxPayout − stake ≤ houseBal); SETTLE consumes exactly one reveal pair.
  • A legal transition must never be punishable. Differential-fuzz your Solidity against the TS mirror — proveBadTransition false positives are a critical bug.
  • Register through the mux. Action ranges: 0–31 blackjack · 32–63 roulette · 64–95 baccarat · 96–127 crash · 128–159 quick games · 160–191 step games · 192–223 Engine V2. GameMuxVerifier9 0xDf214594D021a36bD61aB398c20c4A14cDD0b48e is the live dispatcher on #2; dispatch isolation is tested.

Reality check: setVerifier is owner-gated and the house nodes are foundation-run. Third-party games are the designed path, not yet a permissionless one.

▸HOUSE-NODE OPERATOR PATH

  1. Bond. Deposit into HouseBond (#1 0x37E41E1d1EE2F96cE0203af06d639448547ade84 · #2 0x3D2d25373836C9d102E83f4200e87d087B29b998). Your bond caps the limits you can offer (table limit ≤ slashable/32). Withdrawals take 7 days and stay slashable while pending.
  2. Approval. Operator registration is governance-gated in v1 (single foundation-run node; HA/watchtower/HSM out of scope — accepted risks).
  3. Run the node. Write-ahead persistence before any countersignature, per-hand checkpoints, grace timers, house-reveals-first ordering. Liveness faults cost max(2× open gross, floor) to the player plus an equal burn — automatically, from your bond.

▸CHANGELOG — v1 → v2

v1 (@rain/risk-markets-sdk, Jul 2026)v2 (layered, Sep 2026 — playmarket era)
rain.core — deployment registry→ @rain/channels (registry + ChannelManagerAA / ERC-1271 smart-account open, session key as validation entity, gas sponsorship hooks)
rain.games — blackjack + roulette ChannelSession→ @rain/channels (ChannelSession.act(gameType, …) — one channel, all games) + @rain/games (13 table engines, dice/quick slots, Engine V2 runtime, Craps, Live Crash, step games)
randomness embedded in the channels client→ extracted as @rain/rng-core (pure) + @rain/rng-session (choreography); MIT + attribution; usable without the casino
rain.predictions — rain-sdk-v2 passthrough→ @rain/markets (+ Outperform pari-mutuel client, CryptoRace v1.1, oracle attestation decoding)
rain.vaults — limits derivation→ folded into @rain/channels (RainVault.currentLimits(), HouseBond views)
Pyth Entropy session seed (ChannelManager V3)→ oracle-free two-party session seed (V4 / AA, since v2.6.0) — SessionSeedCommitReveal event is the anchor
wallet popup per session open→ email login via smart accounts on #2: zero popups, zero gas
—+ white-label brand layer, wizard, self-serve portal, multi-brand back-office (/partners)

v2.0 → v2.1 (2026-09-13, “LAB-GRADE DRAWS, WEB2 LATENCY”)

  • drbg(r, gameId) in @rain/rng-core: one RAIN seed per spin → SP 800-90A HMAC_DRBG/SHA-256 (or ChaCha20) draw layer, intBelow rejection sampling + Fisher–Yates shuffle; never spans rounds.
  • Pipelining in @rain/rng-session (prefetch(), maxInFlight); default chain 65,536 with automatic rotation at 90 %.
  • New @rain/rng-node (house counterparty service with KATs, fingerprint check) and rng-py (Python mirror). No on-chain protocol change — outcome / gameSeed byte-identical to 2.0 and the Arbitrum verifiers.
  • Lab package lab/ — see the pre-submission package. Full text: CHANGELOG.

Site version banner: v2.8 (RNG package). Both deployments remain play-money and pre-audit.