For the complete documentation index, see llms.txt. This page is also available as Markdown.

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.

  • 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.

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 and the Vault Contract 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 and Default & Risk Management.

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, 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.

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.

As of September 2026.

Last updated