mike515
mike515

Reputation: 343

brownie:ValueError: execution reverted: VM Exception while processing transaction: revert

Macbook Pro : Monterey

Intel Core i7

Brownie v1.17.2

I am learning solidity according to reference(https://www.youtube.com/watch?v=M576WGiDBdQ&t=25510s).

What I tried to do here, is use brownie to deploy a contract(FundMe) in a script (deploy.py),then write a test script(scripts/fund_and_withdraw.py.py)

I met the same error,the MockV3Aggregator deployed successfully, but the getEntrancePrice is 0 Googled it find this answer,don't quite follow.(https://ethereum.stackexchange.com/questions/114889/deploying-ganache-local-w-brownie-vm-exception-while-processing-transaction-in)

getPrice() isn't returning a number you want from the mock, somewhere in the vicinity of 2B. Think this is a bug with the Ganache implementation- performing the calculation (minimumUSD * precision) / price in getEntranceFee() gives you a number less than 1- and, since Solidity can't handle floats, Solidity simply sees it as a 0, and the whole thing errors out.

scripts/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()

deploy.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);
    }
}

update the error disappear magicly (may be come back later),right now the error info is :list out of index actually i faced the same error in another project (Brownie test IndexError: list index out of range)

according the answer and brownie docs, I need to add account. what confused me is if I launched the ganache local blockchain already ,why I still need to add account or I added the wrong way?

enter image description here

Upvotes: 2

Views: 1549

Answers (5)

Prashant Malan
Prashant Malan

Reputation: 51

I also got this issue, resolved by fixing the entrance fee. we need to keep the brackets

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

Upvotes: 0

jess
jess

Reputation: 1

Please compare your FundMe.sol with the github source: https://github.com/PatrickAlphaC/brownie_fund_me/blob/main/contracts/FundMe.sol

You'll see: function getEntranceFee() public view returns (uint256)

    return (mimimumUSD * precision) / price;

it already be changed:

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

Upvotes: 0

Edmond
Edmond

Reputation: 91

If you're getting the getEntrancePrice as 0, remove the web3.toWei function in this part right here in the helpful_scripts.py file:

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

and change to this:

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

Since you already specified at the top(as global variables) that the mock price output decimal place would be 8 and added the additional 8 zeros after 2000 to send the mock constructor an initial price with 8 decimal places, by leaving the toWei function your adding an additional 18 decimal places for a total of 26 which is wrong.

In addition, you're output after deploying the mock is being added another 10 decimal places for a total of 36.

DECIMALS = 8
STARTING_PRICE = 200000000000

My guess is the reason you're getting 0 is because you exceeded the size allowed by the uint8 decimal variable or maybe sending the initial price with 26 decimal places to the constructor takes more gas fees than the gas limit allowed to each block and transaction by ganache. Someone clarify if able!

Upvotes: 0

Ziopelo
Ziopelo

Reputation: 3

Hi I'm following your same course, I too had fallen into the same problem as you. I forgot to replace the address with the variable price_feed_address here:

deploy.py

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

Now everything works.

The only difference I found in our codes is here:

deploy.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()

You call:

entrance_fee = fund_me.getEntranceFee()

Upvotes: 0

Yilmaz
Yilmaz

Reputation: 49661

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

You do not need to multiply with precison. currently, assuming eth price 3000, you are returning

 (50 * (10^18) * (10^18)) / (3000 * 10^10)

 (50 * (10^36)) / (3 * 10^13)

 (50/3)*(10^23)

I think your return value should be

  return mimimumUSD  / price;

Upvotes: 1

Related Questions