mirror of
https://github.com/rjNemo/epicNFT
synced 2026-06-12 12:46:39 +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.
|
Demo NFT collection for learning purposes.
|
||||||
|
|
||||||
## OPenSea Testnet
|
## OpenSea Testnet
|
||||||
1. https://testnets.opensea.io/collection/squarenft-cd2xk3yh7v
|
|
||||||
2. https://testnets.opensea.io/collection/squarenft-bndes4idpq
|
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
|
## Square NFT
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ pragma solidity ^0.8.0;
|
||||||
import "hardhat/console.sol";
|
import "hardhat/console.sol";
|
||||||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
|
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
|
||||||
import "@openzeppelin/contracts/utils/Counters.sol";
|
import "@openzeppelin/contracts/utils/Counters.sol";
|
||||||
|
import "../lib/Base64.sol";
|
||||||
|
|
||||||
contract EpicNFT is ERC721URIStorage {
|
contract EpicNFT is ERC721URIStorage {
|
||||||
using Counters for Counters.Counter;
|
using Counters for Counters.Counter;
|
||||||
|
|
@ -13,14 +14,129 @@ contract EpicNFT is ERC721URIStorage {
|
||||||
console.log("My first NFT contract! EPIC!!!");
|
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 {
|
function mint() public {
|
||||||
uint256 tokenID = _tokenIds.current();
|
uint256 tokenID = _tokenIds.current();
|
||||||
_safeMint(msg.sender, tokenID);
|
|
||||||
_setTokenURI(
|
string memory color = pickRandomWord(colors, "color", tokenID);
|
||||||
tokenID,
|
string memory first = pickRandomWord(levels, "first", tokenID);
|
||||||
"data:application/json;base64,ewogICAgIm5hbWUiOiAiRXBpY0xvcmRIYW1idXJnZXIiLAogICAgImRlc2NyaXB0aW9uIjogIkFuIE5GVCBmcm9tIHRoZSBoaWdobHkgYWNjbGFpbWVkIHNxdWFyZSBjb2xsZWN0aW9uIiwKICAgICJpbWFnZSI6ICJkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSEJ5WlhObGNuWmxRWE53WldOMFVtRjBhVzg5SW5oTmFXNVpUV2x1SUcxbFpYUWlJSFpwWlhkQ2IzZzlJakFnTUNBek5UQWdNelV3SWo0TkNpQWdJQ0E4YzNSNWJHVStMbUpoYzJVZ2V5Qm1hV3hzT2lCM2FHbDBaVHNnWm05dWRDMW1ZVzFwYkhrNklITmxjbWxtT3lCbWIyNTBMWE5wZW1VNklERTBjSGc3SUgwOEwzTjBlV3hsUGcwS0lDQWdJRHh5WldOMElIZHBaSFJvUFNJeE1EQWxJaUJvWldsbmFIUTlJakV3TUNVaUlHWnBiR3c5SW1Kc1lXTnJJaUF2UGcwS0lDQWdJRHgwWlhoMElIZzlJalV3SlNJZ2VUMGlOVEFsSWlCamJHRnpjejBpWW1GelpTSWdaRzl0YVc1aGJuUXRZbUZ6Wld4cGJtVTlJbTFwWkdSc1pTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0krUlhCcFkweHZjbVJJWVcxaWRYSm5aWEk4TDNSbGVIUStEUW84TDNOMlp6ND0iCn0="
|
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);
|
console.log("NFT %s minted to %s", tokenID, msg.sender);
|
||||||
_tokenIds.increment();
|
_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