Student Loan Smart Agreement

What it does:
Automates issuance, repayment, and tracking of student loans on-chain with transparent terms and schedules.

Why it matters:
Reduces administrative friction, ensures clear repayment obligations, provides transparent audit trails, and allows instant verification of loan status.

How it works:

  • Lender or institution funds the loan pool on-chain

  • Student applies for a loan, specifying amount and repayment terms

  • Loan agreement is stored on-chain with interest rate, repayment schedule, and collateral (if any)

  • Smart contract tracks repayment due dates and amounts

  • Students make repayments directly to the contract

  • Contract automatically updates loan balance and can trigger penalties for late payments

  • Full loan history, balance, and status are auditable on-chain

      // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title StudentLoanAgreement
 * @author Nam
 * @notice Automates issuance, repayment, and tracking of student loans
 */
contract StudentLoanAgreement {

    address public lender;
    uint256 public loanCount;

    struct Loan {
        address student;
        uint256 principal;
        uint256 interest; // simple interest in wei
        uint256 totalOwed;
        uint256 repaid;
        uint256 dueDate;
        bool active;
    }

    mapping(uint256 => Loan) public loans;

    // -------------------- EVENTS --------------------

    event LoanIssued(uint256 indexed loanId, address indexed student, uint256 principal, uint256 totalOwed, uint256 dueDate);
    event PaymentMade(uint256 indexed loanId, address indexed student, uint256 amount);
    event LoanClosed(uint256 indexed loanId, address indexed student);

    // -------------------- MODIFIERS --------------------

    modifier onlyLender() {
        require(msg.sender == lender, "Not lender");
        _;
    }

    modifier onlyStudent(uint256 _loanId) {
        require(msg.sender == loans[_loanId].student, "Not borrower");
        _;
    }

    modifier loanActive(uint256 _loanId) {
        require(loans[_loanId].active, "Loan inactive");
        _;
    }

    // -------------------- CONSTRUCTOR --------------------

    constructor() {
        lender = msg.sender;
    }

    // -------------------- LOAN MANAGEMENT --------------------

    function issueLoan(address _student, uint256 _principal, uint256 _interest, uint256 _repaymentDuration) external onlyLender {
        require(_student != address(0), "Invalid student");
        require(_principal > 0, "Principal must be >0");

        loanCount += 1;
        uint256 totalOwed = _principal + _interest;
        uint256 dueDate = block.timestamp + _repaymentDuration;

        loans[loanCount] = Loan({
            student: _student,
            principal: _principal,
            interest: _interest,
            totalOwed: totalOwed,
            repaid: 0,
            dueDate: dueDate,
            active: true
        });

        emit LoanIssued(loanCount, _student, _principal, totalOwed, dueDate);
    }

    function makePayment(uint256 _loanId) external payable onlyStudent(_loanId) loanActive(_loanId) {
        Loan storage l = loans[_loanId];
        require(msg.value > 0, "Payment must be >0");
        require(l.repaid + msg.value = l.totalOwed) {
            l.active = false;
            emit LoanClosed(_loanId, msg.sender);
        }
    }

    // -------------------- HELPER FUNCTIONS --------------------

    function getOutstanding(uint256 _loanId) external view returns (uint256) {
        Loan memory l = loans[_loanId];
        return l.totalOwed - l.repaid;
    }

    function isLoanOverdue(uint256 _loanId) external view returns (bool) {
        Loan memory l = loans[_loanId];
        return l.active && block.timestamp > l.dueDate;
    }

    receive() external payable {}
}