mirror of
https://github.com/rjNemo/epicNFT
synced 2026-06-06 01:46:38 +00:00
deploy dynamic NFTs
This commit is contained in:
parent
333b90241d
commit
541495ac89
3 changed files with 204 additions and 7 deletions
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
Demo NFT collection for learning purposes.
|
||||
|
||||
## OPenSea Testnet
|
||||
1. https://testnets.opensea.io/collection/squarenft-cd2xk3yh7v
|
||||
2. https://testnets.opensea.io/collection/squarenft-bndes4idpq
|
||||
## OpenSea Testnet
|
||||
|
||||
1. https://testnets.opensea.io/collection/squarenft-cd2xk3yh7v
|
||||
2. https://testnets.opensea.io/collection/squarenft-bndes4idpq
|
||||
3. https://testnets.opensea.io/collection/squarenft-lemz9demvy
|
||||
4. https://testnets.opensea.io/collection/squarenft-1xkwn34mdz
|
||||
|
||||
## Square NFT
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ pragma solidity ^0.8.0;
|
|||
import "hardhat/console.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
|
||||
import "@openzeppelin/contracts/utils/Counters.sol";
|
||||
import "../lib/Base64.sol";
|
||||
|
||||
contract EpicNFT is ERC721URIStorage {
|
||||
using Counters for Counters.Counter;
|
||||
|
|
@ -13,14 +14,129 @@ contract EpicNFT is ERC721URIStorage {
|
|||
console.log("My first NFT contract! EPIC!!!");
|
||||
}
|
||||
|
||||
string baseSvg1 =
|
||||
"<svg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='xMinYMin meet' viewBox='0 0 350 350'><style>.base { fill:";
|
||||
|
||||
string baseSvg2 =
|
||||
"; font-family: serif; font-size: 24px; }</style><rect width='100%' height='100%' fill='black' /><text x='50%' y='50%' class='base' dominant-baseline='middle' text-anchor='middle'>";
|
||||
|
||||
string[] colors = [
|
||||
"red",
|
||||
"green",
|
||||
"blue",
|
||||
"white",
|
||||
"yellow",
|
||||
"cyan",
|
||||
"pink",
|
||||
"magenta",
|
||||
"silver",
|
||||
"gold"
|
||||
];
|
||||
|
||||
string[] levels = [
|
||||
"Epic",
|
||||
"Legendary",
|
||||
"Heroic",
|
||||
"Cool",
|
||||
"Fantastic",
|
||||
"Terrible",
|
||||
"Crazy",
|
||||
"Wild",
|
||||
"Terrifying",
|
||||
"Spooky"
|
||||
];
|
||||
|
||||
string[] classes = [
|
||||
"Assassin",
|
||||
"Cleric",
|
||||
"Rogue",
|
||||
"Ninja",
|
||||
"Lord",
|
||||
"Wizard",
|
||||
"Warrior",
|
||||
"Berserker",
|
||||
"Necromander",
|
||||
"Summoner",
|
||||
"Bard",
|
||||
"Lancer"
|
||||
];
|
||||
|
||||
string[] jobs = [
|
||||
"Soldier",
|
||||
"Healer",
|
||||
"Explorer",
|
||||
"Merchant",
|
||||
"Developer",
|
||||
"BlackSmith",
|
||||
"Hitman",
|
||||
"Cook",
|
||||
"Hunter",
|
||||
"Sailor"
|
||||
];
|
||||
|
||||
function mint() public {
|
||||
uint256 tokenID = _tokenIds.current();
|
||||
_safeMint(msg.sender, tokenID);
|
||||
_setTokenURI(
|
||||
tokenID,
|
||||
"data:application/json;base64,ewogICAgIm5hbWUiOiAiRXBpY0xvcmRIYW1idXJnZXIiLAogICAgImRlc2NyaXB0aW9uIjogIkFuIE5GVCBmcm9tIHRoZSBoaWdobHkgYWNjbGFpbWVkIHNxdWFyZSBjb2xsZWN0aW9uIiwKICAgICJpbWFnZSI6ICJkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSEJ5WlhObGNuWmxRWE53WldOMFVtRjBhVzg5SW5oTmFXNVpUV2x1SUcxbFpYUWlJSFpwWlhkQ2IzZzlJakFnTUNBek5UQWdNelV3SWo0TkNpQWdJQ0E4YzNSNWJHVStMbUpoYzJVZ2V5Qm1hV3hzT2lCM2FHbDBaVHNnWm05dWRDMW1ZVzFwYkhrNklITmxjbWxtT3lCbWIyNTBMWE5wZW1VNklERTBjSGc3SUgwOEwzTjBlV3hsUGcwS0lDQWdJRHh5WldOMElIZHBaSFJvUFNJeE1EQWxJaUJvWldsbmFIUTlJakV3TUNVaUlHWnBiR3c5SW1Kc1lXTnJJaUF2UGcwS0lDQWdJRHgwWlhoMElIZzlJalV3SlNJZ2VUMGlOVEFsSWlCamJHRnpjejBpWW1GelpTSWdaRzl0YVc1aGJuUXRZbUZ6Wld4cGJtVTlJbTFwWkdSc1pTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0krUlhCcFkweHZjbVJJWVcxaWRYSm5aWEk4TDNSbGVIUStEUW84TDNOMlp6ND0iCn0="
|
||||
|
||||
string memory color = pickRandomWord(colors, "color", tokenID);
|
||||
string memory first = pickRandomWord(levels, "first", tokenID);
|
||||
string memory second = pickRandomWord(classes, "second", tokenID);
|
||||
string memory third = pickRandomWord(jobs, "third", tokenID);
|
||||
string memory finalWord = string(
|
||||
abi.encodePacked(color, first, second, third)
|
||||
);
|
||||
string memory finalSvg = string(
|
||||
abi.encodePacked(
|
||||
baseSvg1,
|
||||
color,
|
||||
baseSvg2,
|
||||
first,
|
||||
second,
|
||||
third,
|
||||
"</text></svg>"
|
||||
)
|
||||
);
|
||||
|
||||
string memory json = Base64.encode(
|
||||
bytes(
|
||||
string(
|
||||
abi.encodePacked(
|
||||
'{"name": "',
|
||||
finalWord,
|
||||
'", "description": "A highly acclaimed collection of squares.", "image": "data:image/svg+xml;base64,',
|
||||
Base64.encode(bytes(finalSvg)),
|
||||
'"}'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
string memory tokenUri = string(
|
||||
abi.encodePacked("data:application/json;base64,", json)
|
||||
);
|
||||
|
||||
console.log("\n--------------------");
|
||||
console.log(tokenUri);
|
||||
console.log("--------------------\n");
|
||||
|
||||
_safeMint(msg.sender, tokenID);
|
||||
_setTokenURI(tokenID, tokenUri);
|
||||
console.log("NFT %s minted to %s", tokenID, msg.sender);
|
||||
_tokenIds.increment();
|
||||
}
|
||||
|
||||
function pickRandomWord(
|
||||
string[] memory words,
|
||||
string memory position,
|
||||
uint256 tokenID
|
||||
) public pure returns (string memory) {
|
||||
uint256 rand = random(
|
||||
string(abi.encodePacked(position, Strings.toString(tokenID)))
|
||||
);
|
||||
rand = rand % words.length;
|
||||
return words[rand];
|
||||
}
|
||||
|
||||
function random(string memory input) internal pure returns (uint256) {
|
||||
return uint256(keccak256(abi.encodePacked(input)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
78
lib/Base64.sol
Normal file
78
lib/Base64.sol
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
*Submitted for verification at Etherscan.io on 2021-09-05
|
||||
*/
|
||||
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
/// [MIT License]
|
||||
/// @title Base64
|
||||
/// @notice Provides a function for encoding some bytes in base64
|
||||
/// @author Brecht Devos <brecht@loopring.org>
|
||||
library Base64 {
|
||||
bytes internal constant TABLE =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/// @notice Encodes some bytes to the base64 representation
|
||||
function encode(bytes memory data) internal pure returns (string memory) {
|
||||
uint256 len = data.length;
|
||||
if (len == 0) return "";
|
||||
|
||||
// multiply by 4/3 rounded up
|
||||
uint256 encodedLen = 4 * ((len + 2) / 3);
|
||||
|
||||
// Add some extra buffer at the end
|
||||
bytes memory result = new bytes(encodedLen + 32);
|
||||
|
||||
bytes memory table = TABLE;
|
||||
|
||||
assembly {
|
||||
let tablePtr := add(table, 1)
|
||||
let resultPtr := add(result, 32)
|
||||
|
||||
for {
|
||||
let i := 0
|
||||
} lt(i, len) {
|
||||
|
||||
} {
|
||||
i := add(i, 3)
|
||||
let input := and(mload(add(data, i)), 0xffffff)
|
||||
|
||||
let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))
|
||||
out := shl(8, out)
|
||||
out := add(
|
||||
out,
|
||||
and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)
|
||||
)
|
||||
out := shl(8, out)
|
||||
out := add(
|
||||
out,
|
||||
and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)
|
||||
)
|
||||
out := shl(8, out)
|
||||
out := add(
|
||||
out,
|
||||
and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)
|
||||
)
|
||||
out := shl(224, out)
|
||||
|
||||
mstore(resultPtr, out)
|
||||
|
||||
resultPtr := add(resultPtr, 4)
|
||||
}
|
||||
|
||||
switch mod(len, 3)
|
||||
case 1 {
|
||||
mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
|
||||
}
|
||||
case 2 {
|
||||
mstore(sub(resultPtr, 1), shl(248, 0x3d))
|
||||
}
|
||||
|
||||
mstore(result, encodedLen)
|
||||
}
|
||||
|
||||
return string(result);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue