Last active
May 15, 2023 07:42
-
-
Save ayo-klaytn/68431e14e7eff9de64e602a04215a11d to your computer and use it in GitHub Desktop.
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
// SPDX-License-Identifier: Unlicense | |
pragma solidity ^0.8.11; | |
import "@klaytn/contracts/KIP/token/KIP17/extensions/KIP17URIStorage.sol"; | |
import "@klaytn/contracts/utils/Counters.sol"; | |
import "@klaytn/contracts/utils/Strings.sol"; | |
import "@klaytn/contracts/utils/Base64.sol"; | |
// ====================== | |
// ====================== | |
// DYNAMIC ON-CHAIN NFTS (SVGS) | |
// ====================== | |
// ====================== | |
contract KlaytnOnchainNFT is KIP17URIStorage { | |
using Strings for uint256; | |
using Counters for Counters.Counter; | |
Counters.Counter private tokenIds; | |
address payable owner; | |
mapping (uint => uint) idToUpgradeFee; | |
mapping (uint => Details) idToDetails; | |
constructor() KIP17("Klaytn Onchain NFT", "KONFT") { | |
owner = payable(msg.sender); | |
} | |
struct Details { | |
string features; | |
string commonterms; | |
string ecosystem; | |
string experience; | |
uint randomFeature; | |
uint randomCommon; | |
uint randomEco; | |
} | |
// Return a random unique feature | |
function uniqueFeatures(uint _tokenId) | |
internal | |
{ | |
string[6] memory features = [ | |
"1-second block generation", | |
"EVM Compatibility", | |
"Fee delegation", | |
"4000 transaction per seconds", | |
"Low gas price ", | |
"Scaling Solutions - Service chains" | |
]; | |
uint randomSeed = uint( | |
keccak256(abi.encodePacked(msg.sender, block.timestamp)) | |
); | |
if(idToDetails[_tokenId].randomFeature == 0) { | |
uint random = (randomSeed % features.length); | |
idToDetails[_tokenId].features = features[random]; | |
idToDetails[_tokenId].randomFeature = random; | |
} | |
idToDetails[_tokenId].features = features[idToDetails[_tokenId].randomFeature]; | |
// return features[random]; | |
} | |
// Return a random common web3 term | |
function commonTerms(uint _tokenId) | |
internal | |
{ | |
string[10] memory common = [ | |
"KLAY", | |
"Metamask", | |
"EOA", | |
"Account Abstraction", | |
"Gas Fees", | |
"Cold Wallet", | |
"NFTs", | |
"KIP17", | |
"Private Key", | |
"IDE" | |
]; | |
uint randomSeed = uint( | |
keccak256(abi.encodePacked(msg.sender, block.timestamp)) | |
); | |
if(idToDetails[_tokenId].randomCommon == 0) { | |
uint random = (randomSeed % common.length); | |
idToDetails[_tokenId].commonterms = common[random]; | |
idToDetails[_tokenId].randomCommon = random; | |
} | |
idToDetails[_tokenId].commonterms = common[idToDetails[_tokenId].randomFeature]; | |
} | |
// Return a random klaytn ecosystem partner | |
function ecosystem(uint _tokenId) | |
internal | |
{ | |
string[10] memory eco = [ | |
"Safepal", | |
"Tatum", | |
"Orakl Network", | |
"Synapse", | |
"Ozys", | |
"Rabby Wallet", | |
"Witnet", | |
"ZKrypyo", | |
"Klap Protocol", | |
"Swapscanner" | |
]; | |
uint randomSeed = uint( | |
keccak256(abi.encodePacked(msg.sender, block.timestamp)) | |
); | |
if(idToDetails[_tokenId].randomEco == 0) { | |
uint random = (randomSeed % eco.length); | |
idToDetails[_tokenId].ecosystem = eco[random]; | |
idToDetails[_tokenId].randomEco = random; | |
} | |
idToDetails[_tokenId].ecosystem = eco[idToDetails[_tokenId].randomFeature]; | |
} | |
function generateCharacter(string memory _experience, uint tokenId) public returns (string memory) { | |
uniqueFeatures(tokenId); | |
ecosystem(tokenId); | |
commonTerms(tokenId); | |
bytes memory svg = abi.encodePacked( | |
'<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350">', | |
'<style>.base { fill: black; font-family: serif; font-size: 14px;}</style>', | |
'<rect width="100%" height="100%" fill="white" ry="40" rx="40" style="stroke:#FF2F00; stroke-width:5; opacity:0.9" />', | |
'<text x="50%" y="20%" class="base" dominant-baseline="middle" text-anchor="middle">',"Klaytn",'</text>', | |
'<text x="50%" y="30%" class="base" dominant-baseline="middle" text-anchor="middle">', idToDetails[tokenId].features ,'</text>', | |
'<text x="50%" y="40%" class="base" dominant-baseline="middle" text-anchor="middle">', idToDetails[tokenId].commonterms,'</text>', | |
'<text x="50%" y="50%" class="base" dominant-baseline="middle" text-anchor="middle">', idToDetails[tokenId].ecosystem,'</text>', | |
'<text x="50%" y="60%" class="base" dominant-baseline="middle" text-anchor="middle">', _experience , '</text>', | |
'<text x="1.2%" y="90%" class="base" dominant-baseline="middle" text-anchor="left" style="font-size:10px;"> '," Klaytn is an open source public blockchain designed for tommorrow's on-chain world ", '</text>', | |
'</svg>' | |
); | |
return string(abi.encodePacked("data:image/svg+xml;base64,", Base64.encode(svg))); | |
} | |
function getNftExperience(uint tokenId) public view returns (string memory) { | |
string memory experience = idToDetails[tokenId].experience; | |
return experience; | |
} | |
function getTokenURI(uint256 tokenId, string memory _experience) public returns (string memory){ | |
bytes memory dataURI = abi.encodePacked( | |
'{', | |
'"name": "Klaytn Onchain NFT #', tokenId.toString(), '",', | |
'"description": "Klaytn NFT on chain",', | |
'"image": "', generateCharacter(_experience, tokenId), '"', | |
'}' | |
); | |
return string( | |
abi.encodePacked( | |
"data:application/json;base64,", | |
Base64.encode(dataURI) | |
) | |
); | |
} | |
function mint() public { | |
tokenIds.increment(); | |
uint256 newItemId = tokenIds.current(); | |
_safeMint(msg.sender, newItemId); | |
idToDetails[newItemId].experience = "Beginner"; | |
_setTokenURI(newItemId, getTokenURI(newItemId, idToDetails[newItemId].experience)); | |
} | |
function upgrade(uint256 tokenId) public payable { | |
require(_exists(tokenId), "Please use an existing token"); | |
require(ownerOf(tokenId) == msg.sender, "You must own this token to train it"); | |
require(msg.value == 10 ether || msg.value == 50 ether); | |
if (msg.value == 10 ether) { | |
idToUpgradeFee[tokenId] = 10 ether; | |
idToDetails[tokenId].experience = "Intermediate"; | |
} else if (msg.value == 50 ether) { | |
idToUpgradeFee[tokenId] = 50 ether; | |
idToDetails[tokenId].experience = "Expert"; | |
} else { | |
idToDetails[tokenId].experience = "Beginner"; | |
} | |
string memory experience = getExperience(tokenId); | |
_setTokenURI(tokenId, getTokenURI(tokenId, experience)); | |
} | |
function getExperience(uint _tokenId) internal returns (string memory) { | |
// check if amount is == 10 Klay return Intermediate, amount == 50 Klay return Expert | |
if (idToUpgradeFee[_tokenId] == 0) { | |
return "Beginner"; | |
} else if(idToUpgradeFee[_tokenId] > 0 && idToUpgradeFee[_tokenId] == 10 ether) { | |
idToDetails[_tokenId].experience = "Intermediate"; | |
return "Intermediate"; | |
} else { | |
idToDetails[_tokenId].experience = "Expert"; | |
return "Expert"; | |
} | |
} | |
function withdraw() public { | |
require(owner.send(address(this).balance) ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment