Created
November 1, 2022 17:23
-
-
Save rgottleber/fef0e526c236e1b8778be51e1b105a32 to your computer and use it in GitHub Desktop.
SmartCon Demo NFT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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