<!--
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)
-->

# River Engineering Standards

These standards apply to River contracts unless a file documents a deliberate exception.

## Contract Architecture

* Use UUPS implementations behind `ERC1967Proxy` for stateful contracts.
* Initialize proxies in the `ERC1967Proxy` constructor with `abi.encodeCall`.
* Implementation constructors must call `_disableInitializers()`.
* Put mutable product state in `initialize`.
* Gate upgrades with `UPGRADER_ROLE`.
* Keep core accounting in `Structure`. Put policy behind explicit modules.

## Access Control

* Use an external access-control module per Structure or deployment.
* Core contracts store an `accessControls` address or resolve it through the Structure.
* Core contracts should not own role membership mappings directly unless the design needs a local role
  universe.
* Do not let related contracts silently use different role registries.

Initial roles:

```text
DEFAULT_ADMIN_ROLE
STRUCTURE_ADMIN_ROLE
KEEPER_ROLE
UPGRADER_ROLE
```

`RiverAccessControls` should remain thin:

* role registry;
* enumerable role views;
* `setRoleAdmin`;
* UUPS upgrade authorization.

Governance policy, timelocks, emergency revokers, and multisig thresholds should live in governance
modules above it.

## Operator Safety

Assume keeper and allocator keys can be compromised.

* Keeper roles should call bounded workflows.
* Capital movement should happen through named `Structure` functions:
  `fundStrategy`, `requestStrategyReturn`, `claimStrategyReturn`, and `processExits`.
* Add explicit movement controls where needed:
  * per-strategy caps;
  * recipient allowlists;
  * rate limits;
  * minimum-return checks;
  * slippage bounds.
* Treat claim, cancel, and return paths as risky when they depend on external state or can lock funds.

## Storage

* Use ERC-7201 namespaced storage for every upgradeable contract with mutable state.
* Namespace format:

```text
river.storage.<ContractName>.v<Version>
```

* Use Solidity 0.8.35's compile-time ERC-7201 slot helper:

```solidity
/// @custom:storage-location erc7201:river.storage.Structure.v1.0.0
struct StructureStorage {
    // fields
}

bytes32 internal constant STRUCTURE_STORAGE_LOCATION =
    bytes32(uint256(erc7201("river.storage.Structure.v1.0.0")));
```

* Storage accessors should use a local `$` variable and memory-safe assembly:

```solidity
function _getStructureStorage() internal pure returns (StructureStorage storage $) {
    bytes32 slot = STRUCTURE_STORAGE_LOCATION;
    assembly ("memory-safe") {
        $.slot := slot
    }
}
```

* Never reorder or remove fields from an existing storage struct.
* Append fields, or create a new namespace for a major layout change.
* Modules must not read each other's ERC-7201 namespaces. Use interfaces or an explicitly shared namespace.
* Cache storage fields locally when a function reads them multiple times.

## Arithmetic And Units

* Treat rounding as product behavior.
* Keep `StrategyMetrics`, class NAV, and facility covenant values in the Structure asset's native decimals.
* Do not use `1 ether` to mean "one asset" unless the asset is explicitly 18 decimals. Tests may use it
  when the fixture asset is 18 decimals.
* Prefer named constants:

```text
BPS = 10_000
WAD = 1e18
RAY = 1e27
```

* Use `Math.mulDiv` for multiplication followed by division.
* Document the rounding direction at every economic boundary:
  * share minting;
  * exit payment;
  * waterfall allocation;
  * pro-rata allocation;
  * residual dust.
* Keep checked arithmetic by default.
* Use `unchecked` only with a local proof comment and test coverage for the bound.
* Use `SafeCast` or an explicit bound check before downcasting.
* Keep signed/unsigned mixing inside small helper functions.
* Reject `type(int256).min` before absolute value conversion.
* For pro-rata allocation, calculate non-residual allocations with `mulDiv`, then assign the remainder to a
  deterministic residual class so totals conserve exactly.

## Compiler And Tooling

* Pin Foundry to `solc_version = "0.8.35"`.
* Enable optimizer with `optimizer_runs = 200`.
* Keep `lint_on_build = false` until Foundry and Solar fully support Solidity's `erc7201()` helper.
* Prefer Forge commands for Foundry dependencies and submodules.

## Module Boundaries

* `Structure` owns class accounting and conservation.
* `AccessControls` stays external.
* Strategy movement goes through Structure-level calls.
* Facility-only fields stay out of generic strategy interfaces.
* Rate limits and caps are separate modules or explicit strategy checks.
* Prefer explicit interfaces over a dynamic dispatcher for v1.

If dynamic dispatch is added later, reserve core selectors and reject selector collisions before any route
is installed.

## External Calls And Tokens

* Follow checks-effects-interactions.
* Emit events after state changes and external calls complete.
* Use exact approvals for strategy calls.
* Clear nonzero temporary approvals after external calls.
* Avoid unbounded loops in user-triggered paths.
* Keeper paths still need budgets, such as `maxShares`, `maxAssets`, or module-specific caps.
* Mutating functions should not return unbounded arrays. Prefer counters, summaries, or opaque `bytes`
  receipts.
* Guard ERC-20 movement paths with OpenZeppelin `ReentrancyGuardTransient`.
* Use the narrowest interface possible for external calls.
* Avoid arbitrary `call` surfaces unless an allowlist or rate-limit module constrains target, selector,
  recipient, and value.

## Reporting And Oracles

* Reporters must make pricing mode explicit: `Conservative` or `Optimistic`.
* Conservative reports include losses and impairments, but exclude uncertain upside.
* Optimistic reports may include accrued or unrealized upside, but still include losses and impairments.
* Attested reports need nonce, timestamp, source hash, signer policy, and domain binding.
* On-chain state stays on-chain. Do not attest a shadow copy of facility `drawn`.
* Freshness, monotonic nonce checks, signer policy, and maximum movement bounds should be explicit reporter
  or verifier policy.

## Upgrade And Initialization Tests

Every UUPS contract should test:

* implementation cannot be initialized directly;
* proxy initializes correctly;
* proxy cannot initialize twice;
* unauthorized upgrade reverts;
* authorized upgrade emits `Upgraded`;
* state remains readable after upgrade.

## Code Style

* External and public functions should have NatSpec.
* Prefer custom errors for new code.
* Use named mappings for readability.
* Keep repeated module names explicit:
  `StructureStorage`, `STRUCTURE_STORAGE_LOCATION`, `_getStructureStorage`.
* Use semantic `bytes32` ids for product concepts.
* Use `uint256` for indexes and amounts.

## Invariant Tests

Accounting implementations should have focused unit tests plus fuzz or invariant tests for:

* class NAV sums after settlement;
* exact pro-rata delta conservation;
* exact waterfall delta conservation or documented revert;
* negative deltas cannot underflow class NAV;
* checkpoints equal reporter values after settlement;
* value-neutral funding and return paths do not create profit;
* unauthorized callers cannot settle, fund, upgrade, process exits, or change policy;
* stale, replayed, and out-of-domain reports are rejected;
* facility headroom is enforced before funds leave the Structure.
