update all contracts

This commit is contained in:
osmannyildiz 2023-12-16 21:21:25 +03:00
parent 88c5aa6ec8
commit 868fab32c4
3 changed files with 165 additions and 81 deletions

74
contracts/CubLearn.sol Normal file
View File

@ -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);
}
}

18
contracts/DTLToken.sol Normal file
View File

@ -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());
}
}

View File

@ -8,100 +8,92 @@ import "@openzeppelin/contracts/utils/Base64.sol";
contract NftCertificate is ERC721 { contract NftCertificate is ERC721 {
using Strings for uint256; 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 struct CertificateInfo {
mapping(string => mapping(address => bool)) private issuedCertificates; string studentFullName;
string courseName;
string instructorFullName;
}
struct CertificateInfo { constructor() ERC721("CubLearn Certificate", "CUBCERT") {}
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.");
function mintCertificate(
address recipient,
string memory studentFullName,
string memory courseName,
string memory instructorFullName
) external {
uint256 tokenId = nextTokenId; uint256 tokenId = nextTokenId;
_storeCertificateInfo(tokenId, studentFullName, courseName, instructorFullName); _storeCertificateInfo(tokenId, studentFullName, courseName, instructorFullName);
_safeMint(msg.sender, tokenId); _safeMint(recipient, tokenId);
// Mark the certificate as issued nextTokenId++;
issuedCertificates[courseId][msg.sender] = true; }
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( function getCertificateInfo(uint256 tokenId)
uint256 tokenId, external
string memory studentFullName, view
string memory courseName, returns (
string memory instructorFullName CertificateInfo memory certInfo
) internal { )
certificateInfoMapping[tokenId] = CertificateInfo({ {
studentFullName: studentFullName, return certificateInfoMapping[tokenId];
courseName: courseName, }
instructorFullName: instructorFullName
});
}
function getCertificateInfo(uint256 tokenId)
external
view
returns (
CertificateInfo memory certInfo
)
{
return certificateInfoMapping[tokenId];
}
function _getSvg(uint256 tokenId) internal view returns (string memory) { function _getSvg(uint256 tokenId) internal view returns (string memory) {
CertificateInfo storage certInfo = certificateInfoMapping[tokenId]; CertificateInfo storage certInfo = certificateInfoMapping[tokenId];
string memory svg = string( string memory svg = string(
abi.encodePacked( abi.encodePacked(
unicode"data:image/svg+xml;utf8,<svg width='1024' height='1024' version='1.1' viewBox='0 0 270.93 270.93' xmlns='http://www.w3.org/2000/svg'><g stroke-width='1.75'><rect width='270.93' height='270.93' fill='#fff'/><text x='15.531887' y='33.715561' fill='#000000' font-family='Avenir' font-size='25.4px' letter-spacing='0px' xml:space='preserve'><tspan x='15.531887' y='33.715561' fill='#000000' font-family='Avenir' stroke-width='1.75'>Cub</tspan></text><text x='149.14455' y='33.867962' fill='#000000' font-family='Avenir' font-size='12.7px' letter-spacing='0px' xml:space='preserve'><tspan x='149.14455' y='33.867962' fill='#000000' font-family='Avenir' font-size='12.7px' stroke-width='1.75'>#", unicode"data:image/svg+xml;utf8,<svg width='1024' height='1024' version='1.1' viewBox='0 0 270.93 270.93' xmlns='http://www.w3.org/2000/svg'><g stroke-width='1.75'><rect width='270.93' height='270.93' fill='#fff'/><text x='15.531887' y='33.715561' fill='#000000' font-family='Avenir' font-size='25.4px' letter-spacing='0px' xml:space='preserve'><tspan x='15.531887' y='33.715561' fill='#000000' font-family='Avenir' stroke-width='1.75'>Cub</tspan></text><text x='149.14455' y='33.867962' fill='#000000' font-family='Avenir' font-size='12.7px' letter-spacing='0px' xml:space='preserve'><tspan x='149.14455' y='33.867962' fill='#000000' font-family='Avenir' font-size='12.7px' stroke-width='1.75'>#",
tokenId.toString(), tokenId.toString(),
unicode"</tspan></text><g font-family='Avenir' letter-spacing='0px'><text x='63.156933' y='33.715561' fill='#a11235' font-size='25.4px' xml:space='preserve'><tspan x='63.156933' y='33.715561' fill='#a11235' font-family='Avenir' stroke-width='1.75'>Learn</tspan></text><g><text x='16.209221' y='92.678009' fill='#a11235' font-size='11.289px' xml:space='preserve'><tspan x='16.209221' y='92.678009' font-size='11.289px' stroke-width='1.75'>ÖĞRENCİ</tspan></text><text x='15.531888' y='116.36742' fill='#000000' font-size='22.578px' xml:space='preserve'><tspan x='15.531888' y='116.36742' fill='#000000' font-size='22.578px' stroke-width='1.75'>", unicode"</tspan></text><g font-family='Avenir' letter-spacing='0px'><text x='63.156933' y='33.715561' fill='#a11235' font-size='25.4px' xml:space='preserve'><tspan x='63.156933' y='33.715561' fill='#a11235' font-family='Avenir' stroke-width='1.75'>Learn</tspan></text><g><text x='16.209221' y='92.678009' fill='#a11235' font-size='11.289px' xml:space='preserve'><tspan x='16.209221' y='92.678009' font-size='11.289px' stroke-width='1.75'>ÖĞRENCİ</tspan></text><text x='15.531888' y='116.36742' fill='#000000' font-size='22.578px' xml:space='preserve'><tspan x='15.531888' y='116.36742' fill='#000000' font-size='22.578px' stroke-width='1.75'>",
certInfo.studentFullName, certInfo.studentFullName,
"</tspan></text><text x='16.209221' y='143.1333' fill='#a11235' font-size='11.289px' xml:space='preserve'><tspan x='16.209221' y='143.1333' font-size='11.289px' stroke-width='1.75'>KURS</tspan></text><text x='15.531888' y='166.82274' fill='#000000' font-size='22.578px' xml:space='preserve'><tspan x='15.531888' y='166.82274' fill='#000000' font-size='22.578px' stroke-width='1.75'>", "</tspan></text><text x='16.209221' y='143.1333' fill='#a11235' font-size='11.289px' xml:space='preserve'><tspan x='16.209221' y='143.1333' font-size='11.289px' stroke-width='1.75'>KURS</tspan></text><text x='15.531888' y='166.82274' fill='#000000' font-size='22.578px' xml:space='preserve'><tspan x='15.531888' y='166.82274' fill='#000000' font-size='22.578px' stroke-width='1.75'>",
certInfo.courseName, certInfo.courseName,
unicode"</tspan></text><text x='16.209221' y='193.58873' fill='#a11235' font-size='11.289px' xml:space='preserve'><tspan x='16.209221' y='193.58873' font-size='11.289px' stroke-width='1.75'>EĞİTMEN</tspan></text><text x='15.531888' y='217.27815' fill='#000000' font-size='22.578px' xml:space='preserve'><tspan x='15.531888' y='217.27815' fill='#000000' font-size='22.578px' stroke-width='1.75'>", unicode"</tspan></text><text x='16.209221' y='193.58873' fill='#a11235' font-size='11.289px' xml:space='preserve'><tspan x='16.209221' y='193.58873' font-size='11.289px' stroke-width='1.75'>EĞİTMEN</tspan></text><text x='15.531888' y='217.27815' fill='#000000' font-size='22.578px' xml:space='preserve'><tspan x='15.531888' y='217.27815' fill='#000000' font-size='22.578px' stroke-width='1.75'>",
certInfo.instructorFullName, certInfo.instructorFullName,
"</tspan></text></g></g></g></svg>" "</tspan></text></g></g></g></svg>"
) )
); );
return svg; return svg;
} }
function tokenURI(uint256 tokenId) function tokenURI(uint256 tokenId)
external public
view view
override override
returns (string memory) returns (string memory)
{ {
bytes memory json = abi.encodePacked( bytes memory json = abi.encodePacked(
'{', '{',
'"name": "CubLearn Certificate #', tokenId.toString(), '",', '"name": "CubLearn Certificate #', tokenId.toString(), '",',
'"image_data": "', _getSvg(tokenId), '"', '"image_data": "', _getSvg(tokenId), '"',
'}' '}'
); );
return string( return string(
abi.encodePacked( abi.encodePacked(
"data:application/json;base64,", "data:application/json;base64,",
Base64.encode(json) Base64.encode(json)
) )
); );
} }
} }