I've successfully deployed VrfTest.sol
contract which is same as Get a Random Number example in Chainlink. After that I tried to deploy my BullBear.sol
contract. This is for minting NFT that change itself metadata along with ETH/USD price.
First problem is remix keeps warning 'Gas estimation failed'.
The second is transaction execution failed error when I send transaction.
creation of BullBear pending...
view on etherscan
creation of BullBear errored: transaction execution failed
I used updateAlltokenUris()
function to update NFT's url in the contract. I guess that function causes error because it calls getRequestId()
in VrfTest.sol
contract. How can I solve these problems? I also transferred LINK token to VrfTest.sol
contract,
subscribed Chaninlink VRF and added consumer. Source code is below.
VrfTest.sol
contract
// SPDX-License-Identifier: MIT
// An example of a consumer contract that relies on a subscription for funding.
pragma solidity ^0.8.4;
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
contract VrfTest is VRFConsumerBaseV2 {
VRFCoordinatorV2Interface COORDINATOR;
uint64 s_subscriptionId;
// Goerli coordinator
address vrfCoordinator = 0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D;
bytes32 keyHash = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;
uint32 callbackGasLimit = 100000;
uint16 requestConfirmations = 3;
uint32 numWords = 2;
uint256[] public s_randomWords;
uint256 public s_requestId;
address s_owner;
constructor(uint64 subscriptionId) VRFConsumerBaseV2(vrfCoordinator) {
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
s_owner = msg.sender;
s_subscriptionId = subscriptionId;
}
function getRequestId() public view returns (uint256[] memory) {
return s_randomWords;
}
function requestRandomWords() external onlyOwner {
s_requestId = COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
}
function fulfillRandomWords(
uint256, /* requestId */
uint256[] memory randomWords
) internal override {
s_randomWords = randomWords;
}
modifier onlyOwner() {
require(msg.sender == s_owner);
_;
}
}
BullBear.sol
contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/[email protected]/token/ERC721/ERC721.sol";
import "@openzeppelin/[email protected]/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/[email protected]/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/[email protected]/access/Ownable.sol";
import "@openzeppelin/[email protected]/utils/Counters.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
// KeeperCompatible.sol imports the functions from both ./KeeperBase.sol and
// ./interfaces/KeeperCompatibleInterface.sol
import "@chainlink/contracts/src/v0.8/KeeperCompatible.sol";
import "./VrfTest.sol";
contract BullBear is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable, KeeperCompatibleInterface {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
uint public interval;
uint public lastTimeStamp;
int256 public currentPrice;
AggregatorV3Interface public priceFeed;
VrfTest public vrfContract;
event TokenUpdated(string marketTrend);
string[] bullUrisIpfs = [
"https://ipfs.io/ipfs/QmcEd1R1Qq7M6G7NnHxDXYdiYtJAn9A2FGjg94Ku75HgUD?filename=gamer_bull.png",
"https://ipfs.io/ipfs/QmUveY3PgfLD9TahrAEH2WieCG1PfU9Ybdq9WbZe8wXwvQ?filename=party_bull.png",
"https://ipfs.io/ipfs/QmXou1mty7AqhKzxrxC5C7Xqx8yVjVi8ZEqjacUpQQ89hD?filename=simple_bull.png"
];
string[] bearUrisIpfs = [
"https://ipfs.io/ipfs/QmSHyHr3kHKza3YRMfNz5HFatotSvLSa17YHJPzXJow1gU?filename=beanie_bear.png",
"https://ipfs.io/ipfs/QmVqKAMsQRbNcVffMUwyzVHhcx37sx46qnFX6nnYqu1rb9?filename=coolio_bear.png",
"https://ipfs.io/ipfs/QmNeo34iQGsPLagnw1E6LjzfgmqVNLYftCymHKv11q9QsS?filename=simple_bear.png"
];
constructor(uint updateInterval, address _priceFeed, VrfTest _addrVrfContract) ERC721("Bull&Bear", "BBTK") {
vrfContract = _addrVrfContract;
interval = updateInterval;
lastTimeStamp = block.timestamp;
priceFeed = AggregatorV3Interface(_priceFeed);
currentPrice = getLatestPrice();
}
function safeMint(address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
string memory defaultUri = bullUrisIpfs[0];
_setTokenURI(tokenId, defaultUri);
}
function checkUpkeep(bytes calldata /* checkData */) external view override returns (bool upkeepNeeded, bytes memory /* performData */) {
upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;
}
function performUpkeep(bytes calldata /* performData */) external override {
if ((block.timestamp - lastTimeStamp) > interval ) {
vrfContract.requestRandomWords();
lastTimeStamp = block.timestamp;
int latestPrice = getLatestPrice();
if(latestPrice == currentPrice) {
return;
}
if(latestPrice < currentPrice) {
updateAlltokenUris("bear");
} else {
updateAlltokenUris("bull");
}
currentPrice = latestPrice;
}
}
function getLatestPrice() public view returns (int256) {
(
/*uint80 roundID*/,
int256 price,
/*uint startedAt*/,
/*uint timeStamp*/,
/*uint80 answeredInRound*/
) = priceFeed.latestRoundData();
return price;
}
function updateAlltokenUris(string memory trend) internal {
uint256[] memory randomWords = vrfContract.getRequestId();
uint256 randomNum = randomWords[0] % bearUrisIpfs.length;
if(compareStrings("bear", trend)) {
for (uint i=0; i<_tokenIdCounter.current(); i++) {
_setTokenURI(i, bearUrisIpfs[randomNum]);
}
} else {
for (uint i=0; i<_tokenIdCounter.current(); i++) {
_setTokenURI(i, bullUrisIpfs[randomNum]);
}
}
emit TokenUpdated(trend);
}
function compareStrings(string memory a, string memory b) internal pure returns (bool) {
return (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)));
}
function setInterval(uint256 newInterval) public onlyOwner {
interval = newInterval;
}
function setPriceFeed(address newFeed) public onlyOwner {
priceFeed = AggregatorV3Interface(newFeed);
}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId);
}
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);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
BullBear.sol
contract transaction failed.