Skip to content

ProtocolFee.sol

Collects and distributes the 4% APR AsiliChain protocol margin from every loan repayment. All fee rates are annualized percentages on principal (same as interest). Controlled by a 3-of-5 multisig. Transparent on-chain — every fee collection is publicly auditable.

Every auto-repayment distributes as follows (rates are APR on principal):
Gross repayment from buyer USDC payment
├── Principal + MFI interest (10% APR) → LendingVault MFI pool (repaid)
├── 4% APR protocol fee → ProtocolFee.sol (this contract)
├── 2% APR credit loss reserve → LendingVault reserve buffer
└── Net balance → Farmer via Fonbnk
Total cost to farmer: 10% + 4% + 2% = 16% APR

The 4% protocol fee collected by this contract is allocated by governance vote:

AllocationPercentagePurpose
Protocol operations40%API infrastructure, Hedera HCS fees, Pinata costs
Development reserve30%Smart contract upgrades, audits, new integrations
Credit loss backstop20%Additional insurance beyond per-loan reserve
Community / impact10%Cooperative training, field agent support
// State variables — auto-generated public getters
uint256 public totalCollected; // cumulative USDC received
uint256 public totalDistributed; // cumulative USDC sent out
address public usdcToken; // USDC token address (immutable)
// Core functions
function collect(uint256 amountUsdc) external onlyRole(VAULT_ROLE);
function distribute(
address recipient,
uint256 amount,
string calldata purpose // ← required, e.g. "Operations Q3 2026"
) external onlyRole(MULTISIG_ROLE);
function pendingDistribution()
external view returns (uint256); // totalCollected - totalDistributed

Important: collect() does not pull USDC from LendingVault.

The correct flow is:

  1. LendingVault calls usdc.transfer(protocolFeeAddr, amount)
  2. LendingVault then calls collect(amount) to record the arrival
  3. ProtocolFee emits FeeCollected with running total

This separation means ProtocolFee never holds a USDC allowance on behalf of LendingVault. It simply records what has already arrived.

CheckRevert if violated
recipient != address(0)"ProtocolFee: zero recipient"
amount > 0"ProtocolFee: zero amount"
bytes(purpose).length > 0"ProtocolFee: empty purpose"
amount <= pendingDistribution()"ProtocolFee: insufficient balance"

Protocol fee withdrawals require 3-of-5 MULTISIG_ROLE approval. Signers at launch:

SignerRole
AsiliChain founding team wallet 1Co-founder
AsiliChain founding team wallet 2Co-founder
Independent technical advisorExternal signer
MFI representative walletInstitutional accountability
ReservedFuture: community / MAAIF observer

This prevents unilateral treasury withdrawal and provides institutional confidence for MFI partners.

event FeeCollected(
uint256 amountUsdc,
uint256 totalCollectedToDate,
uint256 timestamp
);
event FeeDistributed(
address indexed recipient,
uint256 amountUsdc,
string purpose,
uint256 timestamp
);

These events are permanently readable on Mantle explorer and mirrored to Hedera HCS for the governance audit trail.