Skip to content

Instantly share code, notes, and snippets.

@ayo-klaytn
Created January 5, 2023 09:52
Show Gist options
  • Save ayo-klaytn/0ecc460e37fa8e9f676520fb444d98c5 to your computer and use it in GitHub Desktop.
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
// 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