> For the complete documentation index, see [llms.txt](https://docs.trilobyte.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.trilobyte.finance/protocol-mechanics/governance.md).

# Governance

Trilobyte uses a **role-based access control** system combined with a **Timelock** for governance delay on critical actions.

## Governance Architecture

```
┌───────────────────────────────────────────────┐
│                  Timelock                      │
│        (OZ TimelockController)                │
│   Proposer / Executor / Canceller roles       │
│   Admin of Globals (governor actions delayed) │
└──────────────────────┬────────────────────────┘
                       │ admin
┌──────────────────────▼────────────────────────┐
│                   Globals                      │
│          (OZ Access + Pausable + Upgradeable)  │
│   Settings · Roles · Fees · Assets · Managers  │
│   Exposure tracking · Compliance gate          │
└───────────────────────────────────────────────┘
```

The **Timelock** is set as the admin of the **Globals** contract via the OZ two-step transfer. This means admin-level actions are *intended* to go through a time-delayed governance process — and, once `require_timelock_admin` is enabled (see below), that intent becomes an on-chain requirement rather than just a convention.

## Roles

| Role                 | Key         | Assigned To         | Responsibilities                                                                                                                         |
| -------------------- | ----------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Admin**            | (OZ admin)  | Governor / Timelock | Whitelist lending and collateral assets, treasury, register the Factory, set the compliance gate and timelock address, contract upgrades |
| **Security Admin**   | `"sec_adm"` | Security team       | Emergency pause/unpause of the protocol                                                                                                  |
| **Operations Admin** | `"ops_adm"` | Operations team     | Approve/remove pool managers, set credit limits, clear delinquency, update global settings and the protocol fee                          |

## Timelock Controller

The Timelock enforces a **minimum delay** on governance operations, measured in **ledger sequence numbers** (\~5 s/ledger) — not seconds. A `TIMELOCK_MIN_DELAY` of `86400` is therefore roughly 5 days of ledgers, not one day; this has been a real source of deploy-tooling bugs (see [Deployment](/technical-documentation/deployment.md)).

### Operation Lifecycle

```
Unset → Waiting → Ready → Done
```

1. **Proposer** schedules an operation with a delay
2. The operation enters **Waiting** state
3. After the delay passes, the operation becomes **Ready**
4. **Executor** executes the operation → **Done**

A **Canceller** can cancel any pending operation before execution.

### Admin (Timelock-controlled) actions

The Globals **admin role** is intended to be held by the Timelock, so these admin-only actions are meant to carry the governance delay:

| Action                       | Function                     | Impact                                                                                     |
| ---------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------ |
| Whitelist a lending asset    | `whitelist_asset`            | Enables a token for lending                                                                |
| Remove a lending asset       | `remove_asset`               | Disables a token                                                                           |
| Whitelist a collateral asset | `whitelist_collateral_asset` | Enables a token as manager or borrower collateral (§14.2)                                  |
| Remove a collateral asset    | `remove_collateral_asset`    | Disables a collateral token                                                                |
| Update treasury              | `set_treasury_address`       | Changes the fee recipient                                                                  |
| Register factory             | `set_factory`                | Authorises the factory to lock collateral, track outstanding, and register vaults          |
| Set compliance gate          | `set_compliance_gate`        | Points the protocol-wide compliance check at a contract, or clears it                      |
| Set timelock address         | `set_timelock`               | Records which address `require_timelock_admin` will enforce                                |
| Upgrade contracts            | `upgrade`                    | Deploys new contract code (Globals, Vault, Factory, CollateralEscrow, ComplianceAllowlist) |

### Non-Timelocked (instant) actions

These are Operations- or Security-Admin actions, executed instantly:

| Action                     | Role           | Function                                       |
| -------------------------- | -------------- | ---------------------------------------------- |
| Pause / unpause            | Security Admin | `pause` / `unpause`                            |
| Approve / remove managers  | Ops Admin      | `approve_pool_manager` / `remove_pool_manager` |
| Set credit limits          | Ops Admin      | `set_manager_credit_limit`                     |
| Clear delinquency          | Ops Admin      | `clear_delinquency`                            |
| **Update global settings** | Ops Admin      | `update_settings`                              |
| **Update protocol fee**    | Ops Admin      | `set_protocol_fee`                             |

{% hint style="warning" %}
**Updating global settings and the protocol fee is an Operations-Admin action and is NOT timelocked** — the Ops Admin can change loan-parameter bounds, tranche settings, exposure caps, and the fee instantly. Only the admin-role actions above are meant to carry the Timelock delay.
{% endhint %}

## Upgrade-authority hardening

Globals holds an optional `timelock: Option<Address>` and a `require_timelock_admin: bool` setting (default `false` on testnet; the mainnet deploy script is required to set it `true` after wiring the timelock — see [Deployment](/technical-documentation/deployment.md)). Once `require_timelock_admin` is `true`:

* Completing a Globals admin transfer (`accept_admin_transfer`) requires the resulting admin to equal the stored `timelock` address — checked immediately after the underlying OZ two-step transfer completes, and the whole transaction reverts (including the transfer itself) if it doesn't hold.
* `Vault.upgrade`, `Factory.upgrade`, and `CollateralEscrow.upgrade` additionally require the **current** admin (already required to authorize the upgrade) to equal the stored `timelock`.

This turns the Timelock from a role convention into an on-chain enforcement — once enabled, no admin key, however it was obtained, can upgrade a contract or complete an admin handover without going through the timelock first.

{% hint style="danger" %}
**Upgrade-path rule.** An upgrade or admin-recovery entry point must never decode another contract's full composite type (like `GlobalSettings`) — only primitives (`bool`, numbers, addresses, `Option<Address>`). A hand-mirrored struct that drifts from the real one traps on decode, and if that trap is inside the upgrade path itself, the contract is permanently bricked — there is no upgrade left to fix it. This is exactly what happened to an early testnet Factory; see [Testnet Deployment](/technical-documentation/testnet-deployment.md) for the incident and the recovery. `Globals.is_timelock_admin_required()` and `Globals.get_timelock()` exist specifically so upgrade paths never need to decode `GlobalSettings`.
{% endhint %}

## Emergency Powers

The **Security Admin** can pause the entire protocol instantly:

* `pause(caller)` — Halts all state-changing functions protected by `#[when_not_paused]`
* `unpause(caller)` — Resumes normal operation

This is a circuit breaker for emergencies — exploits, critical bugs, or market events that require immediate protocol freeze.

### Pause scope — wind-down stays available

Pausing blocks ordinary economic activity (`deposit`, new vault creation via `increment_outstanding`), but **deliberately does not** block the calls a vault needs to wind down a loan that is already defaulting or expiring: `release_collateral`, `slash_collateral`, `mark_delinquent`, and `decrement_outstanding` are not pause-gated in Globals (they're already gated by `is_registered_vault`, so only a real vault can call them), and a vault's own `check_default` / `claim_recovery` paths are deliberately exempt from the pause check too. A paused protocol can still let existing defaulted or expired loans resolve; it just can't take on new exposure or new deposits while paused.

## Self-Administered Timelock

The Timelock is deployed as **self-administered** — it is its own admin. This means:

* No single address can bypass the time delay
* The Timelock's own settings (delay, roles) can only be changed through the Timelock itself
* This creates a fully decentralised governance loop

*As of September 2026.*
