<!--
Sitemap:
- [Welcome to River](/index)
- [Asset-Backed Finance Primer](/concepts/finance-primer)
- [River for Lenders](/lenders/introduction)
- [Depositing](/lenders/depositing)
- [Earning: the Coupon](/lenders/earning)
- [The Accumulating Wrapper](/lenders/wrapper)
- [Withdrawals & Exits](/lenders/withdrawals)
- [Losses & Impairments](/lenders/losses)
- [FAQ](/lenders/faq)
- [Integrate with River](/integrate/get-started)
- [Wrapper Integration](/integrate/wrapper)
- [Class Token Integration](/integrate/class-token)
- [Contract Addresses](/integrate/addresses)
- [Protocol Architecture](/architecture)
- [Actors: Roles & Permissions](/technical/actors)
- [Proxies & Upgradeability](/technical/proxies)
- [Strategies & Reporters](/technical/strategies)
- [Glossary](/concepts/glossary)
- [Dual NAV & Exchange Rates](/accounting/dual-nav)
- [Settlement & Conservation](/accounting/settlement)
- [The Coupon Ledger](/accounting/coupon-ledger)
- [Wrapper Accounting](/accounting/wrapper)
- [Accounting Examples](/accounting/examples)
- [The Tiered Waterfall](/waterfall/)
- [Waterfall Scenarios](/waterfall/scenarios)
- [Security Model](/security)
- [Protocol Invariants](/technical/invariants)
- [List of Assumptions](/technical/assumptions)
- [External Entry Points](/technical/entry-points)
- [Governance](/governance)
- [Contract Reference](/reference/contracts)
- [River Engineering Standards](/reference/engineering-standards)
-->

# Proxies & Upgradeability

## Pattern

Every stateful River contract is a **UUPS proxy** (`ERC1967Proxy` + `UUPSUpgradeable`
implementation). Upgrade authorization is enforced in the implementation's `_authorizeUpgrade`,
which requires `UPGRADER_ROLE` in the relevant `RiverAccessControls` — held by the timelocked
governance authority, so every upgrade is delayed and visible before execution. See
[Timelock & Authority](/governance).

## Storage: ERC-7201 namespaces

All mutable state lives in ERC-7201 namespaced storage:

```solidity
/// @custom:storage-location erc7201:river.storage.<Contract>.v1
bytes32 internal constant STORAGE_LOCATION =
    bytes32(uint256(erc7201("river.storage.<Contract>.v1")));
```

This eliminates storage-collision risk across upgrades and inheritance changes, and makes each
contract's state auditable as a single struct. New fields are **appended** to the namespace struct
only — layout positions are never reordered.

## Immutable-after-init configuration

Some storage is set at `initialize` and deliberately has **no setter**. These are behavioral
commitments:

| Contract | Field | Why it must never change |
| --- | --- | --- |
| Wrapper | `underlying` | The exit-coupon clock assumes one monotonic `cumCashIndex` series; repointing would corrupt every live exit |
| Wrapper | `controllerProxyImpl` | Exit-bucket addresses are CREATE2-predicted from it; repointing would strand in-flight exits |
| Wrapper / tokens | `asset`, `decimalsOffset` | Unit-of-account and share-scale commitments |
| Structure | `accessControls`, pinned `pricingMode` | Authorization root and valuation basis for the deal's life |

A planned migration path exists anyway — the UUPS upgrade itself — which is timelocked, unlike a
setter would be.

## Upgrade constraints (operational)

* An upgrade of the **class token** must preserve `CouponLedgerLib` semantics — in particular
  `cumCashIndex` monotonicity. Wrappers pinned to it depend on the series never resetting or
  re-basing.
* Implementations are deployed with `_disableInitializers()` in the constructor — raw
  implementations cannot be initialized or hijacked.
* Each wrapper deploys and binds its own `ControllerProxy` implementation at initialize; clones
  are bound to the wrapper atomically at first use (no front-run window).
