Skip to content

LendingVault.sol

UUPS upgradeable lending vault that issues coffee-collateralized loans. Loan repayment is auto-triggered by the API when a batch reaches EXPORTED stage. Fees are calculated as APR on principal — same formula as interest.

Loans are collateralized by BatchTokens (ERC-721). The vault reads batch valuation directly from BatchToken on the same chain:

batchValue = pricePerKgBase × weightKg × gradeMultiplier
loanPrincipal = batchValue × ltvBasisPoints / 10000

BatchToken’s hasActiveLoan() flag prevents double-collateralization — a batch cannot back more than one loan.

All rates are APR percentages on principal (annualized). This keeps the total cost predictable regardless of loan duration.

ComponentRate (APR)Recipient
MFI interest10% (1000 bps)LendingVault — MFI pool
Protocol fee4% (400 bps)ProtocolFee.sol
Credit loss reserve2% (200 bps)Vault reserve buffer
Total cost to farmer16% (1600 bps)

Example for a $2,500 loan at 90 days:

ComponentCalculationAmount
MFI interest$2,500 × 10% × 90/365$61.64
Protocol fee$2,500 × 4% × 90/365$24.66
Reserve$2,500 × 2% × 90/365$12.33
Total cost$2,500 × 16% × 90/365$98.63

Issues a loan against a BatchToken. The LTV is determined by the farmer’s CreditScore tier, capped by maxLtvBps (default 80%).

  1. Checks farmer exists, batch is free, protocol is not paused
  2. Reads batch valuation and CreditScore LTV tier
  3. Transfers principal USDC from vault to farmer
  4. Locks batch as collateral (sets hasActiveLoan = true)
  5. Stores loan with term (default 90 days)
function originate(uint256 batchTokenId, address farmerWallet) external;

Processes repayment when the API confirms EXPORTED. Called after buyer transfers USDC into vault.

  1. Calculates APR-based protocol fee (4%) and reserve (2%) using the loan’s actual duration
  2. Transfers protocol fee USDC to ProtocolFee.sol
  3. Accrues reserve in creditLossReserve (USDC stays in vault)
  4. Unlocks and burns the BatchToken collateral
  5. Transfers net proceeds to farmer
function settle(uint256 batchTokenId, uint256 usdcAmount) external;

Deploys accrued credit loss reserve to cover defaults. MULTISIG_ROLE only. Typically used to compensate an MFI after a loan defaults and the collateral cannot be fully recovered.

function deployReserve(address recipient, uint256 amount) external onlyRole(MULTISIG_ROLE);

Marks a loan as defaulted after expiry. 30-day forbearance period allows for late repayment. Default records a penalty on the farmer’s CreditScore.

The creditLossReserve is a cumulative buffer that stays in the LendingVault. Each settlement withholds 2% APR of the principal. The reserve is drawn down via deployReserve() when defaults must be covered.

Gross repayment from buyer
├── Principal + MFI interest → vault (MFI pool)
├── 4% APR protocol fee → ProtocolFee.sol
├── 2% APR reserve → creditLossReserve
└── Net balance → farmer
RolePurpose
VAULT_ROLECan call state-changing functions (granted to API wallet)
MULTISIG_ROLECan deploy credit loss reserve (3-of-5 multisig)
DEFAULT_ADMIN_ROLECan upgrade contract, update parameters
ParameterDefaultDescription
pricePerKgBase$5.00/kgCoffee price for batch valuation
maxLtvBps8000 (80%)Maximum LTV cap
interestRateBps1000 (10%)MFI interest rate
loanTermSecs90 daysLoan duration
forbearancePeriodSecs30 daysGrace period after default