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 {}
}