Skip to content

Instantly share code, notes, and snippets.

@ayo-klaytn
Last active May 15, 2023 07:42
Show Gist options
  • Save ayo-klaytn/68431e14e7eff9de64e602a04215a11d to your computer and use it in GitHub Desktop.
Save ayo-klaytn/68431e14e7eff9de64e602a04215a11d to your computer and use it in GitHub Desktop.
// 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