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:
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_vaultoutright whenborrower == manager(BorrowerIsManager) — a manager can never be the borrower on their own vault.VaultConfig.related_partyis 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 inVaultCreated, exposed viaget_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%) ofjunior_target— enforced indeposit(Junior)and defensively again inlock_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 eachVaultConfigat creation asmax_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 everydeposit, 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_cashis blocked withBorrowerNotCurrentwhilemissed_payments > 0. A borrower must be caught up on arrears before taking residual cash out of the vault.Reporting covenant — if
VaultConfig.reporting_intervalis non-zero, the manager callsmark_report_received()on that cadence. If a report becomes overdue, anyone can callcheck_reporting(), which sets areporting_overdueflag, 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(actionInvest)The vault checks it before disbursing to the borrower in
approve_and_disburse(actionBorrow)The Factory checks it for the manager at
create_vault(actionManage)
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.
As of September 2026.
Last updated