> For the complete documentation index, see [llms.txt](https://spree-finance.gitbook.io/spreefinance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://spree-finance.gitbook.io/spreefinance/how-it-works/design.md).

# How It Works

### Contract Architecture

Spree is a modular system of upgradeable smart contracts deployed on EVM chains. Each contract has a specific responsibility, and contracts communicate through well-defined interfaces.

```
                        ┌─────────────────────┐
                        │    SpreeFactory      │
                        │  (Mint / Redeem SP)  │
                        └──────┬──────┬────────┘
                               │      │
                    ┌──────────┘      └──────────┐
                    ▼                             ▼
          ┌──────────────────┐          ┌──────────────────┐
          │   SpreePoints    │          │  CollateralVault  │
          │   (SP ERC-20)    │          │  (ERC-4626)       │
          └────────┬─────────┘          └──────────────────┘
                   │
       ┌───────────┼───────────────┐
       ▼           ▼               ▼
┌────────────┐ ┌──────────────┐ ┌──────────────────┐
│PointsFactory│ │PendingSPVault│ │  SpreeVault4626   │
│(Branded SP) │ │  (pSP)       │ │ (Rewards Vault)   │
└────────────┘ └──────┬───────┘ └────────┬──────────┘
                      │                  │
                      │         ┌────────┘
                      ▼         ▼
               ┌──────────────────────┐
               │  BonusRewardsVault   │
               │ (Bonus Rewards)      │
               └──────────────────────┘
                      │
            ┌─────────┼──────────┐
            ▼                    ▼
  ┌───────────────────┐ ┌───────────────┐
  │SpreeStatusRegistry│ │  BoostEngine  │
  │  (Tiers / TWAB)   │ │ (Multipliers) │
  └───────────────────┘ └───────────────┘
```

### Deployed Chains

| Network           | Chain ID | Environment |
| ----------------- | -------- | ----------- |
| Ethereum Mainnet  | 1        | Mainnet     |
| Base              | 8453     | Mainnet     |
| Berachain         | 80094    | Mainnet     |
| Base Sepolia      | 84532    | Testnet     |
| Berachain Testnet | 80084    | Testnet     |
| MOCA Devnet       | 5151     | Devnet      |
| MOCA Testnet      | 222888   | Testnet     |

### Security Model

#### Role-Based Access Control (RBAC)

Every contract uses OpenZeppelin's AccessControl (or AccessControlUpgradeable). Roles are granular:

* **DEFAULT\_ADMIN\_ROLE** controls role assignment and critical configuration
* **MANAGER\_ROLE** handles day-to-day operations (rates, whitelists, campaigns)
* **OPERATOR\_ROLE** triggers automated processes (tier updates, rebalancing)
* **PAUSER\_ROLE** can halt operations in emergencies

No contract uses a single-owner pattern. All privileged operations require a specific role.

#### UUPS Upgrades

Core contracts (SpreePoints, SpreeFactory, SpreeVault4626, BonusRewardsVault, PendingSPVault, SpreeStatusRegistry, BoostEngine) use the UUPS proxy pattern. An UPGRADER\_ROLE authorizes upgrades. The implementation contract's constructor calls `_disableInitializers()` to prevent initialization of the implementation directly.

#### Whitelists

SP transfers require both sender and receiver to be on the transfer whitelist. Minting SP requires the caller to be on the mint whitelist. Redemption requires the redeem whitelist. pSP settlements require the destination to be on the campaign's settlement whitelist.

#### Oracle Safety

The SpreeFactory checks price oracle data before every mint. If a collateral asset's price deviates from $1.00 beyond the configured tolerance, or if the price data is stale, the mint reverts.

The SpreeVault4626 uses an OracleManager with hysteresis-based circuit breaking: the vault pauses deposits when deviation exceeds `pauseDeviation`, and requires N consecutive safe price updates below `unpauseDeviation` before resuming.

#### Collateral Invariants

* **SP:** `totalSupply() of SP <= sum of all CollateralVault assets`
* **Branded SP:** `SP.balanceOf(PointsFactory) >= sum of all brands' collateralSP`
* **pSP:** `totalSupply() of pSP <= SP.balanceOf(PendingSPVault)`
* **BonusRewardsVault:** `totalDistributed <= totalHarvested`

The contracts check these invariants after state-changing operations.
