Solidity

布朗尼氣體估計失敗:“執行恢復”

  • March 3, 2022

我正在完成高級 NFT 的 freecodecamp solidity 教程,並在部署到 rinkeby 測試網時返回:

ValueError: Gas estimation failed: 'execution reverted'. This transaction will likely revert. If you wish to broadcast, you must set the gas limit manually.

當我使用 fund_with_link 代幣時,我的合約已獲得資金,但我無法呼叫 create_collectible 函式而不返回錯誤消息。我的元遮罩帳戶中確實有足夠的連結。

這是合約程式碼:

pragma solidity ^0.7.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@chainlink/contracts/src/v0.7/VRFConsumerbase.sol";

contract AdvancedCollectible is ERC721, VRFConsumerBase {
   uint256 public tokenCounter;
   bytes32 public keyhash;
   uint256 public fee;
   enum Breed {
       PUG,
       SHIBA_INU,
       ST_BERNARD
   }
   mapping(uint256 => Breed) public tokenIdToBreed;
   mapping(bytes32 => address) requestIdToSender;
   event requestedCollectible(bytes32 indexed requestId, address requester);
   event breedAssigned(uint256 indexed tokenId, Breed breed);

   constructor(
       address _vrfCoordinator,
       address _linkToken,
       bytes32 _keyhash,
       uint256 _fee
   )
       public
       VRFConsumerBase(_vrfCoordinator, _linkToken)
       ERC721("Dogie", "DOG")
   {
       tokenCounter = 0;
       keyhash = _keyhash;
       fee = _fee;
   }

   function createCollectible(string memory tokenURI)
       public
       returns (bytes32)
   {
       bytes32 requestId = requestRandomness(keyhash, fee);
       requestIdToSender[requestId] = msg.sender;
       emit requestedCollectible(requestId, msg.sender);
   }

   function fulfillRandomness(bytes32 requestId, uint256 randomNumber)
       internal
       override
   {
       Breed breed = Breed(randomNumber % 3);
       uint256 newTokenId = tokenCounter;
       tokenIdToBreed[newTokenId] = breed;
       emit breedAssigned(newTokenId, breed);
       address owner = requestIdToSender[requestId];
       _safeMint(owner, newTokenId);
       tokenCounter = tokenCounter + 1;
   }

   function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
       //need tokenId for pug, shiba-inu and st-bernard
       //making sure that only the owner of the tokenId can update the tokenURI
       require(
           _isApprovedOrOwner(_msgSender(), tokenId),
           "ERC721: is not owner, not approved"
       );
   }
}

這是部署腳本:

from scripts.helpful_scripts import (
   get_account,
   OPENSEA_URL,
   get_contract,
   fund_with_link,
)
from brownie import AdvancedCollectible, config, network
from web3 import Web3
from time import sleep

sample_token_uri = "https://ipfs.io/ipfs/Qmd9MCGtdVz2miNumBHDbvj8bigSgTwnr4SbyH6DNnpWdt?filename=0-PUG.json"


def deploy_and_create():
   account = get_account()
   advanced_collectible = AdvancedCollectible.deploy(
       get_contract("vrf_coordinator"),
       get_contract("link_token"),
       config["networks"][network.show_active()]["keyhash"],
       config["networks"][network.show_active()]["fee"],
       {"from": account},
   )
   fund_with_link(advanced_collectible.address)
   create_collectible = advanced_collectible.createCollectible(
       sample_token_uri, {"from": account}
   )


def main():
   deploy_and_create()

以下是有用的腳本:

from brownie import network, config, accounts, LinkToken, VRFCoordinatorMock, Contract
import dotenv
from web3 import Web3

OPENSEA_URL = "https://testnets.opensea.io/assets/{}/{}"
LOCAL_BLOCKCHAIN_ENVIRONMENTS = ["hardhat", "development", "ganache", "mainnet-fork"]


def get_account(index=None, id=None):
   if index:
       return accounts[index]
   if network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
       return accounts[0]
   if id:
       return accounts.load(id)
   return accounts.add(config["wallets"]["from_key"])


contract_to_mock = {"link_token": LinkToken, "vrf_coordinator": VRFCoordinatorMock}


def get_contract(contract_name):
   """
   This function will either:
       - Get an address from the config
       - Or deploy a Mock to use for a network that doesn't have the contract
   Args:
       contract_name (string): This is the name of the contract that we will get
       from the config or deploy
   Returns:
       brownie.network.contract.ProjectContract: This is the most recently deployed
       Contract of the type specified by a dictionary. This could either be a mock
       or a 'real' contract on a live network.
   """
   # link_token
   # LinkToken
   contract_type = contract_to_mock[contract_name]
   if network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
       if len(contract_type) <= 0:
           deploy_mocks()
       contract = contract_type[-1]
   else:
       contract_address = config["networks"][network.show_active()][contract_name]
       contract = Contract.from_abi(
           contract_type._name, contract_address, contract_type.abi
       )
   return contract


def deploy_mocks():
   """
   Use this script if you want to deploy mocks to a testnet
   """
   print(f"The active network is {network.show_active()}")
   print("Deploying mocks...")
   account = get_account()
   print("Deploying Mock LinkToken...")
   link_token = LinkToken.deploy({"from": account})
   print(f"Link Token deployed to {link_token.address}")
   print("Deploying Mock VRF Coordinator...")
   vrf_coordinator = VRFCoordinatorMock.deploy(link_token.address, {"from": account})
   print(f"VRFCoordinator deployed to {vrf_coordinator.address}")
   print("All done!")


def fund_with_link(
   contract_address, account=None, link_token=None, amount=Web3.toWei(2, "ether")
):
   account = account if account else get_account()
   link_token = link_token if link_token else get_contract("link_token")
   funding_tx = link_token.transfer(contract_address, amount, {"from": account})
   funding_tx.wait(1)
   print(f"Funded {contract_address}")
   return funding_tx

這是 brownie-config.yaml:

dotenv: .env
dependencies:
 - OpenZeppelin/openzeppelin-contracts@3.4.0
 - smartcontractkit/chainlink-brownie-contracts@0.2.1
compiler:
 solc:
   remappings:
     - '@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.4.0'
     - '@chainlink=smartcontractkit/chainlink-brownie-contracts@0.2.1'
wallets:
 from_key: ${PRIVATE_KEY}
networks:
 development:
   keyhash: "0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc"
   fee: 100000000000000000
 rinkeby:
   vrf_coordinator: "0x6168499c0cFfCaCD319c818142124B7A15E857ab"
   link_token: "0x01BE23585060835E02B77ef475b0Cc51aA1e0709"
   keyhash: "0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc"
   fee: 10000000000000000

任何幫助,將不勝感激 :)

我找到了一個解決方案,只是我很愚蠢——這並不奇怪。我只是在 brownie-config.yaml 文件中為費用寫了錯誤數量的零。我也有錯誤的 keyhash eth 地址。

引用自:https://ethereum.stackexchange.com/questions/123019