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.
Fee Structure
Section titled “Fee Structure”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% APRFee Allocation (Protocol Treasury)
Section titled “Fee Allocation (Protocol Treasury)”The 4% protocol fee collected by this contract is allocated by governance vote:
| Allocation | Percentage | Purpose |
|---|---|---|
| Protocol operations | 40% | API infrastructure, Hedera HCS fees, Pinata costs |
| Development reserve | 30% | Smart contract upgrades, audits, new integrations |
| Credit loss backstop | 20% | Additional insurance beyond per-loan reserve |
| Community / impact | 10% | Cooperative training, field agent support |
Interface
Section titled “Interface”// State variables — auto-generated public gettersuint256 public totalCollected; // cumulative USDC receiveduint256 public totalDistributed; // cumulative USDC sent outaddress public usdcToken; // USDC token address (immutable)
// Core functionsfunction 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 - totalDistributedPush-Model Collection
Section titled “Push-Model Collection”Important: collect() does not pull USDC from LendingVault.
The correct flow is:
LendingVaultcallsusdc.transfer(protocolFeeAddr, amount)LendingVaultthen callscollect(amount)to record the arrivalProtocolFeeemitsFeeCollectedwith running total
This separation means ProtocolFee never holds a USDC allowance on behalf of LendingVault. It simply records what has already arrived.
Distribution Rules
Section titled “Distribution Rules”| Check | Revert 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" |
Multisig Governance
Section titled “Multisig Governance”Protocol fee withdrawals require 3-of-5 MULTISIG_ROLE approval. Signers at launch:
| Signer | Role |
|---|---|
| AsiliChain founding team wallet 1 | Co-founder |
| AsiliChain founding team wallet 2 | Co-founder |
| Independent technical advisor | External signer |
| MFI representative wallet | Institutional accountability |
| Reserved | Future: community / MAAIF observer |
This prevents unilateral treasury withdrawal and provides institutional confidence for MFI partners.
Events
Section titled “Events”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.