# 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://spree-finance.gitbook.io/spreefinance/how-it-works/design.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
