Vault Contract

The core lending contract. Each vault represents a single loan — created with negotiated terms, funded by investors, disbursed to the borrower, and repaid through incoming cash flow payments.

Source: contracts/vault/

Source Modules

File
Purpose

contract.rs

All public entry points, SEP-41 FungibleToken + FungibleBurnable impls, OZ Upgradeable

storage.rs

Data types, storage keys, getters/setters, phase transitions

math.rs

Fixed-point integer EMI calculation, split logic, late fees

errors.rs

#[contracterror] enum (31 variants)

events.rs

#[contractevent] structs (19 events)

token.rs

Documentation module — explains FungibleToken impl approach

test.rs

55 contract tests + 14 math tests (69 total)

Data Model

VaultConfig

VaultConfig {
    borrower: Address,       // Business receiving the loan
    lent_token: Address,     // Token being lent (e.g. USDC)
    manager: Address,        // Pool Manager who underwrote this vault
    principal: i128,         // Requested loan amount (7-decimal)
    interest_rate: u32,      // Annual rate in basis points (1000 = 10%)
    loan_term: u32,          // Term in months
    split_ratio: u32,        // % of payments routed to EMI pool (1–99)
    permissioned: bool,      // Whether only allowlisted investors can deposit
    grace_period: u64,       // Seconds after due date before default
    phase: VaultPhase,       // Current lifecycle phase
    created_at: u64,         // Creation timestamp
    disbursed_at: u64,       // Disbursement timestamp (0 if not yet)
    funding_deadline: u64,   // Deadline for full funding (0 = no deadline)
    approval_deadline: u64,  // Deadline for manager approval (0 = no deadline)
}

VaultPhase

Lifecycle Diagram

Functions

Constructor

Deploy a new vault. Sets debt token metadata (SEP-41) and cap (= principal). The admin is set to the Globals governor for upgradeability.

Investor Actions (RaisingFunds)

Function
Description

deposit(investor, amount)

Deposit funds and mint 1:1 debt tokens. Deducts 0.5% protocol fee. Auto-transitions to AwaitingApproval when fully funded.

withdraw(investor, amount)

Withdraw before fully funded, burns debt tokens.

Manager Actions

Function
Description

approve_and_disburse(caller)

Approve loan, disburse to borrower, calculate EMI, initialise payment schedule. AwaitingApproval → Active.

add_to_allowlist(caller, investor)

Add investor to permissioned vault's allowlist.

remove_from_allowlist(caller, investor)

Remove investor from allowlist.

Payment Actions (Active)

Function
Description

receive_payment(payer, amount)

Accept payment. Deducts fee, splits to pools, amortises principal, advances counter. Auto-transitions to FullyRepaid when done.

claim_yield(investor)

Claim pro-rata share of EMI pool (Active or FullyRepaid).

withdraw_cash(amount)

Borrower withdraws from cash pool (Active or FullyRepaid).

Deadline Enforcement (Permissionless)

Function
Description

check_funding_expiry()

Cancel if funding deadline passed. Refunds investors, releases collateral. RaisingFunds → Finalized.

check_approval_expiry()

Cancel if approval deadline passed. Refunds investors, releases collateral. AwaitingApproval → Finalized.

Risk & Default (Active)

Function
Description

apply_late_fee(caller)

Manager applies 18% p.a. penalty when overdue. Increments missed counter.

check_default()

Anyone can trigger. If past grace period: slash collateral, mark delinquent. Active → Defaulted.

Renegotiation (Active or Defaulted)

Function
Description

propose_renegotiation(caller, rate, term)

Manager proposes new terms. Saves previous phase. → Renegotiation.

approve_renegotiation(caller)

Apply new terms, recalculate EMI on outstanding principal, reset schedule. → Active.

reject_renegotiation(caller)

Cancel proposal, restore previous phase.

Queries

Function
Returns

get_config()

VaultConfig

get_lending_pool()

Total funded amount

get_investor_deposit(investor)

Individual deposit

get_investors()

List of all investors

get_emi()

Calculated EMI amount

get_emi_pool() / get_cash_pool()

Pool balances

get_payments_made()

Payment counter

get_outstanding()

Remaining principal

get_next_due()

Next payment due date

get_claimable(investor)

Available yield to claim

get_late_fees()

Accumulated late fees

get_missed_payments()

Consecutive missed payments

get_grace_period()

Grace period in seconds

get_reneg_proposal()

Current renegotiation proposal

get_token_cap()

Debt token supply cap

get_allowlist()

Allowlisted investors

SEP-41 Debt Token

The vault itself is the debt token contract — it implements OZ FungibleToken and FungibleBurnable traits directly. Tokens are minted 1:1 with deposits and represent the investor's share.

Debt tokens are non-transferabletransfer, transfer_from, and approve are disabled (panic on call). This ensures yield claims remain tied to the original depositor.

Function
Description

total_supply() / balance(account)

Supply and balance queries

transfer(from, to, amount)

❌ Disabled — panics

transfer_from(spender, from, to, amount)

❌ Disabled — panics

approve(owner, spender, amount, live_until_ledger)

❌ Disabled — panics

allowance(owner, spender)

Allowance query (always 0)

decimals() → 7

Token decimals

name() → "Trilobyte Vault Token"

Token name

symbol() → "tVLT"

Token symbol

burn(from, amount) / burn_from(...)

Burn tokens

EMI Math (math.rs)

All math is integer-only with 10¹² internal scaling:

Function
Description

calculate_emi(principal, annual_bps, term)

Standard amortisation, ceiling-rounded

split_payment(amount, split_ratio)

Split into EMI + cash pool portions

split_emi(outstanding, emi, annual_bps)

Break EMI into interest + principal

total_interest(principal, annual_bps, term)

Total interest over lifetime

total_repayment(principal, annual_bps, term)

Total borrower repayment

calculate_protocol_fee(amount, fee)

Fee in 7-decimal format

late_fee(overdue, penalty_bps)

Monthly penalty interest

Events

Event
Key Fields
When

VaultCreated

borrower, principal, loan_term, interest_rate

Constructor

InvestorDeposited

investor, amount, total_funded

Deposit

InvestorWithdrew

investor, amount

Withdrawal

VaultFullyFunded

total_funded

Fully funded

LoanDisbursed

borrower, amount

Disbursement

PhaseTransition

from, to

Phase change

PaymentReceived

payer, total_amount, emi_share, cash_share, payment_number, outstanding

Payment

YieldClaimed

investor, amount

Claim

CashWithdrawn

borrower, amount

Cash withdrawal

LateFeeApplied

fee, total_late_fees, missed_payments

Late fee

VaultDefaulted

borrower, outstanding, missed_payments

Default

RenegotiationProposed

manager, new_interest_rate, new_loan_term

Proposal

RenegotiationFinalized

new_interest_rate, new_loan_term, new_emi

Terms applied

RenegotiationRejected

caller

Proposal cancelled

VaultFundingExpired

deadline, total_funded, num_investors

Funding expired

VaultApprovalExpired

deadline, total_funded, num_investors

Approval expired

ProtocolFeeCollected

amount, treasury

Fee deducted

InvestorAllowlisted

investor

Added to allowlist

InvestorRemovedFromAllowlist

investor

Removed from allowlist

Error Codes

Code
Name
Description

1

InvalidPhase

Wrong lifecycle phase

2

InvalidAmount

Amount out of bounds

3

InvalidTerm

Term outside limits

4

InvalidRate

Rate below minimum

5

AlreadyFunded

Already fully funded

6

ExceedsPrincipal

Deposit exceeds principal

7

NoDeposit

No deposit found

8

InsufficientDeposit

Withdrawing too much

9

NotFullyFunded

Not yet fully funded

10

InvalidSplitRatio

Not 1–99

11

AssetNotSupported

Token not whitelisted

12

BorrowerNotApproved

Caller is not manager

13

PaymentNotDue

Payment not yet due

14

LoanFullyRepaid

All payments made

15

Unauthorized

Not authorised

16

NothingToClaim

No yield available

17

InsufficientCashPool

Cash pool too low

18

NotOverdue

Can't apply late fee

19

AlreadyDefaulted

Already defaulted

20

WithinGracePeriod

Too early for default

21

NoProposalExists

No renegotiation

22

ProposalAlreadyExists

Proposal pending

25

NotAllowlisted

Not on allowlist

26

AlreadyAllowlisted

Already on allowlist

27

FundingDeadlineNotReached

Too early

28

ApprovalDeadlineNotReached

Too early

29

NoDeadlineSet

No deadline configured

30

TooManyInvestors

Max investors reached

31

MathOverflow

Arithmetic overflow in math helper

Last updated