This repository has been archived by the owner on Nov 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
315 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@openzeppelin/contracts=lib/openzeppelin-contracts/contracts |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; | ||
import "./interfaces/IUSDe.sol"; | ||
import "forge-std/console.sol"; //NOTE: testing only | ||
|
||
error InsufficientShares(); | ||
error InsufficientFunds(); | ||
error InsufficientBalance(); | ||
error OnlyOwner(); | ||
error DepositAmountZero(); | ||
error InsufficientYield(); | ||
|
||
contract EduenaEndowmentFund is ReentrancyGuard { | ||
using SafeERC20 for IERC20; | ||
|
||
address public owner; | ||
ISUSDe public sUSDe; | ||
IERC20 public USDe; | ||
uint256 public totalShares; | ||
uint256 public lastAssetValueInUSDe; | ||
uint256 public totalUnclaimedYield; | ||
mapping(address => uint256) public donorShares; | ||
|
||
event Deposit(address indexed donor, uint256 amount); | ||
event Stake(uint256 amount); | ||
event Withdraw(address indexed recipient, uint256 amount); | ||
event YieldUpdated(uint256 newAssetValueInUSDe, uint256 yield); | ||
|
||
constructor(address _USDeAddress, address _sUSDeAddress) { | ||
owner = msg.sender; | ||
USDe = IERC20(_USDeAddress); | ||
sUSDe = ISUSDe(_sUSDeAddress); | ||
} | ||
|
||
function poolBalance() public view returns (uint256) { | ||
return USDe.balanceOf(address(this)); | ||
} | ||
|
||
function deposit(uint256 amount) external nonReentrant { | ||
if (amount == 0) revert DepositAmountZero(); | ||
|
||
USDe.safeTransferFrom(msg.sender, address(this), amount); | ||
|
||
uint256 shares; | ||
if (totalShares == 0) { | ||
shares = amount; | ||
} else { | ||
shares = (amount * totalShares) / lastAssetValueInUSDe; | ||
} | ||
|
||
donorShares[msg.sender] += shares; | ||
totalShares += shares; | ||
emit Deposit(msg.sender, amount); | ||
|
||
_stake(amount); | ||
updateYield(); | ||
} | ||
|
||
function _stake(uint256 amount) internal { | ||
USDe.approve(address(sUSDe), amount); | ||
sUSDe.deposit(amount, address(this)); | ||
emit Stake(amount); | ||
} | ||
|
||
function withdraw(uint256 amount) external nonReentrant { | ||
uint256 shares = (amount * totalShares) / lastAssetValueInUSDe; | ||
if (donorShares[msg.sender] < shares) revert InsufficientShares(); | ||
|
||
uint256 previewAmount = sUSDe.previewRedeem(shares); | ||
if (previewAmount < amount) revert InsufficientFunds(); | ||
|
||
donorShares[msg.sender] -= shares; | ||
totalShares -= shares; | ||
|
||
//FIXME: Fix the withdraw to the donor as a sUSDe | ||
sUSDe.redeem(shares, msg.sender, address(this)); | ||
emit Withdraw(msg.sender, previewAmount); | ||
updateYield(); | ||
} | ||
|
||
//TODO: Implement the distribute function to distribute the returns to eligible students verified by scholarships creator | ||
//TODO: Use scholarship manager to handle the scholarship creation and verification | ||
function distribute(address payable student, uint256 amount) external { | ||
if (msg.sender != owner) revert OnlyOwner(); | ||
if (amount > totalUnclaimedYield) revert InsufficientYield(); | ||
|
||
uint256 sUSDeBalance = sUSDe.balanceOf(address(this)); | ||
if (amount > sUSDeBalance) revert InsufficientBalance(); | ||
|
||
uint256 previewAmount = sUSDe.previewRedeem(amount); | ||
// sUSDe.redeem(amount); | ||
USDe.safeTransfer(student, previewAmount); | ||
totalUnclaimedYield -= amount; | ||
|
||
emit Withdraw(student, previewAmount); | ||
updateYield(); | ||
} | ||
|
||
function updateYield() public { | ||
//todo: Implement the yield calculation | ||
uint256 sUSDeBalance = sUSDe.balanceOf(address(this)); | ||
|
||
uint256 assetValueInUSDe = sUSDe.previewDeposit(sUSDeBalance); | ||
lastAssetValueInUSDe = assetValueInUSDe; | ||
|
||
uint256 yield = assetValueInUSDe - lastAssetValueInUSDe; | ||
totalUnclaimedYield += yield; | ||
emit YieldUpdated(assetValueInUSDe, yield); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
contract ScholarshipManager { | ||
address public owner; | ||
uint256 public scholarshipCount; | ||
|
||
struct Scholarship { | ||
uint256 id; | ||
uint256 amount; | ||
string criteria; | ||
address[] applicants; | ||
mapping(address => bool) verifiedApplicants; | ||
mapping(address => bool) claimed; | ||
} | ||
|
||
mapping(uint256 => Scholarship) public scholarships; | ||
|
||
event ScholarshipCreated(uint256 indexed scholarshipId, uint256 amount, string criteria); | ||
event ScholarshipUpdated(uint256 indexed scholarshipId, uint256 amount, string criteria); | ||
event ScholarshipApplied(uint256 indexed scholarshipId, address indexed applicant); | ||
event ApplicantVerified(uint256 indexed scholarshipId, address indexed applicant); | ||
event ScholarshipClaimed(uint256 indexed scholarshipId, address indexed applicant); | ||
|
||
modifier onlyOwner() { | ||
require(msg.sender == owner, "Only owner can call this function"); | ||
_; | ||
} | ||
|
||
constructor() { | ||
owner = msg.sender; | ||
} | ||
|
||
function createScholarship(uint256 amount, string memory criteria) external onlyOwner { | ||
scholarshipCount++; | ||
Scholarship storage scholarship = scholarships[scholarshipCount]; | ||
scholarship.id = scholarshipCount; | ||
scholarship.amount = amount; | ||
scholarship.criteria = criteria; | ||
|
||
emit ScholarshipCreated(scholarshipCount, amount, criteria); | ||
} | ||
|
||
function updateScholarship(uint256 scholarshipId, uint256 amount, string memory criteria) external onlyOwner { | ||
Scholarship storage scholarship = scholarships[scholarshipId]; | ||
scholarship.amount = amount; | ||
scholarship.criteria = criteria; | ||
|
||
emit ScholarshipUpdated(scholarshipId, amount, criteria); | ||
} | ||
|
||
function getScholarshipDetails(uint256 scholarshipId) external view returns (uint256, uint256, string memory, address[] memory) { | ||
Scholarship storage scholarship = scholarships[scholarshipId]; | ||
return (scholarship.id, scholarship.amount, scholarship.criteria, scholarship.applicants); | ||
} | ||
|
||
function applyForScholarship(uint256 scholarshipId) external { | ||
Scholarship storage scholarship = scholarships[scholarshipId]; | ||
scholarship.applicants.push(msg.sender); | ||
|
||
emit ScholarshipApplied(scholarshipId, msg.sender); | ||
} | ||
|
||
function verifyApplicant(address applicant, uint256 scholarshipId) external onlyOwner { | ||
Scholarship storage scholarship = scholarships[scholarshipId]; | ||
scholarship.verifiedApplicants[applicant] = true; | ||
|
||
emit ApplicantVerified(scholarshipId, applicant); | ||
} | ||
|
||
function getApplicantStatus(address applicant, uint256 scholarshipId) external view returns (bool) { | ||
Scholarship storage scholarship = scholarships[scholarshipId]; | ||
return scholarship.verifiedApplicants[applicant]; | ||
} | ||
|
||
function claimScholarship(uint256 scholarshipId) external { | ||
Scholarship storage scholarship = scholarships[scholarshipId]; | ||
require(scholarship.verifiedApplicants[msg.sender], "Applicant not verified"); | ||
require(!scholarship.claimed[msg.sender], "Scholarship already claimed"); | ||
|
||
scholarship.claimed[msg.sender] = true; | ||
|
||
emit ScholarshipClaimed(scholarshipId, msg.sender); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
interface ISUSDe { | ||
function approve(address spender, uint256 amount) external; | ||
|
||
function transfer( | ||
address to, | ||
uint256 amount | ||
) external returns (uint256); | ||
|
||
function deposit( | ||
uint256 assets, | ||
address receiver | ||
) external returns (uint256); | ||
|
||
function redeem( | ||
uint256 shares, | ||
address receiver, | ||
address _owner | ||
) external returns (uint256); | ||
|
||
function previewRedeem(uint256 shares) external view returns (uint256); | ||
function previewDeposit(uint256 assets) external view returns (uint256); | ||
|
||
function balanceOf(address account) external view returns (uint256); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; | ||
|
||
contract MockSUSDe is ERC4626 { | ||
constructor( | ||
ERC20 _usdeToken | ||
) ERC4626(_usdeToken) ERC20("Mock Staked USDe", "MSUSDe") {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
|
||
contract MockUSDe is ERC20 { | ||
constructor() ERC20("Mock USDe", "mUSDe") {} | ||
|
||
function mint(address to, uint256 amount) external { | ||
_mint(to, amount); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.