AUDIT PACKAGE v4.1.0

πŸ›‘ RAIN CHANNELS β€” AUDIT PACKAGE

Everything an external security auditor needs, in one place: contracts in scope with verified source, system architecture, the invariants to try to break, the threat model, test & coverage summary, known incidents, and accepted risks. Prepared honestly β€” including the gaps.

⚠ PRE-AUDIT β€” NOT YET EXTERNALLY AUDITED SOURCIFY EXACT-MATCH VERIFIED FORGE 140/140 Β· INTEGRATION 24/24 DEMO STAKES (RUSD PLAY-MONEY)
1 Β· SCOPE 2 Β· ARCHITECTURE 3 Β· ADDRESSES 4 Β· INVARIANTS 5 Β· THREAT MODEL 6 Β· TESTS 7 Β· INCIDENTS 8 Β· ACCEPTED RISKS 9 Β· READINESS 10 Β· DOCUMENTS

1CONTRACTS IN SCOPE

Solidity 0.8.24 Β· Foundry Β· via_ir=true Β· ~1,470 raw lines (~1,100 SLoC) Β· protocol/src/channels/
CONTRACTSLOCSTATUSSOURCIFY
ChannelManager.sol (V3) β€” simulator-parity limits, incl. reclaimStale635ACTIVEexact_match βœ…
ChannelManager.sol (V2)635RETIREDexact_match βœ…
ChannelManager.sol (V1, commit e7da239)601RETIRED / DRAINEDexact_match βœ…
HouseBond.sol116ACTIVEexact_match βœ…
BlackjackRulesVerifier.sol330ACTIVEexact_match βœ…
RouletteRulesVerifier.sol β€” European roulette channel rules (13 bet types, exact casino payouts, solvency check)296ACTIVEexact_match βœ…
GameMuxVerifier.sol β€” action-range dispatcher (0–31 blackjack, 32–63 roulette); manager's active verifier45ACTIVEexact_match βœ…
IRulesVerifier.sol (interface)51IN SCOPEβ€”
MockEntropyLocal.sol (test-only)27OUT OF SCOPEβ€”

External dependencies: OpenZeppelin (SafeERC20, ReentrancyGuard, Ownable), Pyth Entropy (provider callback), RUSD ERC-20 (6 decimals, standard).

Off-chain components (threat-model context, not in on-chain scope): services/house-node/ (TS house node: WAL, checkpointing, grace timers, reconciliation, recover_close) and app/channels-sdk.js (browser SDK: session keys, hash chains, EIP-712 signing, snapshot/restore persistence).

2SYSTEM SUMMARY

FunFair-style state channels for casino games

Player deposits RUSD; the operator allocates house float. Hands are played off-chain via dual-signed EIP-712 ChannelStates (domain "RAIN ChannelManager" v1). Randomness = mutual commit-reveal hash chains (N=4096) + a Pyth Entropy session seed mixed per card: card_k = keccak(pRev_k, hRev_k, sessionSeed, channelId, k) % 52, house-reveals-first ordering.

On-chain surface: open (entropy seed request) Β· checkpoint (nonce floor) Β· cooperative close Β· forced close + challenge window + finalize Β· reveal verification (submitReveals/demandReveal) Β· fraud proof (proveBadTransition) Β· stale-channel recovery (reclaimStale, V2 only, 30-day) Β· fee waterfall at close (1.25% of lost gross β†’ burn 4000 / rebate 1700 / standby 500 / residual 6300 ppm).

Key parameters: 180s player grace β†’ forfeit of open hand's gross Β· house fault β†’ hand void + comp max(2Γ— gross, 5 RUSD) from HouseBond + equal penalty burned Β· tiered challenge windows (≀10,000 RUSD β†’ 10 min; above β†’ 24 h) Β· exposure caps (Ξ£ allocations ≀ 2% vault float, single ≀ 0.25%, 8Γ—maxUnitStake ≀ allocation) Β· HouseBond 7-day withdrawal delay, pending withdrawals remain slashable Β· funds always pay out to playerOwner wallet, never session keys.

3DEPLOYED ADDRESSES β€” ARBITRUM ONE (42161)

All active contracts verified on Sourcify (exact_match); links open Arbiscan
ChannelManager V3 (active)0xe13DC056111906aA4d3659880EBDC67138c76DA7
ChannelManager V2 (retired)0xacbfCf3523DDA59419a181Afb2e17A80BE453fEb
ChannelManager V1 (retired)0x82698e4C14DC5D144bdA2a028aDe60d886681AFb
HouseBond (2Γ—100k RUSD bonds)0x37E41E1d1EE2F96cE0203af06d639448547ade84
BlackjackRulesVerifier0xFdcCE2DE2F8A28cBBdBaB01131C3bab138Eb9293
RouletteRulesVerifier0x5239969ff32e5733F319d3e80eD64D19adF4962f
GameMuxVerifier (manager.verifier)0x14155583112F87777B95AB0EA76786bf079c6A83
Blackjack V3 (Pyth fallback)0x2E7747E9c4c18511A4F9e79C6bD38061e1443F7A
RUSD token (demo, 6 dec)0x260c7019E760763988843Bc5b873d749b5937469
Pyth Entropy0x7698E925FfC29655576D0b361D75Af579e20AdAc

House node: wss://api.rainsandbox.xyz Β· health: api.rainsandbox.xyz/health Β· Arbiscan API verification pending (no API key); Sourcify metadata renders on Arbiscan/Blockscout regardless.

4KEY INVARIANTS β€” WHAT TO TRY TO BREAK

The 10 properties the audit should attack. Breaking any one is a valid finding.
I1 Β· CONSERVATIONFor any settling state: playerBal + houseBal + feeAccrued + grossAtRisk == deposit + allocation. No path may mint or destroy escrowed RUSD.
I2 Β· NONCE MONOTONICITYA checkpointed nonce is a hard floor β€” no close (cooperative/forced/final) may settle on a lower nonce; a challenge must strictly increase the closing nonce.
I3 Β· DUAL SIGNATURE INTEGRITYEvery settlement-bearing state requires valid player-session AND house-session signatures bound to the channel's registered keys, chainId, and verifying contract. No cross-channel or cross-chain replay (fuzz-tested).
I4 Β· FUNDS DESTINATIONSPlayer payouts only to playerOwner (never session keys); house payouts only to operator; fee waterfall split is exact and applied exactly once.
I5 Β· RECLAIMSTALE CONSERVATISM (V2)Only after β‰₯30 days of zero on-chain activity; settles at the last on-chain checkpoint (or opening balances); never better for the caller than the last anchored state; permissionless; cannot grief an active channel (any on-chain touch resets the clock).
I6 Β· FORFEIT / FAULT PATHSPlayer-forfeit only after grace, and only the open hand's gross; house-fault pays void + comp max(2Γ— gross, 5 RUSD) from HouseBond + equal penalty burned β€” never from other channels' escrow.
I7 Β· HOUSEBOND7-day withdrawal delay; pending withdrawals remain slashable; slash pays compensation before burn when underfunded; only the manager may slash; setManager only owner.
I8 Β· ENTROPYOnly the Pyth Entropy contract may invoke _entropyCallback; voidOpen full-refund only in SeedPending after 1h; exposure caps enforced at open.
I9 Β· REENTRANCYAll fund-moving functions are nonReentrant; RUSD is standard but assume-hostile analysis welcome.
I10 Β· RULES VERIFIERproveBadTransition accepts only a dual-signed prev and an accused-signed illegal next; a legal transition must never be punishable; card derivation must be unbiased given one honest party.

5THREAT MODEL

Adversaries and the mitigations they must defeat

😈 MALICIOUS PLAYER

  • Stale-state forceClose β†’ challenge window + checkpoint floor
  • Mid-hand stall β†’ 180s grace β†’ forfeit of open gross
  • Fake reveals β†’ on-chain hash-chain verification
  • Session-key theft β†’ irrelevant: funds only pay to playerOwner

🏠 MALICIOUS OPERATOR / HOUSE

  • Stale-state close β†’ player challenge
  • Withholding reveals β†’ demandReveal escalation
  • Refusing to countersign β†’ player forceClose from last dual-signed state
  • Node death β†’ V2 reclaimStale after 30d guarantees escrow release

πŸ‘₯ THIRD PARTIES

  • Griefing via permissionless functions (finalizeClose, reclaimStale, submitReveals) β†’ must not worsen an honest party's outcome

🌐 INFRASTRUCTURE

  • Arbitrum sequencer outage vs challenge windows β†’ tiered 10 min / 24 h β€” accepted risk at demo stakes
  • Pyth Entropy liveness β†’ voidOpen full refund after 1h

6TEST & COVERAGE SUMMARY

Test-to-code ratio β‰ˆ 1.9:1 by lines
140/140
FORGE (UNIT + FUZZ)
24/24
INTEGRATION (ANVIL E2E)
βœ…
MAINNET E2E + DISPUTE DRILL
N/A
FORGE COVERAGE % (TOOLING)

7INCIDENT LOG

Full disclosure β€” what broke, what it cost, how it was fixed. Details in DEPLOYMENT.md.
βœ… Abandoned-escrow recovery (v4.0.1)

v4.0.0 kept session material in memory only β€” page refresh abandoned open channels. 4 channels (2,400 RUSD) recovered via operator cooperativeClose from WAL states. Fix: localStorage snapshot/restore, auto-resume, recover_close, 30-min reconciliation sweep.

⚠ Stuck V1 channel 0xdd64aa43… β€” 2,500 RUSD locked permanently

Opened mid-maintenance; WAL wiped by redeploys, no dual-signed state on either side. V1 has no recovery path by design (re-audited: all settle paths need dual signatures). Player's 500 RUSD deposit refunded from treasury; 2,000 RUSD house allocation written off. This failure mode is exactly why V2's reclaimStale exists.

βœ… House-node durability (v4.1.0)

Bar: a redeploy mid-session must never destroy the only copy of a signed state. Three layers now: per-hand on-chain checkpoints (~130k gas, default ON), checkpoint-on-disconnect, SIGTERM flush β€” plus client snapshots and reclaimStale as the durable floor.

8ACCEPTED RISKS & KNOWN LIMITATIONS

Auditors: please do not re-report these β€” they are known and accepted for v1 / demo stakes

9AUDIT-READINESS CHECKLIST

Where the package stands today

10AUDIT DOCUMENTS

The full package β€” download and hand to the auditor

Contact for audit engagement: open a channel via the dApp or the operator address above. Suggested firms & budget rationale are in spec Β§7.3.

RAIN RISK MARKETS Β· AUDIT PACKAGE v4.1.0 Β· 2026-07-28 Β· PREPARED PRE-AUDIT β€” HONEST GAPS INCLUDED