> 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/covenants-exposure-and-compliance.md).

# Covenants, Exposure and Compliance

Alongside the tranche waterfall and manager collateral, Trilobyte enforces a set of protocol-level safeguards added with the tranched-waterfall protocol: on-chain concentration limits, loan-level covenants, collateral and investor-base policy, and an optional compliance gate. Most of these are Globals settings, so Governance can tune them without a contract upgrade.

## Exposure caps and concentration limits

Globals tracks running totals — `total_outstanding` protocol-wide, plus per-borrower and per-manager outstanding principal across all their vaults — and the **Factory** checks new loans against them at `create_vault`:

| Setting                    | Default        | Meaning                                                                                                                                                               |
| -------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `max_borrower_outstanding` | 5,000,000 USDC | Absolute cap on a single borrower's outstanding principal across all vaults                                                                                           |
| `max_borrower_share_bps`   | 500 (5%)       | Cap on a single borrower's share of `total_outstanding`                                                                                                               |
| `max_manager_share_bps`    | 2500 (25%)     | Cap on a single manager's share of `total_outstanding`                                                                                                                |
| `concentration_floor`      | 2,000,000 USDC | The share caps above only start applying once `total_outstanding` exceeds this floor, so the protocol's first loans are never blocked by a share of a still-tiny pool |

A new loan that would push a borrower over its absolute cap or (once past the floor) its share of the pool fails with `BorrowerExposureExceeded`; the equivalent for a manager fails with `ManagerExposureExceeded`. The backend's underwriting check applies the same logic as an earlier, friendlier warning — but the on-chain check in the Factory is the actual enforcement.

## Related-party rule

* The Factory **rejects** `create_vault` outright when `borrower == manager` (`BorrowerIsManager`) — a manager can never be the borrower on their own vault.
* `VaultConfig.related_party` is a separate, manager-declared **disclosure flag**, set at creation and immutable, for deals that off-chain policy considers related without the addresses literally matching (for example, a manager's affiliated cash-float vault). It is emitted in `VaultCreated`, exposed via `get_config`, and every UI listing must display it.
* A manager's **voluntary** junior deposit under their own address (never the protocol-mandated collateral amount) is capped at `max_manager_junior_share_bps` (default 50%) of `junior_target` — enforced in `deposit(Junior)` and defensively again in `lock_junior`. This keeps junior from being entirely manager capital by design, even before counting the collateral that anchors it.

## Collateral asset policy

Globals keeps a **collateral asset whitelist**, separate from the whitelist of assets that can be lent. Both the manager's staked collateral and any borrower pledge must use a listed collateral asset (`whitelist_collateral_asset` / `remove_collateral_asset`, admin-only).

`min_borrower_coll_ratio_bps` (default 10000 = 100%, bounded 5000–30000) sets the floor a verified borrower pledge must meet relative to principal, checked at `approve_and_disburse`. Version 1 policy assumes stable or 1:1-tokenized collateral — there is no price oracle or LTV/margin-call monitoring yet; see [Collateral & Real-World Assets](/overview/collateral-and-rwa.md).

## Investor cap and minimum investment

* `max_investors_per_vault` (default 250, bounded 10–1000) replaces the old hardcoded 100-investor cap. It's snapshotted into each `VaultConfig` at creation as `max_investors`, and counts (investor, tranche) positions — an investor holding both tranches uses two slots.
* `min_investment` (default 100 USDC, bounded 1–10,000 USDC) is enforced on every `deposit`, rejecting dust positions that would otherwise fill a small cap with noise (`BelowMinimumInvestment`).
* Refunds, TTL bumps, and the finalize gating are all **pull-based and paginated** rather than looped, specifically so a vault can safely carry a large number of investors without any single call's cost scaling with the count — see [Cancelled](/protocol-mechanics/vault-lifecycle/cancelled.md) and the [Vault Contract](/technical-documentation/vault-contract.md) reference.

## Loan-level covenants

Two covenants apply once a loan is Active:

* **Cash-pool lock** — `withdraw_cash` is blocked with `BorrowerNotCurrent` while `missed_payments > 0`. A borrower must be caught up on arrears before taking residual cash out of the vault.
* **Reporting covenant** — if `VaultConfig.reporting_interval` is non-zero, the manager calls `mark_report_received()` on that cadence. If a report becomes overdue, anyone can call `check_reporting()`, which sets a `reporting_overdue` flag, emits an event, and counts as one missed period toward the NAV write-down until the next report clears it.

Both flags are exposed together via `get_covenant_status()` and factored into `get_senior_nav()` / `get_junior_nav()`. See [Active](/protocol-mechanics/vault-lifecycle/active.md) and [Default & Risk Management](/protocol-mechanics/default-and-risk-management.md).

## Compliance gate (optional, protocol-wide)

Globals can optionally hold a `compliance_gate` contract address implementing a single function, `is_allowed(who, action) -> bool` (actions: `0 = Invest`, `1 = Borrow`, `2 = Manage`). When set:

* The vault checks it before a `deposit` (action `Invest`)
* The vault checks it before disbursing to the borrower in `approve_and_disburse` (action `Borrow`)
* The Factory checks it for the manager at `create_vault` (action `Manage`)

When unset, every check passes and a permissioned vault's own allowlist remains the only investor-side gate. A rejected check fails with `NotCompliant`.

The first implementation, [Compliance Allowlist](/technical-documentation/compliance-allowlist-contract.md), is a simple admin-maintained allowlist — a stand-in that can later be swapped for a KYC-token contract (for example, one minted on Sumsub approval) without touching the Vault or Factory, since only the address Globals points at changes.

{% hint style="info" %}
On testnet, `ComplianceAllowlist` is deployed but **not** wired into Globals by the deploy script — `set_compliance_gate` is a deliberate, separate governance action once the allowlist has real entries. See [Testnet Deployment](/technical-documentation/testnet-deployment.md).
{% endhint %}

*As of September 2026.*
