Skip to content
azharpratamaPublic

Latest commit

 

History

5 Commits

Folders and files

Repository files navigation

EduLoan

Foundry License: MIT Tests

A production-ready decentralized education loan platform built on the Mantle Network. Students apply for loans, administrators manage approvals and disbursements, and all repayments are tracked transparently on-chain.

Live Demo

Frontend: https://eduloan-mantle.vercel.app

Contract (Mantle Sepolia): 0x0AeC48e885a9ec762A2653cB8866e35f1CEAcc8d

Verified Source: View on Mantlescan

Try it now! Connect your wallet (switch to Mantle Sepolia), get testnet MNT from the faucet, and test the full loan flow.

Features

Core Functionality

  • Loan Applications - Students specify amount and educational purpose
  • Admin Approval System - Approve/reject based on liquidity and criteria
  • Direct Disbursement - Funds transfer directly to approved borrowers
  • Flexible Repayments - Pay any amount, track progress transparently
  • Multiple Loans - Students can have multiple active loans simultaneously
  • Purpose Tracking - Every loan documents its educational purpose

Security & Best Practices

  • Custom Errors - Gas-optimized error handling (~91% savings on reverts)
  • Input Validation - Min/max bounds for amounts (0.01-10 MNT)
  • Fixed Duration - All loans have 365-day repayment period
  • Status Tracking - Clear lifecycle: Pending → Approved → Active → Repaid/Defaulted
  • Event-Driven - Complete audit trail via blockchain events
  • Access Control - Admin-only functions properly protected

Technical Highlights

  • 25/25 tests passing with 100% function coverage
  • Gas-optimized custom errors save ~17,600 gas total
  • HackQuest-compatible contract interface
  • Verified source code on Mantlescan
  • Production-ready security patterns

Quick Start

Prerequisites

Installation

# Clone the repository
git clone https://github.com/azharpratama/eduloan.git
cd eduloan

# Copy environment file
cp .env.example .env
# Edit .env and add your PRIVATE_KEY for contract deployment

# Install contract dependencies
cd contract
forge install

# Install frontend dependencies
cd ../frontend
npm install

Project Structure

eduloan/
├── contract/               # Smart contract (Foundry)
│   ├── src/
│   │   └── EduLoan.sol    # Main contract (338 lines)
│   ├── test/
│   │   └── EduLoan.t.sol  # 25 comprehensive tests
│   ├── script/
│   │   └── EduLoan.s.sol  # Deployment script
│   ├── lib/               # Foundry dependencies
│   └── foundry.toml       # Foundry config
├── frontend/               # React frontend
│   ├── src/
│   │   ├── components/    # UI components
│   │   ├── config/        # Contract ABI & config
│   │   ├── hooks/         # Web3 hooks
│   │   ├── pages/         # App pages
│   │   └── lib/           # Utilities
│   └── package.json
├── .env.example           # Environment template
└── README.md              # This file

Smart Contract Development

Build Contract

cd contract
forge build

Run Tests

cd contract

# Run all tests
forge test

# Run with gas report
forge test --gas-report

# Run with verbosity
forge test -vvv

Expected: All 25 tests passing ✅

Deploy Contract

cd contract

# 1. Configure ../.env with your PRIVATE_KEY

# 2. Deploy to Mantle Sepolia
forge script script/EduLoan.s.sol \
  --rpc-url https://rpc.sepolia.mantle.xyz \
  --broadcast \
  --verify \
  -vvvv

# 3. Note the deployed contract address from output

Interact with Contract (using Cast)

# Check contract balance
cast call <CONTRACT_ADDRESS> "getContractBalance()" --rpc-url https://rpc.sepolia.mantle.xyz

# Get total loans
cast call <CONTRACT_ADDRESS> "getTotalLoans()" --rpc-url https://rpc.sepolia.mantle.xyz

# Admin deposits funds
cast send <CONTRACT_ADDRESS> "depositFunds()" \
  --value 10ether \
  --private-key <YOUR_PRIVATE_KEY> \
  --rpc-url https://rpc.sepolia.mantle.xyz

Frontend Development

The frontend is built with React 19, TypeScript, Vite, and Wagmi v2 for Web3 integration.

Configuration

cd frontend

# Copy environment file (optional - has default values)
cp .env.example .env

# Update contract address if you deployed your own:
# VITE_CONTRACT_ADDRESS=0xYourContractAddress

Development Server

npm run dev

Visit http://localhost:5173

Build for Production

npm run build
npm run preview  # Preview production build

Available Pages

  • Home (/) - Landing page with project overview
  • Apply Loan (/apply) - Loan application form
  • My Loans (/my-loans) - View all your loans
  • Loan Detail (/loan/:id) - Detailed loan view with payment
  • Admin (/admin) - Admin dashboard (approve, disburse, manage funds)

Contract Interface

Student Functions

Function Description Parameters
applyLoan Submit loan application amount, purpose
makePayment Make loan payment loanId
getMyLoans Get all your loan IDs -
getLoanDetails Get loan information loanId
getRemainingAmount Check remaining debt loanId

Admin Functions

Function Description Parameters
approveLoan Approve pending loan loanId
rejectLoan Reject pending loan loanId, reason
disburseLoan Transfer funds to borrower loanId
depositFunds Add funds to contract -
withdrawFunds Withdraw excess funds amount

View Functions

Function Returns Description
loans(loanId) Loan struct Get loan data
borrowerLoans(address, index) uint256 Get loan ID by index
getContractBalance() uint256 Check contract balance
getTotalLoans() uint256 Total number of loans
calculateInterest(amount) uint256 Calculate 5% interest
admin() address Get admin address

Loan Status Flow

┌─────────┐
│ PENDING │  Student applies
└────┬────┘
     │
     ├──────► [Admin Approves] ──────┐
     │                                │
     └──────► [Admin Rejects] ─────► REJECTED
                                      │
                                      ▼
                               ┌──────────┐
                               │ APPROVED │
                               └─────┬────┘
                                     │
                         [Admin Disburses Funds]
                                     │
                                     ▼
                               ┌────────┐
                               │ ACTIVE │
                               └────┬───┘
                                    │
                  ┌─────────────────┼─────────────────┐
                  │                 │                 │
          [Full Payment]    [Partial Payments]  [Past Deadline]
                  │                 │                 │
                  ▼                 ▼                 ▼
             ┌────────┐       ┌────────┐       ┌───────────┐
             │ REPAID │       │ ACTIVE │       │ DEFAULTED │
             └────────┘       └────────┘       └───────────┘

Testing

Contract Tests (25 total)

  • Constructor & Setup (2 tests)
  • Apply Loan (4 tests)
  • Approve Loan (3 tests)
  • Reject Loan (1 test)
  • Disburse Loan (2 tests)
  • Make Payment (4 tests)
  • Check Default (2 tests)
  • View Functions (3 tests)
  • Admin Functions (4 tests)

Coverage: 100% function coverage

Run Tests

# All tests
forge test

# Specific test
forge test --match-test test_ApplyLoan

# With gas report
forge test --gas-report

# Coverage report
forge coverage

Gas Optimization

Custom Errors vs Require Strings

Method Gas Cost Savings
require("Error message") ~2,400 gas -
revert CustomError() ~200 gas ~2,200 gas (91%)

Total savings: ~17,600 gas across all error checks

Contract Deployment

  • Deployment Cost: ~6,013,379 gas (~0.48 MNT on Mantle Sepolia)
  • Contract Size: ~5.2 KB (well under 24KB limit)

Security Considerations

  1. Input Validation - All user inputs validated against min/max bounds
  2. Access Control - Admin functions properly protected with modifiers
  3. Custom Errors - Gas-efficient error handling
  4. Event Emission - All state changes emit events for transparency
  5. Fixed Parameters - Interest rate (5%) and duration (365 days) are constants
  6. Status Checks - Proper status validation in modifiers

Note: This is a testnet project for educational purposes. For mainnet deployment, a professional security audit is recommended.

Environment Variables

Root .env (for contract deployment)

PRIVATE_KEY=your_private_key_here
RPC_URL=https://rpc.sepolia.mantle.xyz
ETHERSCAN_API_KEY=                    # Optional

Frontend .env (optional - has defaults)

VITE_CONTRACT_ADDRESS=0x0AeC48e885a9ec762A2653cB8866e35f1CEAcc8d

Note: The frontend will use the hardcoded default if VITE_CONTRACT_ADDRESS is not set.

Resources

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing)
  5. Open a Pull Request

Author

Azhar Aditya Pratama

Built for HackQuest Indonesia: Co-Learning Camp 6 - Mantle

License

MIT License - See LICENSE file for details

Questions? Open an issue on GitHub!

Releases

Packages

Contributors

Languages