# Security & Trust Model

Stockpot's security posture is **audited code first, disclosed trust
everywhere else**: the contract holding principal is a near-byte-faithful
fork of PoolTogether V5's audited PrizeVault (with PT's TwabController and
TwabRewards adopted unmodified), the draw engine's trust model is honest and
verifiable, and everything tightens as infrastructure (onchain VRF, audit)
arrives.

:::danger
**Stockpot's own deployment has not been audited.** The PrizeVault forks
audited PoolTogether V5 code with minimal, documented deltas — but the fork,
the DrawManager, and the composition are Stockpot's responsibility, not
covered by PT's audits. Regulatory review is likewise deferred. Do not
deposit more than you can afford to lose. Total deposits are capped at $1M,
enforced onchain.
:::

## What is audited, what is not

| Layer | Provenance | Audit status |
|---|---|---|
| PrizeVault accounting (1:1 shares, dust collection, yield buffer, loss handling) | PT v5 fork, byte-identical accounting | Audited upstream (C4 2024, Macro) |
| TwabController, TwabERC20, TwabRewards | PT v5, unmodified, pinned | Audited upstream |
| PrizeVault deltas (cap, sweep, role rewiring, Ownable2Step) | Stockpot, marked in source, diffable | **Not audited** |
| DrawManager, BoostStaking, PrizeBuyer | Stockpot | **Not audited** |
| DiceEntropy oracle | Third party (Pyth Entropy fork) | Self-audited only (disclosed) |
| Steakhouse USDG vault (yield source) | Morpho/Steakhouse, $226M TVL, used by Robinhood Earn | Independent of Stockpot; curator-managed parameters |

## The vault: what cannot happen

* **Principal cannot fund prizes.** The skim path is bounded by
  `totalAssets − totalDebt − yieldBuffer` in the audited accounting — taking
  deposits is structurally impossible, not just access-controlled.
* **Withdrawals cannot be paused.** No such code path exists. The deposit
  cap can go to zero (pausing new deposits); withdrawals are untouchable.
* **The vault cannot be upgraded.** No proxy, no admin over code. Stockpot
  cannot upgrade, replace, or take control of the contract holding deposits.
* **Shares cannot be diluted.** Minting is 1:1 against deposited assets (or
  fee shares backed by accrued yield); there is no exchange rate to
  manipulate — first-depositor inflation attacks don't exist in this design.
* **If the underlying vault loses assets**, deposits shut off and
  withdrawals become proportional (audited PT loss handling). This is the
  disclosed residual risk of the yield source, not a Stockpot discretion.

## Trust model

### What the keeper can and cannot do

| Keeper action | Prevented / bounded by |
|---|---|
| Take principal via the skim | Vault yield accounting (see above) |
| Forge a winner not in the weights tree | Merkle proof verified onchain against the committed root |
| Pick a seed after seeing the oracle's random number | Seed commitment published at commit, before the oracle reveals |
| Bias the outcome alone | Winning ticket mixes the DiceEntropy oracle's contribution; derivation is rejection-sampled (uniform, no modulo bias) |
| Stall a round it doesn't like | Reveal window; after that **anyone** can void the round and the pot rolls over |
| Publish dishonest weights | Deposit TWAB is **onchain** (TwabController) — anyone can recompute the exact root from chain state before the draw reveals; a wrong root is public cryptographic evidence |

Residual keeper trust in v0: weights are checkable but a dishonest root is
not onchain-*prevented*; the keeper triggers draws (permissionless
triggering is a roadmap rider). The keeper can never steal the pot or touch
principal.

### Randomness: two mutually distrusting parties

Chainlink VRF does not exist on Robinhood Chain. Draws combine two
independent commitments so that biasing a draw requires **collusion between
the keeper and the oracle operator**:

1. The keeper hash-commits a secret seed at `commitDraw`.
2. The same transaction buys a random number from the **DiceEntropy** oracle
   (verified against the live deployment by fork test). Neither party learns
   the other's contribution before committing to its own.
3. The winning ticket is derived from `keccak256(abi.encode(seed, oracleRandom))`
   by rejection sampling — exactly uniform over `[0, totalWeight)`.

Safety properties enforced onchain:

* A round that bought oracle entropy **cannot reveal without it**
  (`EntropyPending`).
* The reveal-block hash is deliberately **not** an entropy input (the keeper
  could see it in advance — it would grant grinding power).
* Unilateral withholding by either party only stalls the round into a public
  void-and-rollover.
* Oracle fees are paid from a dedicated `entropyBalance`, never from prize
  money; an underfunded budget fails commits loudly (`EntropyUnderfunded`).
* Rounds bind their entropy source at commit, so `setEntropy` never weakens
  an open round.

Residual assumptions: the DiceEntropy operator's non-collusion with the
keeper and oracle liveness (a dead oracle stalls rounds into rollover, not
loss). The provider set is admin-gated and self-audited only — disclosed;
the source is pluggable if a stronger VRF deploys on chain 4663.

### Owner powers

| Role | Powers | Mitigations |
|---|---|---|
| PrizeVault owner | Deposit cap, skimmer & fee recipient roles, sweep of non-core tokens | Cannot pause withdrawals, upgrade, skim principal, or sweep core tokens; two-step ownership transfer |
| DrawManager owner | Treasury, PrizeBuyer, registrars, token configs | Rake hard cap 20%; cannot touch escrowed round pots |
| Pons (external) | Controls the Pons locker's fee-redirect authority for $POT | Disclosed trust dependency; affects fee revenue only, never deposits |

## Contract-level defenses

* **Checks-effects-interactions everywhere.** Round status flips before the
  prize leaves; `nonReentrant` guards claim/stake/unstake paths.
* **Audited deposit/withdraw paths.** ERC-777-safe transfer ordering,
  dust-collection strategy, yield buffer against rounding loss — inherited
  from the audited upstream, unmodified.
* **Escape hatches are permissionless.** `voidRound` after a missed reveal
  can be called by anyone — no funds depend on a privileged actor showing up.
* **SafeERC20** for all token transfers; custom errors on every failure path.

## Known issues & open items (tracked)

| Item | Status |
|---|---|
| Third-party audit of Stockpot's deployment | Not done — milestone-gated on treasury revenue; gates the uncapped vault |
| Static-analysis triage | Slither findings on inherited upstream patterns documented in `contracts/README.md`; intentionally kept (audited code not modified to appease linters) |
| Keeper decentralization | Roadmap rider: permissionless draw triggering, third-party weight verification |
| Oracle liveness & fees | A dead oracle stalls rounds into void-and-rollover; `entropyBalance` must stay funded or commits revert |
| External reward campaigns | Merkl's steakUSDG campaign is Robinhood-wallets-only (resolved 2026-08-06, unavailable to the vault); `sweep` stands ready for any future holder-paid rewards (e.g. GDN) |
| Prize-swap MEV | `minAmountOut` slippage floor set by claimer; stock-pool depth measured in dry run |
| Underlying vault (Steakhouse/Morpho) risk | Disclosed in the deposit-flow risk box; curator-managed, independent of Stockpot |
