当我 运行 mainnet-fork-dev 上的合约函数时交易恢复

Transaction reverts when I run a contract function on mainnet-fork-dev

为了重现错误,可以从https://github.com/Binoy-John/brownie_fund_me

中获取代码

所以我有一个合同 FundMe.sol,它有几个函数,其中之一是 getEntranceFee()。如下图:

// SPDX-License-Identifier: MIT

// Smart contract that lets anyone deposit ETH into the contract
// Only the owner of the contract can withdraw the ETH
pragma solidity ^0.8.0;

// Get the latest ETH/USD price from chainlink price feed
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract FundMe {
    // safe math library check uint256 for integer overflows
    // using SafeMathChainlink for uint256;

    //mapping to store which address depositeded how much ETH
    mapping(address => uint256) public addressToAmountFunded;
    // array of addresses who deposited
    address[] public funders;
    //address of the owner (who deployed the contract)
    address public owner;

    //creating interface variable for use with parameterized constructor
    AggregatorV3Interface public priceFeed;

    // the first person to deploy the contract is
    // the owner
    constructor(address _priceFeed) {
        owner = msg.sender;
        priceFeed = AggregatorV3Interface(_priceFeed);
    }

    function fund() public payable {
        // 18 digit number to be compared with donated amount
        uint256 minimumUSD = 50 * 10**18;
        //is the donated amount less than 50USD?
        require(
            getConversionRate(msg.value) >= minimumUSD,
            "You need to spend more ETH!"
        );
        //if not, add to mapping and funders array
        addressToAmountFunded[msg.sender] += msg.value;
        funders.push(msg.sender);
    }

    function getEntranceFee() public view returns (uint256) {
        // minimumUSD
        uint256 minimumUSD = 50 * 10**18;
        uint256 price = getPrice();
        uint256 precision = 1 * 10**18;
        return (minimumUSD * precision) / price;
    }

    //function to get the version of the chainlink pricefeed
    function getVersion() public view returns (uint256) {
        return priceFeed.version();
    }

    function getPrice() public view returns (uint256) {
        (, int256 answer, , , ) = priceFeed.latestRoundData();
        // ETH/USD rate in 18 digit
        return uint256(answer * 10000000000);
    }

    // 1000000000
    function getConversionRate(uint256 ethAmount)
        public
        view
        returns (uint256)
    {
        uint256 ethPrice = getPrice();
        uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
        // the actual ETH/USD conversation rate, after adjusting the extra 0s.
        return ethAmountInUsd;
    }

    //modifier: https://medium.com/coinmonks/solidity-tutorial-all-about-modifiers-a86cf81c14cb
    modifier onlyOwner() {
        //is the message sender owner of the contract?
        require(msg.sender == owner);

        _;
    }

    // onlyOwner modifer will first check the condition inside it
    // and
    // if true, withdraw function will be executed
    function withdraw() public payable onlyOwner {
        // If you are using version eight (v0.8) of chainlink aggregator interface,
        // you will need to change the code below to
        payable(msg.sender).transfer(address(this).balance);
        //msg.sender.transfer(address(this).balance);

        //iterate through all the mappings and make them 0
        //since all the deposited amount has been withdrawn
        for (
            uint256 funderIndex = 0;
            funderIndex < funders.length;
            funderIndex++
        ) {
            address funder = funders[funderIndex];
            addressToAmountFunded[funder] = 0;
        }
        //funders array will be initialized to 0
        funders = new address[](0);
    }
}

我使用一个名为 deploy.py 的脚本来部署这个合约和 运行 它的一些功能。如下图:

from brownie import FundMe, accounts, config, network, MockV3Aggregator
from scripts.helpful_scripts import (
    deploy_mocks,
    get_account,
    LOCAL_BLOCKCHAIN_ENVIRONMENT,
)
from web3 import Web3


def deploy_fund_me():
    account = get_account()
    print("account used is ", account)
    if network.show_active() not in LOCAL_BLOCKCHAIN_ENVIRONMENT:
        price_feed_address = config["networks"][network.show_active()][
            "eth_usd_priceFeed"
        ]
    else:
        deploy_mocks()
        price_feed_address = MockV3Aggregator[-1].address
    fund_me = FundMe.deploy(
        price_feed_address,
        {"from": account},
        publish_source=config["networks"][network.show_active()].get("verify"),
    )

    print("contract deployed to ", fund_me.address)
    print("entree fee is ", fund_me.getEntranceFee())
    return fund_me


def main():
    deploy_fund_me()

它使用另一个名为 helpful_scripts.py 的脚本来创建帐户和部署模拟。具体如下:

from brownie import config, network, accounts, MockV3Aggregator
from web3 import Web3

FORKED_LOCAL_ENVIRONMENT = ["mainnet-fork", "mainnet-fork-dev"]
LOCAL_BLOCKCHAIN_ENVIRONMENT = ["development", "ganache-local"]
DECIMALS = 8
STARTING = 2000000000000000000000


def get_account():
    if (
        network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENT
        or network.show_active() in FORKED_LOCAL_ENVIRONMENT
    ):
        return accounts[0]
    else:
        # accounts.add(config["wallets"]["from_key"])
        # return config["wallets"]["from_key"]
        # print(accounts.add(config["wallets"]["from_key"]))
        return accounts.add(config["wallets"]["from_key"])


def deploy_mocks():
    account = get_account()
    print("from deploy ")
    print("the active network is ", network.show_active())
    print("deploying the contract")

    if len(MockV3Aggregator) <= 0:
        MockV3Aggregator.deploy(DECIMALS, STARTING, {"from": account})
        print("Deployed a new Mock because the length of MockV3Aggregator was 0")
    # print("mock aggregator is ", mock_aggregator)
    print("Mock deployed!")

    # print("Mocks deployed on ", mock_aggregator)

当我 运行 deploy.py 在 rinkeby 和 ganache-cli 网络上使用 $布朗尼 运行 deploy.py --network rinkeby 要么 $布朗尼 运行 deploy.py 我得到正确的输出:

Attached to local RPC client listening at '127.0.0.1:8545'...

Running 'scripts\deploy.py::main'...
account used is  0xFF3c899C61625bF772bA029C50D27E33db52f2D9
from deploy
the active network is  development
deploying the contract
Transaction sent: 0x9d6896cc8b2ea9ce24615a4bc6c069ab8b30e2ed44fb321677f5ffde30816338
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 104
  MockV3Aggregator.constructor confirmed   Block: 113   Gas used: 437447 (3.65%)
  MockV3Aggregator deployed at: 0x3eD74772c3403fa96826c38D94Ad67685B25f2D0

Deployed a new Mock because the length of MockV3Aggregator was 0
Mock deployed!
Transaction sent: 0x3cffbacb081fd70860783e497a3dbf293c0d03e2a9cf78335d67ae021b209615
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 105
  FundMe.constructor confirmed   Block: 114   Gas used: 515717 (4.30%)
  FundMe deployed at: 0xDeFd78dC7D60132FEaa39AD3f31E20738471cD08

contract deployed to  0xDeFd78dC7D60132FEaa39AD3f31E20738471cD08
entree fee is  2500000

但是当我 运行 使用 deploy.py $ brownie 运行 deploy.py --network mainnet-fork-dev 它给了我以下错误:

$ brownie run deploy.py --network mainnet-fork-dev
INFO: Could not find files for the given pattern(s).
Brownie v1.16.4 - Python development framework for Ethereum

BrownieFundMeProject is the active project.
C:\Users989\AppData\Roaming\Python\Python310\site-packages\brownie\network\main.py:44: BrownieEnvironmentWarning: Development network has a block height of 114
  warnings.warn(
Attached to local RPC client listening at '127.0.0.1:8545'...

Running 'scripts\deploy.py::main'...
account used is  0xFF3c899C61625bF772bA029C50D27E33db52f2D9
Transaction sent: 0xbb0c1ab97868e2851a586fddd4b64d23ec317dbba05efd35ff9fe04e03f54e3a
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 106
  FundMe.constructor confirmed   Block: 115   Gas used: 515717 (4.30%)
  FundMe deployed at: 0x948E3BA0dE6FADCE5e1459F5432A48Ef3DC7F70b

contract deployed to  0x948E3BA0dE6FADCE5e1459F5432A48Ef3DC7F70b
  File "C:\Users989\AppData\Roaming\Python\Python310\site-packages\brownie\_cli\run.py", line 49, 
in main
    return_value, frame = run(
  File "C:\Users989\AppData\Roaming\Python\Python310\site-packages\brownie\project\scripts.py", line 103, in run
    return_value = f_locals[method_name](*args, **kwargs)
  File ".\scripts\deploy.py", line 32, in main
    deploy_fund_me()
  File ".\scripts\deploy.py", line 27, in deploy_fund_me
    print("entree fee is ", fund_me.getEntranceFee())
  File "C:\Users989\AppData\Roaming\Python\Python310\site-packages\brownie\network\multicall.py", 
line 115, in _proxy_call
    result = ContractCall.__call__(*args, **kwargs)  # type: ignore
  File "C:\Users989\AppData\Roaming\Python\Python310\site-packages\brownie\network\contract.py", line 1729, in __call__
    return self.call(*args, block_identifier=block_identifier)
  File "C:\Users989\AppData\Roaming\Python\Python310\site-packages\brownie\network\contract.py", line 1533, in call
    raise VirtualMachineError(e) from None
  File "C:\Users989\AppData\Roaming\Python\Python310\site-packages\brownie\exceptions.py", line 104, in __init__
    raise ValueError(exc["message"]) from None
ValueError: VM Exception while processing transaction: revert

所以只有当 运行在 mainnet-fork-dev 上而不是其他地方时,我才会遇到这个问题。我对如何解决这个问题感到困惑,所以任何帮助将不胜感激!

如果您需要更多信息,请告诉我。

提前致谢!

function getPrice() public view returns (uint256) {
        (, int256 answer, , , ) = priceFeed.latestRoundData();
        // ETH/USD rate in 18 digit
        return uint256(answer * 10000000000);
    }

这是导致问题的代码。我认为 mainnet-fork-dev 的喂价合约地址不正确。这就是为什么除了这个以外的其他网络。