Created
January 5, 2023 09:52
-
-
Save ayo-klaytn/0ecc460e37fa8e9f676520fb444d98c5 to your computer and use it in GitHub Desktop.
This is an implementation of dynamic NFT on Klaytn. The metadata change based on the behaviour of KLAY/USDT as gotten from Witnet Oracle
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: GPL-3.0 | |
pragma solidity ^0.8.0; | |
import "@klaytn/contracts/KIP/token/KIP17/KIP17.sol"; | |
import "@klaytn/contracts/KIP/token/KIP17/extensions/KIP17Enumerable.sol"; | |
import "@klaytn/contracts/KIP/token/KIP17/extensions/KIP17URIStorage.sol"; | |
import "@klaytn/contracts/utils/Counters.sol"; | |
import "@klaytn/contracts/utils/Strings.sol"; | |
import "@klaytn/contracts/access/Ownable.sol"; | |
// witnet pricefeed | |
import "witnet-solidity-bridge/contracts/interfaces/IWitnetPriceRouter.sol"; | |
import "witnet-solidity-bridge/contracts/interfaces/IWitnetPriceFeed.sol"; | |
contract wKlayPricedNFT is KIP17, KIP17Enumerable, KIP17URIStorage, Ownable { | |
using Counters for Counters.Counter; | |
Counters.Counter private _tokenIdCounter; | |
uint public /* immutable */ interval; | |
uint public lastTimeStamp; | |
int256 public currentPrice; | |
IWitnetPriceRouter public witnetPriceRouter; | |
IWitnetPriceFeed public klayUsdtPrice; | |
// IPFS URIs for the dynamic nft graphics/metadata. | |
// NOTE: These connect to my IPFS Companion node. | |
// You should upload the contents of the /ipfs folder to your own node for development. | |
string[] bullUrisIpfs = ["https://ipfs.io/ipfs/QmTPyPMz6rVyHAnGWpFbfPmUWJMyaCKkj2sKhfMdichFuS?filename=k_bull.json"]; | |
string[] bearUrisIpfs = ["https://ipfs.io/ipfs/QmWFfeWbGyxwq7NYHajW1DCSBrnqcG4VtaToCBu4XvR6LQ?filename=k_bear.json"]; | |
event TokensUpdated(string marketTrend); | |
// For testing with the mock on Rinkeby, pass in 10(seconds) for `updateInterval` and the address of my | |
// deployed MockPriceFeed.sol contract (0xD753A1c190091368EaC67bbF3Ee5bAEd265aC420). | |
constructor(uint updateInterval) KIP17("Bull&Bear", "BBTK") { | |
// Set the keeper update interval | |
interval = updateInterval; | |
lastTimeStamp = block.timestamp; // seconds since unix epoch | |
witnetPriceRouter = IWitnetPriceRouter(0xeD074DA2A76FD2Ca90C1508930b4FB4420e413B0); | |
updateKlayUsdtPriceFeed(); | |
(currentPrice ,) = getKlayUsdtPrice(); | |
} | |
function safeMint(address to) public { | |
// Current counter value will be the minted token's token ID. | |
uint256 tokenId = _tokenIdCounter.current(); | |
// Increment it so next time it's correct when we call .current() | |
_tokenIdCounter.increment(); | |
// Mint the token | |
_safeMint(to, tokenId); | |
// Default to a bull NFT | |
string memory defaultUri = bullUrisIpfs[0]; | |
_setTokenURI(tokenId, defaultUri); | |
} | |
function checkUpkeep(bytes calldata /* checkData */) external view returns (bool upkeepNeeded, bytes memory /* performData */ ) { | |
upkeepNeeded = (block.timestamp - lastTimeStamp) > interval; | |
} | |
function performUpkeep(bytes calldata /* performData */ ) external { | |
//We highly recommend revalidating the upkeep in the performUpkeep function | |
if ((block.timestamp - lastTimeStamp) > interval ) { | |
int latestPrice; | |
lastTimeStamp = block.timestamp; | |
(latestPrice, ) = getKlayUsdtPrice(); | |
if (latestPrice == currentPrice) { | |
return; | |
} | |
if (latestPrice < currentPrice) { | |
// bear | |
updateAllTokenUris("bear"); | |
} else { | |
// bull | |
updateAllTokenUris("bull"); | |
} | |
// update currentPrice | |
currentPrice = latestPrice; | |
} else { | |
return; | |
} | |
} | |
function updateAllTokenUris(string memory trend) internal { | |
if (compareStrings("bear", trend)) { | |
for (uint i = 0; i < _tokenIdCounter.current() ; i++) { | |
_setTokenURI(i, bearUrisIpfs[0]); | |
} | |
} else { | |
for (uint i = 0; i < _tokenIdCounter.current() ; i++) { | |
_setTokenURI(i, bullUrisIpfs[0]); | |
} | |
} | |
emit TokensUpdated(trend); | |
} | |
function setInterval(uint256 newInterval) public onlyOwner { | |
interval = newInterval; | |
} | |
function updateKlayUsdtPriceFeed() public { | |
IERC165 _newPriceFeed = witnetPriceRouter.getPriceFeed(bytes4(0x5d9add33)); | |
if (address(_newPriceFeed) != address(0)) { | |
klayUsdtPrice = IWitnetPriceFeed(address(_newPriceFeed)); | |
} | |
} | |
/// Returns the KlAY / USD price (6 decimals), ultimately provided by the Witnet oracle, and | |
/// the timestamps at which the price was reported back from the Witnet oracle's sidechain | |
/// to Klaytn Baobab. | |
function getKlayUsdtPrice() public view returns (int256 _lastPrice, uint256 _lastTimestamp) { | |
(_lastPrice, _lastTimestamp,,) = klayUsdtPrice.lastValue(); | |
} | |
function compareStrings(string memory a, string memory b) internal pure returns (bool) { | |
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); | |
} | |
// The following functions are overrides required by Solidity. | |
function _beforeTokenTransfer(address from, address to, uint256 tokenId) | |
internal | |
override(KIP17, KIP17Enumerable) | |
{ | |
super._beforeTokenTransfer(from, to, tokenId); | |
} | |
function _burn(uint256 tokenId) internal override(KIP17, KIP17URIStorage) { | |
super._burn(tokenId); | |
} | |
function tokenURI(uint256 tokenId) | |
public | |
view | |
override(KIP17, KIP17URIStorage) | |
returns (string memory) | |
{ | |
return super.tokenURI(tokenId); | |
} | |
function supportsInterface(bytes4 interfaceId) | |
public | |
view | |
override(KIP17, KIP17Enumerable) | |
returns (bool) | |
{ | |
return super.supportsInterface(interfaceId); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment