【问题标题】:brownie:ValueError: execution reverted: VM Exception while processing transaction: revert布朗尼:ValueError: execution reverted: VM Exception while processing transaction: revert
【发布时间】:2022-03-09 22:01:57
【问题描述】:

Macbook Pro:蒙特雷

英特尔酷睿 i7

布朗尼 v1.17.2

我正在根据参考学习solidity(https://www.youtube.com/watch?v=M576WGiDBdQ&t=25510s)。

我在这里尝试做的是使用 brownie 在脚本(deploy.py)中部署合约(FundMe),然后编写测试脚本(scripts/fund_and_withdraw.py.py)

我遇到了同样的错误,MockV3Aggregator 部署成功,但 getEntrancePrice 为 0 谷歌搜索它找到了这个答案,不要完全遵循。(https://ethereum.stackexchange.com/questions/114889/deploying-ganache-local-w-brownie-vm-exception-while-processing-transaction-in

getPrice() 没有从模拟中返回你想要的数字,在 2B 附近的某个地方。认为这是 Ganache 实现的一个错误——在 getEntranceFee() 中执行计算(最小美元 * 精度)/价格给你一个小于 1 的数字——并且,由于 Solidity 无法处理浮点数,Solidity 只是将其视为 0,整个事情都出错了。

脚本/fund_and_withdraw.py

from brownie import FundMe
from scripts.helpful_scripts import get_account





def fund():
    fund_me = FundMe[-1]

    account = get_account()

    entrance_fee = fund_me.getEntranceFee()
    print(f"The entrance fee is : {entrance_fee} !")
    print("funding")
    fund_me.fund({"from": account, "value": entrance_fee})
    print(f"Funded {entrance_fee} !")


def withdraw():
    fund_me = FundMe[-1]
    account = get_account()
    fund_me.withdraw({"from": account})


def main():
    fund()
    withdraw()

部署.py

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


def deploy_fund_me():
    account = get_account()
    # if we have a persistent network like rinkeby,use the associated address
    # otherwise ,deploy mocks
    if network.show_active() not in LOCAL_BLOCKCHAIN_ENVIRONMENT:
        price_feed_address = config["networks"][network.show_active()][
            "eth_usd_price_feed"
        ]
    else:
        deploy_mocks()
        # just use the latest mockV3Aggregator
        price_feed_address = MockV3Aggregator[-1].address
        print("***********************************************************")
        print(f"MockVeAggrator's address is {price_feed_address}")

    fund_me = FundMe.deploy(
        price_feed_address,
        {"from": account},
        publish_source=config["networks"][network.show_active()].get("verify"),
    )
    print("***********************************************************")
    print(f"The Ether price is :{fund_me.getPrice()}\n")
    print(f"Contract deployed to {fund_me.address}\n")
    entrance_fee = fund_me.getEntranceFee()
    print("***********************************************************")
    print(f"The entrance fee is : {entrance_fee} !\n")
    return fund_me


def main():
    deploy_fund_me()

FundMe.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.0;

// we need tell brownie @chainlink means == what input in config,need to tell compiler

import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";

import "@chainlink/contracts/src/v0.6/vendor/SafeMathChainlink.sol";

contract FundMe {
    //using SafeMathChainlink for uint256;

    mapping(address => uint256) public addressToAmountFunded;
    address[] public funders;
    address public owner;
    AggregatorV3Interface public priceFeed;

    // if you're following along with the freecodecamp video
    // Please see https://github.com/PatrickAlphaC/fund_me
    // to get the starting solidity contract code, it'll be slightly different than this!
    constructor(address _priceFeed) {
        // make price feed a parameter
        priceFeed = AggregatorV3Interface(_priceFeed);
        owner = msg.sender;
    }

    function fund() public payable {
        uint256 mimimumUSD = 50 * 10**18;
        require(
            getConversionRate(msg.value) >= mimimumUSD,
            "You need to spend more ETH!"
        );
        addressToAmountFunded[msg.sender] += msg.value;
        funders.push(msg.sender);
    }

    function getVersion() public view returns (uint256) {
        return priceFeed.version();
    }

    function getPrice() public view returns (uint256) {
        (, int256 answer, , , ) = priceFeed.latestRoundData();
        return uint256(answer * 10000000000);
    }

    // 1000000000
    function getConversionRate(uint256 ethAmount)
        public
        view
        returns (uint256)
    {
        uint256 ethPrice = getPrice();
        uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
        return ethAmountInUsd;
    }

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

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    function withdraw() public payable onlyOwner {
        payable(msg.sender).transfer(address(this).balance);

        for (
            uint256 funderIndex = 0;
            funderIndex < funders.length;
            funderIndex++
        ) {
            address funder = funders[funderIndex];
            addressToAmountFunded[funder] = 0;
        }
        funders = new address[](0);
    }
}

更新 错误神奇地消失了(可能稍后会回来),现在错误信息是:list out of index 实际上我在another project (Brownie test IndexError: list index out of range) 中遇到了同样的错误

根据答案和brownie docs,我需要添加帐户。 让我困惑的是,如果我已经启动了 ganache 本地区块链,为什么我还需要添加帐户或添加错误的方式?

【问题讨论】:

    标签: python ethereum solidity chainlink brownie


    【解决方案1】:
    function getEntranceFee() public view returns (uint256) {
            // mimimumUSD
            uint256 mimimumUSD = 50 * 10**18;
            uint256 price = getPrice();
            uint256 precision = 1 * 10**18;
            return (mimimumUSD * precision) / price;
        }
    

    您不需要精确乘法。目前,假设 eth 价格为 3000,您正在返回

     (50 * (10^18) * (10^18)) / (3000 * 10^10)
    
     (50 * (10^36)) / (3 * 10^13)
    
     (50/3)*(10^23)
    

    我认为你的返回值应该是

      return mimimumUSD  / price;
    

    【讨论】:

    • 函数getPrice()的返回价格已经是18个小数(3000*10^18),(如果eth价格是3000$,来自rinkeby测试网的价格是8个小数,函数中乘以10^10 ,所以是``` (50*(10^18)*(10^18))/(3000*(10^18)) (50/3)*(10^(36-18-3)) (50/3)*(10^15) ```
    • @mike515 在这里你使用的是 3000*(10^18) 但在 getPrice 函数中你有 return uint256(answer * 10000000000);
    • 是的,但是答案(来自 rinkeby 测试网)是一个 8 位小数,比如 3000*(10^8),所以我计算出价格是 3000*(10^8)*(10^10)
    • @mike515 我稍后再看看
    • 感谢您的耐心等待,实际上这个错误没有显示(可能稍后会回来),现在我面临一个新的错误:list out of index。
    【解决方案2】:

    您好,我正在学习您的课程,我也遇到了与您相同的问题。我忘了在这里用变量 price_feed_address 替换地址:

    部署.py

        fund_me = FundMe.deploy(
            price_feed_address, # <--- before there was "0x8A..ect"
            {"from": account}, 
            publish_source=config["networks"][network.show_active()].get("verify")
        )
    

    现在一切正常。

    我在我们的代码中发现的唯一区别是:

    部署.py

    from brownie import FundMe, MockV3Aggregator, network, config
    from scripts.helpful_script import (
        get_account, 
        deploy_mocks, 
        LOCAL_BLOCKCHAIN_ENVIRONMENTS
    )
    
    def deploy_fund_me():
        account = get_account()
        # pass the price feed address to our fundme contract
        
        # if we are on a persistent network like rinkeby, use the associated address
        # otherwise, deploy mocks
    
        if network.show_active() not in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
            price_feed_address = config["networks"][network.show_active()][
                "eth_usd_price_feed"
            ]
        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(f"Contract deployed to {fund_me.address}")
        return fund_me
    
    def main():
        deploy_fund_me()
    

    你打电话:

    entrance_fee = fund_me.getEntranceFee()
    

    【讨论】:

    • 对不起,我不太明白,我们都在代码中将 pricefeed 地址设为变量,为了参数化 pricefeed 地址,使其成为变量并将真实地址保存在 config.xml 中。 yaml文件
    【解决方案3】:

    如果您将 getEntrancePrice 设为 0,请在 help_scripts.py 文件中删除此部分中的 web3.toWei 函数:

    MockV3Aggregator.deploy(
                DECIMALS, Web3.toWei(STARTING_PRICE, "ether"), {"from": get_account()}
            )
    

    改成这样:

    MockV3Aggregator.deploy(DECIMALS, STARTING_PRICE, {"from": get_account()})
    

    由于您已经在顶部(作为全局变量)指定模拟价格输出小数位为 8,并在 2000 年之后添加额外的 8 个零,以向模拟构造函数发送具有 8 位小数的初始价格,留下 toWei函数你添加了额外的 18 位小数,总共 26 位是错误的。

    此外,您在部署模拟后的输出中添加了另外 10 个小数位,总共 36 个。

    DECIMALS = 8
    STARTING_PRICE = 200000000000
    

    我的猜测是你得到 0 的原因是因为你超过了 uint8 十进制变量允许的大小,或者可能将带有 26 位小数的初始价格发送给构造函数需要比每个块允许的气体限制更多的气体费用和甘纳许交易。如果可以的话,有人澄清一下!

    【讨论】:

      【解决方案4】:

      请将您的 FundMe.sol 与 github 源进行比较: https://github.com/PatrickAlphaC/brownie_fund_me/blob/main/contracts/FundMe.sol

      你会看到:function getEntranceFee() public view returns (uint256)

          return (mimimumUSD * precision) / price;
      

      它已经改变了:

          return ((minimumUSD * precision) / price) + 1;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-09
        • 1970-01-01
        • 2021-12-03
        • 2022-08-09
        • 2022-10-15
        • 2021-09-21
        • 2021-12-23
        • 2022-01-03
        相关资源
        最近更新 更多