# 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

```rust
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

```rust
VaultPhase {
    RaisingFunds(0),
    AwaitingApproval(1),
    Active(2),
    FullyRepaid(3),
    Finalized(4),
    Renegotiation(5),
    Defaulted(6),
}
```

### Lifecycle Diagram

```
RaisingFunds → AwaitingApproval → Active → FullyRepaid → Finalized
                                    ↕           ↗
                               Renegotiation
                                    ↕           ↘
                                 Defaulted
```

## Functions

### Constructor

```
__constructor(globals, params: VaultParams)
```

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-transferable** — `transfer`, `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 |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.trilobyte.finance/technical-documentation/vault-contract.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
