# STOX Perps — Security Review

**Scope:** the on-chain protocol deployed on Robinhood Chain (chainId 4663).
**Source:** verified bytecode on Blockscout, recovered 2026‑10‑22 (byte-identical to mainnet). solc 0.8.26, optimizer runs 200, viaIR=true. Libraries: OpenZeppelin `Ownable2Step`, `ReentrancyGuard`, `ECDSA`, `EIP712`, `SafeERC20`.
**Contracts reviewed:** `Exchange`, `PriceRelay`, `SessionRouter`, `HouseShare`, `Staking`, `Reserve`, `Treasury`.
**Nature of this document:** an internal/automated code review, *not* a certified third‑party audit. It is a best‑effort read of the source; it is not a guarantee of safety and does not replace a paid external audit.

---

## 1. Addresses

| Contract | Address |
|---|---|
| Exchange v2 (holds the pool) | `0xC8017e08CB5a8948D9cc9DED6D90f85bD813C382` |
| PriceRelay (oracle) | `0xb6ee07Ab358f6223F3b56a764De49FB52DC96F9b` |
| SessionRouter (1‑click) | `0x8E7a8139a7602ac99b6BCf6e089463D4E696B4Ec` |
| HouseShare | `0x49dc3eBD3C5E380810D579f7db6a9eA45991DF89` |
| Staking | `0xb85Ba9dD979A54256a9001Dcb0A7dC948Ba72853` |
| Reserve | `0x063B8f140E3682D453876Ef240257E53582fF135` |
| Treasury | `0xDcd51A79339F194001EB8ef9Cdc21911810d4Fe2` |
| Collateral (USDG) | `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168` |
| STOX | `0xb4d3a6097b765d094c0950ac03e917a2773eef4d` |

All contracts verified on Blockscout — anyone can read the exact source.

---

## 2. Architecture

Synthetic perps on RWA/equity markets, all settled against one shared USDG pool ("the House"). Prices are quorum‑signed HIP‑3 (Hyperliquid trade.xyz) marks posted per 5s grid by `PriceRelay`. Losses fund the pool and mint non‑transferable `HouseShare` to the loser; half of fees + pool overflow above the soft cap stream to shareholders, the other half funds STOX buybacks. One‑click trading via `SessionRouter` (session keys, relayer pays gas). Not upgradeable.

---

## 3. Custody & withdrawal paths (the money question)

Confirmed by reading every balance mutation:

- **Exchange `pool`** changes in exactly 4 places (`Exchange.sol` L561/593/596/627): pay a winner, take a loss, overflow→shareholders, hold a fee. **There is no function — owner, guardian, or otherwise — that transfers pool principal to a chosen address.** `fundPool` only adds. User free balances leave only via `withdraw()` to `msg.sender`.
- **Reserve** can only `pull` to the Exchange (`msg.sender == exchange`); `redeemEth`/`swapEth` can only *increase* its USDG. Owner cannot withdraw.
- **Treasury** ETH leaves only through permissionless `distribute()` along a fixed waterfall. Owner cannot withdraw.
- **Staking** holds users' STOX; `withdraw()` pays `msg.sender` after cooldown (early‑exit penalty → treasury). No owner path to user stakes.
- **HouseShare** is non‑transferable and has no principal‑redemption; holders `claim()` only their pro‑rata reward streams.

**Finding: there is no custodial backdoor.** This is the protocol's strongest property and it is verifiable on‑chain.

---

## 4. Findings

### H‑1 (High, centralization/trust) — Oracle quorum can move the mark
`PriceRelay.post` accepts a price if `threshold` relayer signatures agree, mark vs. oracle are within `maxDevBps`, and a Chainlink breaker (`breakerBps`, default now 300bps) does not trip while fresh. **Both `mark` and `oracle` originate from the same Hyperliquid source**, so layer‑1 (mark/oracle self‑consistency) does *not* defend against a colluding/compromised quorum that fabricates both consistently. The only external check is the Chainlink Robinhood feed, and only while it is fresh (`breakerMaxAge`, 1h). A quorum (2‑of‑3) that posts a price up to `breakerBps` away from Chainlink could let a self‑dealt position win and drain the pool within that band; if the Chainlink feed is stale, even that check is off.
**Mitigations present:** per‑position notional cap that shrinks with leverage, per‑side OI caps, winner haircut, payout capped at `pool`, deadband, freeze. These bound the per‑block damage but do not remove the trust in the relayer set.
**Recommendation:** independent price source for the breaker (not HL‑derived); lower `breakerMaxAge`; raise `threshold`/signer diversity; publish the relayer set.

### H‑2 (High, centralization) — Owner risk params are not timelocked on‑chain
The NatSpec says "owner changes risk params behind an external timelock," but no timelock is enforced in the contracts. The owner can, in one tx, change `feeBps`, `softCap`, `maxLeverage`, `m0`, etc. Lowering `softCap` forces pool overflow out to shareholders pro‑rata (not to an arbitrary address, so not a drain, but still a unilateral economic lever).
**Recommendation:** move ownership to a timelock + multisig. *(Note: on this deployment the owner key has since been lost, which neutralizes this in practice but also means no parameter can ever be fixed.)*

### M‑1 (Medium) — Winner liquidity is not guaranteed
By design, a win the pool can't cover goes to a FIFO queue, paid from later losses or the Reserve after `reserveDelay` (6h). If losses and Reserve are insufficient, winners can wait indefinitely. This is disclosed (synthetic, haircut model) but is a real solvency/liquidity characteristic users should understand.

### M‑2 (Medium) — `instant` fills trust a recent grid
`requestOpenInstant`/`requestCloseInstant` fill at the latest posted grid up to `instantMaxAge` (≤60s, default 15s) old. Combined with relayer control of posting timing, this is a latency/selection surface. Low exploitability given 5s grids and caps, but non‑zero.

### L‑1 (Low) — Unbounded arrays
`positions`/`requests` grow forever (`delete` only zeroes slots). No security impact; off‑chain indexers and `positionsLength` loops must paginate (the web client already does).

### L‑2 (Low) — `grantCredit` fairness
Owner/`creditGranter` can grant `mintCredit` that multiplies a future loss‑mint up to `creditMultiplier` (≤10x). It cannot extract funds, but it can dilute other shareholders' share of future reward streams if misused.

### L‑3 (Low) — `SessionRouter` sequential nonce in `batch`
Nonces are strictly sequential and shared across registrations and intents; a failed/misordered entry in a batch blocks later ones for that user. UX, not security. Scope of a compromised session key is correctly limited to open/close (never deposit/withdraw) until expiry (≤30d) or revocation.

### Informational
- No reentrancy exposure found: `ReentrancyGuard` on all external state‑changing entry points; SafeERC20 throughout; effects‑before‑interactions in settlement.
- Quorum signatures must be strictly ascending by signer address → uniqueness enforced. Good.
- Not upgradeable → no proxy‑admin risk, but bugs are permanent (no fix path).
- Guardian can only *freeze*/pause; only owner can unfreeze/unpause. Correct least‑privilege split.

---

## 5. Current operational state (disclosure)

As of this review the project is winding down: the front‑end was taken offline and the deployer/owner private key was lost in a local deletion (only relayer and dividend keys survive as Fly secrets). Consequence: no owner action is possible (no pause, param change, or migration), but the contracts continue to run as deployed and users retain full self‑custody — `withdraw()`, staking `withdraw()` after cooldown, and HouseShare `claim()` all work directly against the verified contracts without the website.

---

## 6. Summary

| ID | Severity | Area | Status |
|---|---|---|---|
| H‑1 | High (trust) | Oracle quorum can move the mark within the Chainlink band | Mitigated by caps/haircut/breaker; inherent to design |
| H‑2 | High (trust) | Owner risk params not timelocked | Neutralized on this deployment (owner key lost) |
| M‑1 | Medium | Winner liquidity not guaranteed | By design, disclosed |
| M‑2 | Medium | `instant` grid selection surface | Bounded by caps |
| L‑1..L‑3 | Low | Array growth, credit fairness, batch nonce | No fund risk |

**Bottom line:** custody is sound — no contract has an owner‑drain path, and user funds are self‑custodial and withdrawable directly on‑chain. The principal risk is *trust in the relayer/oracle set* (H‑1), partially bounded by the Chainlink breaker and position/OI caps. This is an internal review, not a certified audit.
