> 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/technical-documentation/globals-contract.md).

# Globals Contract

Protocol-wide settings, role management, fee configuration, pool-manager collateral, manager credit/delinquency tracking, borrower/manager exposure tracking, the optional compliance-gate pointer, and the Factory + vault registry.

**Source:** `contracts/globals/`

## Source Modules

| File           | Purpose                                                                                                                                   |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `contract.rs`  | All public entry points — settings, roles, collateral, delinquency/credit, exposure tracking, compliance gate, Factory/vault registration |
| `storage.rs`   | Data types (`GlobalSettings`, `Manager`, `ManagerCollateral`), storage keys, getters/setters                                              |
| `constants.rs` | Default values (`PROTOCOL_FEE = 50_000` = 0.5% in 7-decimal; `LATE_FEE_BPS = 1800`)                                                       |
| `errors.rs`    | `#[contracterror]` enum                                                                                                                   |
| `events.rs`    | `#[contractevent]` structs                                                                                                                |
| `test.rs`      | 37 tests (core + collateral + delinquency/credit + settings/fee bounds)                                                                   |

## Roles & Authorisation

Roles use OpenZeppelin Access Control. The **admin** is the `governor` set at construction (later transferred to the Timelock). `sec_adm` and `ops_adm` are granted at construction.

| Role           | Key         | Who                 | Can Do                                                                                                                                                                                                                           |
| -------------- | ----------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Admin          | (OZ admin)  | Governor / Timelock | `whitelist_asset`, `remove_asset`, `whitelist_collateral_asset`, `remove_collateral_asset`, `set_treasury_address`, `set_factory`, `register_vault`\*, `set_compliance_gate`, `set_timelock`, `upgrade`, two-step admin transfer |
| Security Admin | `"sec_adm"` | Security team       | `pause` / `unpause`                                                                                                                                                                                                              |
| Ops Admin      | `"ops_adm"` | Operations team     | `approve_pool_manager`, `remove_pool_manager`, `set_protocol_fee`, `update_settings`, `set_manager_inactive`, `set_manager_credit_limit`, `clear_delinquency`                                                                    |

\* `register_vault` is admin-defined but additionally requires the call to come from the registered **Factory** (it re-checks `factory.require_auth()`).

{% hint style="info" %}
There is no `add_pool_manager` function. A manager is registered and activated in a single call, `approve_pool_manager`. There is also no bare `get_fee()` / `get_treasury()` / `is_pool_manager()` / `is_supported_asset()` / `get_pool_managers()` — use `get_global_settings().protocol_fee`, `get_treasury_address()`, `get_manager(addr).is_some()`, and the paginated `list_pool_managers(start, count)` instead.
{% endhint %}

## GlobalSettings

The settings struct now carries the core loan-bound fields plus every tranched-waterfall setting, all bounded in `validate_settings` and all events emitted on `update_settings`:

```rust
GlobalSettings {
    // ── Core (unchanged) ──
    protocol_fee: i128,
    min_interest_rate: u32,
    max_interest_rate: u32,
    min_loan_term: u32,
    max_loan_term: u32,
    default_grace_period: u32,
    default_risk_tolerance: u32,
    default_collateral_ratio: u32,
    min_collateral_value: i128,
    one_day: u64,
    one_year: u64,
    days_in_year_30_360: u32,
    days_in_month_30_360: u32,
    monthly_emi_interval: u64,
    default_penalty_rate_bps: u32,
    min_emi_tolerance: u32,
    token_decimals: u32,
    min_loan_amount: i128,
    max_loan_amount: i128,
    default_timelock_delay: u64,
    default_timelock_duration: u64,
    // ── Tranched-waterfall (new) ──
    max_leverage_uncollateralized: u32,   // 300 (3.00x), bounds 100-500
    max_leverage_collateralized: u32,     // 500 (5.00x), bounds 100-1000
    junior_spread_bps: u32,               // 2000 (20%), bounds 0-5000
    reserve_fee_bps: u32,                 // 1000 (10%), bounds 0-2000
    writedown_grace_days: u32,            // 45, bounds 0-90
    writedown_max_days: u32,              // 120, bounds 30-365
    max_borrower_outstanding: i128,       // 5,000,000 USDC
    max_borrower_share_bps: u32,          // 500 (5%), bounds 1-10000
    concentration_floor: i128,            // 2,000,000 USDC
    max_manager_share_bps: u32,           // 2500 (25%), bounds 1-10000
    max_manager_junior_share_bps: u32,    // 5000 (50%), bounds 1000-10000
    min_borrower_coll_ratio_bps: u32,     // 10000 (100%), bounds 5000-30000
    max_investors_per_vault: u32,         // 250, bounds 10-1000
    min_investment: i128,                 // 100 USDC, bounds 1-10,000 USDC
    late_fee_bps: u32,                    // 1800 (18%), max 5000 (50%)
    max_rate_cut_bps: u32,                // 500 (5%), bounds 0-10000
    require_timelock_admin: bool,         // default false
}
```

`leverage_ratio`, `junior_spread_bps`, `reserve_fee_bps`, `writedown_grace_days`, `writedown_max_days`, `period_seconds` (from `monthly_emi_interval`), and `max_investors` (from `max_investors_per_vault`) are all **snapshotted into each `VaultConfig` at creation**, so a later settings change never alters a live loan.

{% hint style="warning" %}
The min/max loan bounds are named `min_loan_amount` / `max_loan_amount` (not `min_principal` / `max_principal`). Timelock delay/duration are measured in **ledgers** (\~5 s/ledger), not seconds. `late_fee_bps` is read live from Globals when `apply_late_fee` is called — it is the one tranche-era setting that is deliberately **not** snapshotted per vault, since it's meant to reflect current policy on overdue loans.
{% endhint %}

## Functions

### Admin-only (`#[only_admin]`)

| Function                                     | Description                                                                                 |
| -------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `set_treasury_address(new_treasury)`         | Update the treasury address                                                                 |
| `whitelist_asset(asset)`                     | Whitelist a lending token                                                                   |
| `remove_asset(asset)`                        | Remove a lending token from the whitelist                                                   |
| `whitelist_collateral_asset(asset)`          | Whitelist a token for manager or borrower collateral (§14.2, separate list)                 |
| `remove_collateral_asset(asset)`             | Remove a token from the collateral whitelist                                                |
| `set_factory(factory)`                       | Register the Factory address (required before vault creation works)                         |
| `register_vault(vault)`                      | Mark a vault as trusted (Factory-gated)                                                     |
| `set_compliance_gate(gate: Option<Address>)` | Point the protocol-wide compliance check at a contract, or clear it                         |
| `set_timelock(timelock)`                     | Record the address `require_timelock_admin` will enforce                                    |
| `upgrade(new_wasm_hash, operator)`           | Upgrade the contract (auth via stored admin; hardened once `require_timelock_admin` is set) |

### Two-step admin transfer (OZ Access Control)

| Function                                                                                                                                                                                            | Description                                                                                                                                                                                                |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transfer_admin_role(new_admin, live_until_ledger)`                                                                                                                                                 | Initiate admin transfer; pending until accepted or `live_until_ledger`                                                                                                                                     |
| `accept_admin_transfer()`                                                                                                                                                                           | New admin accepts the pending transfer. Once `require_timelock_admin` is set, this additionally requires the resulting admin to equal the stored `timelock` — and reverts the whole transfer if it doesn't |
| Plus OZ role functions: `grant_role`, `revoke_role`, `renounce_role`, `has_role`, `get_role_admin`, `set_role_admin`, `get_role_member`, `get_role_member_count`, `get_admin`, `get_existing_roles` |                                                                                                                                                                                                            |

### Security Admin (`#[only_role(caller, "sec_adm")]`)

| Function          | Description                              |
| ----------------- | ---------------------------------------- |
| `pause(caller)`   | Pause all `#[when_not_paused]` functions |
| `unpause(caller)` | Resume normal operation                  |

### Operations Admin (`#[only_role(caller, "ops_adm")]`)

| Function                                                | Description                                                                                             |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `approve_pool_manager(manager, caller, max_credit)`     | Approve a manager with a credit limit (returns the `Manager`). There is no separate `add_pool_manager`. |
| `remove_pool_manager(manager_address, caller)`          | Remove a manager                                                                                        |
| `set_protocol_fee(fee, caller)`                         | Update the protocol fee (≤ 10%)                                                                         |
| `update_settings(settings, caller)`                     | Replace the full `GlobalSettings` struct, validated as a whole                                          |
| `set_manager_inactive(manager_address, caller)`         | Deactivate a manager                                                                                    |
| `set_manager_credit_limit(manager, max_credit, caller)` | Update a manager's credit limit                                                                         |
| `clear_delinquency(manager, caller)`                    | Clear a manager's delinquency record after review                                                       |

### Collateral (manager / cross-contract, `#[when_not_paused]`)

| Function                                               | Auth             | Description                                                                                                    |
| ------------------------------------------------------ | ---------------- | -------------------------------------------------------------------------------------------------------------- |
| `deposit_collateral(manager, token, amount)`           | Manager          | Stake collateral (manager must be active; token must be on the collateral whitelist; single token per manager) |
| `withdraw_collateral(manager, amount)`                 | Manager          | Withdraw unlocked collateral (`staked − locked`)                                                               |
| `lock_collateral(manager, amount)`                     | Factory          | Lock collateral on vault creation                                                                              |
| `release_collateral(caller, manager, amount)`          | Registered Vault | Release on full repayment / cancellation — not pause-gated (wind-down path)                                    |
| `slash_collateral(caller, manager, amount, recipient)` | Registered Vault | Slash into the vault's recovery pool on default — not pause-gated                                              |
| `get_manager_collateral(manager)`                      | Any              | View `{ token, staked, locked }`                                                                               |
| `get_available_collateral(manager)`                    | Any              | View `staked − locked`                                                                                         |

### Manager / borrower exposure tracking (cross-contract)

| Function                                                   | Called By | Description                                                                                                                           |
| ---------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `mark_delinquent(caller, manager)`                         | Vault     | Increment delinquency count on default — not pause-gated                                                                              |
| `increment_outstanding(manager, borrower, amount)`         | Factory   | Track new vault principal, per-manager **and** per-borrower, plus `total_outstanding`. Pause-gated — new exposure stops while paused. |
| `decrement_outstanding(caller, manager, borrower, amount)` | Vault     | Release principal on repayment / default / expiry, same three counters — not pause-gated                                              |
| `is_delinquent(manager)`                                   | Any       | Whether the manager has any uncleared default                                                                                         |
| `get_manager(manager)`                                     | Any       | Full `Manager` record (`Option`), O(1) regardless of registry size                                                                    |
| `get_borrower_outstanding(borrower)`                       | Any       | Total outstanding principal across all of a borrower's vaults                                                                         |
| `get_total_outstanding()`                                  | Any       | Protocol-wide outstanding principal                                                                                                   |

### Compliance gate

| Function                                     | Auth  | Description                                                                     |
| -------------------------------------------- | ----- | ------------------------------------------------------------------------------- |
| `set_compliance_gate(gate: Option<Address>)` | Admin | Point at a contract implementing `is_allowed(who, action) -> bool`, or clear it |
| `get_compliance_gate()`                      | Any   | Current gate address, if set                                                    |

### Public Queries

| Function                           | Returns                                                                     |
| ---------------------------------- | --------------------------------------------------------------------------- |
| `get_global_settings()`            | `GlobalSettings`                                                            |
| `get_treasury_address()`           | Treasury address                                                            |
| `get_supported_assets()`           | Whitelisted lending-token list                                              |
| `get_collateral_assets()`          | Whitelisted collateral-token list                                           |
| `is_collateral_asset(asset)`       | `bool`                                                                      |
| `list_pool_managers(start, count)` | A page of `Vec<Manager>`                                                    |
| `get_pool_manager_count()`         | Total registered managers                                                   |
| `get_timelock()`                   | `Option<Address>`                                                           |
| `is_timelock_admin_required()`     | `bool` — primitive-shaped, safe for another contract's upgrade path to read |
| `paused()`                         | `bool`                                                                      |

## Events

| Event                        | Key Fields                                               | When                                                   |
| ---------------------------- | -------------------------------------------------------- | ------------------------------------------------------ |
| `RoleUpdated`                | `role`, `new_address`                                    | An admin-set address (e.g. treasury, timelock) changed |
| `ProtocolPaused`             | `paused`                                                 | Paused / unpaused                                      |
| `ManagerApproved`            | `manager`                                                | Manager approved                                       |
| `ManagerRemoved`             | `manager`                                                | Manager removed                                        |
| `AssetWhitelisted`           | `asset`                                                  | Lending asset added                                    |
| `AssetRemoved`               | `asset`                                                  | Lending asset removed                                  |
| `CollateralAssetWhitelisted` | `asset`                                                  | Collateral asset added (§14.2)                         |
| `CollateralAssetRemoved`     | `asset`                                                  | Collateral asset removed                               |
| `FeeUpdated`                 | `new_fee`                                                | Protocol fee updated                                   |
| `SettingsUpdated`            | `caller`                                                 | `update_settings` called                               |
| `CollateralDeposited`        | `manager`, `token`, `amount`, `total_staked`             | Manager stakes collateral                              |
| `CollateralWithdrawn`        | `manager`, `amount`, `total_staked`                      | Manager withdraws collateral                           |
| `CollateralLocked`           | `manager`, `amount`, `total_locked`                      | Collateral locked for a vault                          |
| `CollateralReleased`         | `manager`, `amount`, `total_locked`                      | Collateral released                                    |
| `CollateralSlashed`          | `manager`, `amount`, `remaining_staked`                  | Collateral slashed on default                          |
| `ManagerMarkedDelinquent`    | `manager`, `delinquency_count`                           | Vault defaulted                                        |
| `ManagerDelinquencyCleared`  | `manager`                                                | Delinquency cleared                                    |
| `ManagerCreditLimitSet`      | `manager`, `max_credit`                                  | Credit limit set/updated                               |
| `ManagerOutstandingUpdated`  | `manager`, `outstanding_principal`                       | A manager's outstanding principal changed              |
| `BorrowerOutstandingUpdated` | `borrower`, `outstanding_principal`, `total_outstanding` | A borrower's cross-vault outstanding changed (§13.1)   |
| `ComplianceGateSet`          | `gate: Option<Address>`                                  | Compliance gate set/cleared                            |

See [Common Types and Events](/technical-documentation/common-types-and-events.md) for the full field-level schema of every event in every contract.

## Storage Design

`GlobalSettings`, treasury, the Factory address, the timelock address, and the asset/collateral-asset whitelists are stored in **instance storage** with TTL extension. Pool managers are individual **persistent** entries — `(Mgr, address) -> Manager` plus `(MgrAt, index) -> address` for enumeration and a count — so `get_manager` / `mark_delinquent` / `increment_outstanding` / `decrement_outstanding` are **O(1) regardless of registry size**; only `list_pool_managers(start, count)` pages through the enumeration index (a `remove_pool_manager` does a swap-remove to keep it dense). Registered vaults are stored in **persistent storage** keyed by vault address, with a TTL clamped to the network maximum (`max_ttl()`).

{% hint style="info" %}
This is a deliberate change from a single unbounded `Vec<Manager>` — the old design meant every read or write to any one manager's record had to decode the whole vector, a cost that grows with the size of the manager registry.
{% endhint %}

*As of September 2026.*
