diff --git a/contracts/CubLearn.sol b/contracts/CubLearn.sol new file mode 100644 index 0000000..3422ed9 --- /dev/null +++ b/contracts/CubLearn.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./DTLToken.sol"; +import "./NftCertificate.sol"; + +contract CubLearn is Ownable { + DTLToken dtlContract; + NftCertificate cubcertContract; + + uint256 public cashbackPercentage; + + // course id => price in DTL + mapping(string => uint256) private coursePrices; + + // course id => student address => is enrolled + mapping(string => mapping(address => bool)) private enrolledCourses; + + // course id => student address => is certificate issued + mapping(string => mapping(address => bool)) private issuedCertificates; + + constructor(address dtlContractAddress, address cubcertContractAddress) Ownable(msg.sender) { + dtlContract = DTLToken(dtlContractAddress); + cubcertContract = NftCertificate(cubcertContractAddress); + + coursePrices["1"] = 300; + coursePrices["2"] = 500; + coursePrices["3"] = 200; + cashbackPercentage = 50; + } + + function setCashbackPercentage(uint256 newValue) external onlyOwner { + require(newValue <= 100, "Cashback percentage cannot be more than 100."); + + cashbackPercentage = newValue; + } + + function enroll(string memory courseId) external { + require(coursePrices[courseId] != 0, "Course not found."); + + dtlContract.transferFrom(msg.sender, address(this), coursePrices[courseId]); + + enrolledCourses[courseId][msg.sender] = true; + } + + function finishCourse( + string memory courseId, + string memory studentFullName, + string memory courseName, + string memory instructorFullName + ) external { + require(enrolledCourses[courseId][msg.sender], "Must be enrolled in course."); + require(!issuedCertificates[courseId][msg.sender], "Certificate already issued."); + + cubcertContract.mintCertificate(msg.sender, studentFullName, courseName, instructorFullName); + + // Mark the certificate as issued + issuedCertificates[courseId][msg.sender] = true; + + // Cashback + uint256 cashbackAmount = coursePrices[courseId] * cashbackPercentage / 100; + dtlContract.transfer(msg.sender, cashbackAmount); + } + + function getDTLBalance() external view onlyOwner returns (uint256) { + return dtlContract.balanceOf(address(this)); + } + + function transferAllDTLBalanceToMe() external onlyOwner { + uint256 balance = dtlContract.balanceOf(address(this)); + dtlContract.transfer(msg.sender, balance); + } +} diff --git a/contracts/DTLToken.sol b/contracts/DTLToken.sol new file mode 100644 index 0000000..d8b2a0c --- /dev/null +++ b/contracts/DTLToken.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract DTLToken is ERC20 { + constructor(address initialHolder) ERC20("Digital Turkish Lira", "DTL") { + _mint(initialHolder, 1000000000); + } + + function decimals() public view virtual override returns (uint8) { + return 0; + } + + function approveMax(address spender) external returns (bool) { + return approve(spender, totalSupply()); + } +} diff --git a/contracts/NftCertificate.sol b/contracts/NftCertificate.sol index 9619bd6..235db56 100644 --- a/contracts/NftCertificate.sol +++ b/contracts/NftCertificate.sol @@ -8,100 +8,92 @@ import "@openzeppelin/contracts/utils/Base64.sol"; contract NftCertificate is ERC721 { using Strings for uint256; - uint256 public nextTokenId; + uint256 public nextTokenId; - mapping(uint256 => CertificateInfo) private certificateInfoMapping; + mapping(uint256 => CertificateInfo) private certificateInfoMapping; - // course id => student address => is cert issued - mapping(string => mapping(address => bool)) private issuedCertificates; + struct CertificateInfo { + string studentFullName; + string courseName; + string instructorFullName; + } - struct CertificateInfo { - string studentFullName; - string courseName; - string instructorFullName; - } - - constructor() ERC721("CubLearn Certificate", "CUBCERT") {} - - function mintCertificate( - string memory courseId, - string memory studentFullName, - string memory courseName, - string memory instructorFullName - ) external { - require(!issuedCertificates[courseId][msg.sender], "Certificate already issued."); + constructor() ERC721("CubLearn Certificate", "CUBCERT") {} + function mintCertificate( + address recipient, + string memory studentFullName, + string memory courseName, + string memory instructorFullName + ) external { uint256 tokenId = nextTokenId; - + _storeCertificateInfo(tokenId, studentFullName, courseName, instructorFullName); - _safeMint(msg.sender, tokenId); + _safeMint(recipient, tokenId); - // Mark the certificate as issued - issuedCertificates[courseId][msg.sender] = true; + nextTokenId++; + } - nextTokenId++; - } + function _storeCertificateInfo( + uint256 tokenId, + string memory studentFullName, + string memory courseName, + string memory instructorFullName + ) internal { + certificateInfoMapping[tokenId] = CertificateInfo({ + studentFullName: studentFullName, + courseName: courseName, + instructorFullName: instructorFullName + }); + } - function _storeCertificateInfo( - uint256 tokenId, - string memory studentFullName, - string memory courseName, - string memory instructorFullName - ) internal { - certificateInfoMapping[tokenId] = CertificateInfo({ - studentFullName: studentFullName, - courseName: courseName, - instructorFullName: instructorFullName - }); - } - - function getCertificateInfo(uint256 tokenId) - external - view - returns ( - CertificateInfo memory certInfo - ) - { - return certificateInfoMapping[tokenId]; - } + function getCertificateInfo(uint256 tokenId) + external + view + returns ( + CertificateInfo memory certInfo + ) + { + return certificateInfoMapping[tokenId]; + } function _getSvg(uint256 tokenId) internal view returns (string memory) { - CertificateInfo storage certInfo = certificateInfoMapping[tokenId]; - string memory svg = string( - abi.encodePacked( - unicode"data:image/svg+xml;utf8,Cub#", - tokenId.toString(), - unicode"LearnÖĞRENCİ", - certInfo.studentFullName, - "KURS", - certInfo.courseName, - unicode"EĞİTMEN", - certInfo.instructorFullName, - "" - ) - ); - return svg; - } + CertificateInfo storage certInfo = certificateInfoMapping[tokenId]; + string memory svg = string( + abi.encodePacked( + unicode"data:image/svg+xml;utf8,Cub#", + tokenId.toString(), + unicode"LearnÖĞRENCİ", + certInfo.studentFullName, + "KURS", + certInfo.courseName, + unicode"EĞİTMEN", + certInfo.instructorFullName, + "" + ) + ); + return svg; + } function tokenURI(uint256 tokenId) - external - view - override - returns (string memory) - { - bytes memory json = abi.encodePacked( - '{', - '"name": "CubLearn Certificate #', tokenId.toString(), '",', - '"image_data": "', _getSvg(tokenId), '"', - '}' - ); + public + view + override + returns (string memory) + { + bytes memory json = abi.encodePacked( + '{', + '"name": "CubLearn Certificate #', tokenId.toString(), '",', + '"image_data": "', _getSvg(tokenId), '"', + '}' + ); - return string( - abi.encodePacked( - "data:application/json;base64,", - Base64.encode(json) - ) - ); - } + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode(json) + ) + ); + } }