Skip to content

Instantly share code, notes, and snippets.

@rgottleber
Created November 1, 2022 17:23
Show Gist options
  • Save rgottleber/fef0e526c236e1b8778be51e1b105a32 to your computer and use it in GitHub Desktop.
Save rgottleber/fef0e526c236e1b8778be51e1b105a32 to your computer and use it in GitHub Desktop.
SmartCon Demo NFT
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.7;
// Importing other contracts
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
// Importing Chainlink contracts
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
contract DNFT is ERC721, ERC721URIStorage, VRFConsumerBaseV2 {
// Set ETH price placeholder
int256 previousEthPrice = 0;
// Set variables for NFT
string ethIndicatorUp = unicode"😀";
string ethIndicatorDown = unicode"😔";
string ethIndicatorFlat = unicode"😑";
string ethIndicator;
// Possible hex digits for NFT color
string[] public hexDigits = [
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"a",
"b",
"c",
"d",
"e",
"f"
];
// Create VRF coordinatior
VRFCoordinatorV2Interface COORDINATOR;
// Create price feed
AggregatorV3Interface internal priceFeed;
// Your subscription ID.
uint64 s_subscriptionId;
// Goerli coordinator. For other networks,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
address vrfCoordinator = 0x2eD832Ba664535e5886b75D64C46EB9a228C2610;
// The gas lane to use, which specifies the maximum gas price to bump to.
// For a list of available gas lanes on each network,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
bytes32 keyHash =
0x354d2f95da55398f44b7cff77da56283d9c6c829a4bdf1bbcaf2ad6a4d081f61;
// Depends on the number of requested values that you want sent to the
// fulfillRandomWords() function. This limit is super high just to be safe.
// In a real application, you'd probably want to set this to a more accurate value.
uint32 callbackGasLimit = 999999;
// The default is 3, but you can set this higher.
uint16 requestConfirmations = 1;
// For this example, retrieve 6 random values in one request.
// Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS.
uint32 numWords = 6;
// Store random numbers
uint256[] public s_randomWords;
// Store owner
address s_owner;
// Constructor takes subscription ID from https://vrf.chain.link/
constructor(uint64 subscriptionId)
ERC721("ETH Watch SVG", "ewSVG")
VRFConsumerBaseV2(vrfCoordinator)
{
/**
* Network: Goerli
* Aggregator: ETH/USD
* Address: 0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
*/
priceFeed = AggregatorV3Interface(
0x86d67c3D38D2bCeE722E601025C25a575021c6EA
);
// Set Coordinatior
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
// Set subscription ID
s_subscriptionId = subscriptionId;
// Set owner
s_owner = msg.sender;
// Mint an NFT
_safeMint(s_owner, 0);
}
// Function to request random numbers
function requestRandomWords() public {
// Will revert if subscription is not set and funded.
COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
}
// Callback function used by VRF Coordinator
function fulfillRandomWords(
uint256, /* requestId */
uint256[] memory randomWords
) internal override {
s_randomWords = randomWords;
// Update NFT SVG
updateSVG(s_randomWords);
}
// Update the SVG
function updateSVG(uint256[] memory randomWords) public {
// Create the SVG string
string memory finalSVG = buildSVG(randomWords);
// Base64 encode the SVG
string memory json = Base64.encode(
bytes(
string(
abi.encodePacked(
'{"name": "ETH Watching SVG",',
'"description": "An Automated ETH tracking SVG",',
'"image": "data:image/svg+xml;base64,',
Base64.encode(bytes(finalSVG)),
'"}'
)
)
)
);
// Create token URI
string memory finalTokenURI = string(
abi.encodePacked("data:application/json;base64,", json)
);
// Set token URI
_setTokenURI(0, finalTokenURI);
}
// Build the SVG string
function buildSVG(uint256[] memory randomWords)
public
returns (string memory)
{
// Generate random hex color
string memory fillColor = string(
abi.encodePacked(
"#",
randomHexDigit(randomWords[0]),
randomHexDigit(randomWords[1]),
randomHexDigit(randomWords[2]),
randomHexDigit(randomWords[3]),
randomHexDigit(randomWords[4]),
randomHexDigit(randomWords[5])
)
);
// Create SVG rectangle with random color
string memory headSVG = string(
abi.encodePacked(
"<svg xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:svgjs='http://svgjs.com/svgjs' width='500' height='500' preserveAspectRatio='none' viewBox='0 0 500 500'> <rect width='100%' height='100%' fill='",
fillColor,
"' />"
)
);
// Update emoji based on ETH price
string memory bodySVG = string(
abi.encodePacked(
"<text x='50%' y='50%' font-size='128' dominant-baseline='middle' text-anchor='middle'>",
compareETHPrice(),
"</text>"
)
);
// Close SVG
string memory tailSVG = "</svg>";
// Concatenate SVG strings
string memory _finalSVG = string(
abi.encodePacked(headSVG, bodySVG, tailSVG)
);
return _finalSVG;
}
// Function to return a hex digit based on a random number
function randomHexDigit(uint256 _randomNum)
public
view
returns (string memory)
{
uint256 randomIndex = _randomNum % hexDigits.length;
return hexDigits[randomIndex];
}
// Compare ETH price to previous price
function compareETHPrice() public returns (string memory) {
int256 currentEthPrice = getETHPrice();
if (currentEthPrice > previousEthPrice) {
ethIndicator = ethIndicatorUp;
} else if (currentEthPrice < previousEthPrice) {
ethIndicator = ethIndicatorDown;
} else {
ethIndicator = ethIndicatorFlat;
}
previousEthPrice = currentEthPrice;
return ethIndicator;
}
function getETHPrice() public view returns (int256) {
(, int256 price, , , ) = priceFeed.latestRoundData();
return price;
}
function _burn(uint256 tokenId)
internal
override(ERC721, ERC721URIStorage)
{
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
modifier onlyOwner() {
require(msg.sender == s_owner);
_;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment