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.

  1. 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(

  function fulfillRandomWords(
    uint256, /* requestId */
    uint256[] memory randomWords
  ) internal override {
    s_randomWords = randomWords;

  modifier onlyOwner() {
    require(msg.sender == s_owner);
  1. 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 = [

    string[] bearUrisIpfs = [

    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();
        _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 ) {
            lastTimeStamp = block.timestamp;
            int latestPrice = getLatestPrice();
            if(latestPrice == currentPrice) {
            if(latestPrice < currentPrice) {
            } else {
            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)
        override(ERC721, ERC721Enumerable)
        super._beforeTokenTransfer(from, to, tokenId);

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {

    function tokenURI(uint256 tokenId)
        override(ERC721, ERC721URIStorage)
        returns (string memory)
        return super.tokenURI(tokenId);

    function supportsInterface(bytes4 interfaceId)
        override(ERC721, ERC721Enumerable)
        returns (bool)
        return super.supportsInterface(interfaceId);

  • In your updateAlltokenUris function, why are you using getRequestId as the random words? request id is not meant to be used as a source of randomness, you should use s_randomwords instead. Commented Sep 13, 2022 at 10:02
  • Sorry, It is typo but it returns s_randomWords.
    – Shift_that
    Commented Sep 13, 2022 at 10:25
  • What transaction was the failed one? Deploying the contract? Commented Sep 13, 2022 at 14:55
  • Yes, when I deploy the BullBear.sol contract transaction failed.
    – Shift_that
    Commented Sep 13, 2022 at 21:02
  • Hi @Shift_that, I deployed your smart contracts successfully. Can you check etherscan to find what's wrong with the deployment transaction? The deployment does not fail because functions other than constructor. Can you edit your question and add transaction hash so that other ppl can check the failed transaction too.
    – Frank Kong
    Commented Sep 14, 2022 at 8:55


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.