Tuition Payment Escrow

What it does:
Holds tuition payments in escrow until academic milestones or enrollment confirmations are met, then releases funds to the educational institution.

Why it matters:
Protects students from paying upfront for incomplete or unverified services, ensures institutions receive guaranteed payments upon delivery, and creates a transparent, auditable payment record.

How it works:

  • Student deposits tuition into the escrow contract

  • Education institution registers enrollment or course milestones on-chain

  • Contract verifies milestone completion (e.g., course start, semester completion)

  • Funds are automatically released to the institution once conditions are met

  • Students or institutions can dispute or pause payment under predefined rules

  • Full transaction history is permanently recorded on-chain

  • Unused or refundable funds can be returned to the student

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

/**
 * @title TuitionPaymentEscrow
 * @author Nam
 * @notice Escrow for tuition payments with milestone-based release
 */
contract TuitionPaymentEscrow {

    // -------------------- ROLES --------------------

    address public admin;

    // -------------------- STRUCTS --------------------

    struct Escrow {
        address student;
        address institution;
        uint256 amount;
        uint256 milestone; // example: block.timestamp for milestone
        bool released;
        bool active;
    }

    mapping(uint256 => Escrow) public escrows;
    uint256 public escrowCount;

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

    event TuitionDeposited(uint256 indexed escrowId, address indexed student, uint256 amount);
    event TuitionReleased(uint256 indexed escrowId, address indexed institution, uint256 amount);
    event EscrowCanceled(uint256 indexed escrowId, address indexed student);

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

    modifier onlyAdmin() {
        require(msg.sender == admin, "Not admin");
        _;
    }

    modifier escrowActive(uint256 _escrowId) {
        require(escrows[_escrowId].active, "Escrow inactive");
        _;
    }

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

    constructor() {
        admin = msg.sender;
    }

    // -------------------- ESCROW MANAGEMENT --------------------

    /**
     * @notice Deposit tuition into escrow
     */
    function depositTuition(address _institution, uint256 _milestone) external payable {
        require(msg.value > 0, "No funds sent");
        require(_institution != address(0), "Invalid institution");

        escrowCount += 1;
        escrows[escrowCount] = Escrow({
            student: msg.sender,
            institution: _institution,
            amount: msg.value,
            milestone: _milestone,
            released: false,
            active: true
        });

        emit TuitionDeposited(escrowCount, msg.sender, msg.value);
    }

    /**
     * @notice Release tuition to institution upon milestone completion
     */
    function releaseTuition(uint256 _escrowId) external escrowActive(_escrowId) {
        Escrow storage e = escrows[_escrowId];
        require(block.timestamp >= e.milestone, "Milestone not reached");
        require(!e.released, "Already released");

        e.released = true;
        e.active = false;
        payable(e.institution).transfer(e.amount);

        emit TuitionReleased(_escrowId, e.institution, e.amount);
    }

    /**
     * @notice Cancel escrow and refund student
     */
    function cancelEscrow(uint256 _escrowId) external escrowActive(_escrowId) {
        Escrow storage e = escrows[_escrowId];
        require(msg.sender == e.student, "Not student");
        require(!e.released, "Already released");

        e.active = false;
        payable(e.student).transfer(e.amount);

        emit EscrowCanceled(_escrowId, e.student);
    }

    // -------------------- FUNDING RECEIVED --------------------

    receive() external payable {}
}