Skip to content

Instantly share code, notes, and snippets.

@farzaa
Last active November 19, 2022 22:44
Show Gist options
  • Save farzaa/dc45da3eb91a41913767f3eb4d7830f1 to your computer and use it in GitHub Desktop.
Save farzaa/dc45da3eb91a41913767f3eb4d7830f1 to your computer and use it in GitHub Desktop.
pragma solidity 0.8.0;
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "hardhat/console.sol";
// We need to import the helper functions from the contract that we copy/pasted.
import { Base64 } from "./libraries/Base64.sol";
contract MyEpicNFT is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
string baseSvg = "<svg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='xMinYMin meet' viewBox='0 0 350 350'><style>.base { fill: white; 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[] firstWords = ["YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD"];
string[] secondWords = ["YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD"];
string[] thirdWords = ["YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD", "YOUR_WORD"];
constructor() ERC721 ("SquareNFT", "SQUARE") {
console.log("This is my NFT contract. Woah!");
}
function pickRandomFirstWord(uint256 tokenId) public view returns (string memory) {
uint256 rand = random(string(abi.encodePacked("FIRST_WORD", Strings.toString(tokenId))));
rand = rand % firstWords.length;
return firstWords[rand];
}
function pickRandomSecondWord(uint256 tokenId) public view returns (string memory) {
uint256 rand = random(string(abi.encodePacked("SECOND_WORD", Strings.toString(tokenId))));
rand = rand % secondWords.length;
return secondWords[rand];
}
function pickRandomThirdWord(uint256 tokenId) public view returns (string memory) {
uint256 rand = random(string(abi.encodePacked("THIRD_WORD", Strings.toString(tokenId))));
rand = rand % thirdWords.length;
return thirdWords[rand];
}
function random(string memory input) internal pure returns (uint256) {
return uint256(keccak256(abi.encodePacked(input)));
}
function makeAnEpicNFT() public {
uint256 newItemId = _tokenIds.current();
string memory first = pickRandomFirstWord(newItemId);
string memory second = pickRandomSecondWord(newItemId);
string memory third = pickRandomThirdWord(newItemId);
string memory combinedWord = string(abi.encodePacked(first, second, third));
string memory finalSvg = string(abi.encodePacked(baseSvg, combinedWord, "</text></svg>"));
// Get all the JSON metadata in place and base64 encode it.
string memory json = Base64.encode(
bytes(
string(
abi.encodePacked(
'{"name": "',
// We set the title of our NFT as the generated word.
combinedWord,
'", "description": "A highly acclaimed collection of squares.", "image": "data:image/svg+xml;base64,',
// We add data:image/svg+xml;base64 and then append our base64 encode our svg.
Base64.encode(bytes(finalSvg)),
'"}'
)
)
)
);
// Just like before, we prepend data:application/json;base64, to our data.
string memory finalTokenUri = string(
abi.encodePacked("data:application/json;base64,", json)
);
console.log("\n--------------------");
console.log(finalTokenUri);
console.log("--------------------\n");
_safeMint(msg.sender, newItemId);
// Update your URI!!!
_setTokenURI(newItemId, finalTokenUri);
_tokenIds.increment();
console.log("An NFT w/ ID %s has been minted to %s", newItemId, msg.sender);
}
}
@stefanrows
Copy link

Using pragma solidity 0.8.0; on VSCode with WSL 2 throws an error.

Changing it to pragma solidity ^0.8.0; works for me.

Greets,
Stefan

@zeuslawyer
Copy link

@farzaa, for line 59, abi.encodePacked returns bytes - so I dont think we need to cast to string and then cast again to bytes?

I tried running the below locally on hardhat and it compiled and ran fine (using the run.js script).

thoughts?

string memory json = Base64.encode(
            abi.encodePacked(
                '{"name": "',
                // We set the title of our NFT as the generated word.
                combinedWord,
                '", "description": "A highly acclaimed collection of Legal NFTs.", "image": "data:image/svg+xml;base64,',
                // We add data:image/svg+xml;base64 and then append our base64 encode our svg.
                Base64.encode(bytes(finalSvg)),
                '"}'
            )
         @);
 

@boubaker25
Copy link

all be ok

@dark-faze
Copy link

Hi, the console.log() inside .sol files are not appearing in my windows terminal. Has anyone come across the same problem?

@evantancy
Copy link

Hi, I was just wondering why do we use _setTokenURI instead of overriding the tokenURI function? I've tried minting a single token using both methods and _setTokenURI seems to consume significantly more gas. Contract code can be found here
image

@jikdo
Copy link

jikdo commented Feb 22, 2022

@evantancy , may i know which tool you are using to measure gas ?

@evantancy
Copy link

@jikdo hey, i'm using hardhat-gas-reporter and there's also foundry which i haven't tried but looks very promising

@Rishabh510
Copy link

Hi, the console.log() inside .sol files are not appearing in my windows terminal. Has anyone come across the same problem?

Yes, same for me as well

@asshroudy
Copy link

Don't for get to change it to

// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.1;

@michhub-dev
Copy link

pragma solidity ^0.8.1; Works for me

@Githugutech
Copy link

Using pragma solidity 0.8.0; on VSCode with WSL 2 throws an error.

Changing it to pragma solidity ^0.8.0; works for me.

Greets, Stefan

Also ^0.8.1 works just fine

@Brag2gr8
Copy link

Brag2gr8 commented Jun 17, 2022

import { Base64 } from "./libraries/Base64.sol"; >>> import { Base64 } from "../libraries/Base64.sol";
if it doesn't locate it

@webtester0
Copy link

@farzaa, hey

I think in random function, should be used a encode it's more secure, especially when we talk about generating random values.

For example:

function runEncodePacked(string calldata str1, string calldata str2) internal pure returns(bytes32) {
    bytes memory encoded = abi.encodePacked(str1, str2);
    return keccak256(encoded);
}

runEncodePacked("hello", "world") === runEncodePacked("hell", "oworld")
The result would be the same 0xfa26db7ca85ead399216e7c6316bc50ed24393c3122b582735e7f3b0f91b93f0

@Githugutech
Copy link

That actually works. Thanks

@OkoliEvans
Copy link

@farzaa, hey

I think in random function, should be used a encode it's more secure, especially when we talk about generating random values.

For example:

function runEncodePacked(string calldata str1, string calldata str2) internal pure returns(bytes32) {
    bytes memory encoded = abi.encodePacked(str1, str2);
    return keccak256(encoded);
}

runEncodePacked("hello", "world") === runEncodePacked("hell", "oworld") The result would be the same 0xfa26db7ca85ead399216e7c6316bc50ed24393c3122b582735e7f3b0f91b93f0

I think the same thing too

@Githugutech
Copy link

so basically the essence is to maintain security.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment