2

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

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
mike515
  • 183
  • 1
  • 14

5 Answers5

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;
    }

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;
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
  • function getPrice()'s return price is alreay 18decimals(3000*10^18),(if eth price is 3000$,the price feed from rinkeby test net is 8decimals,and times 10ˆ10in the function,so it's ``` (50*(10ˆ18)*(10ˆ18))/(3000*(10ˆ18)) (50/3)*(10ˆ(36-18-3)) (50/3)*(10ˆ15) ``` – mike515 Jan 20 '22 at 02:37
  • @mike515 here you are using 3000*(10ˆ18) but in the getPrice function you have return uint256(answer * 10000000000); – Yilmaz Jan 20 '22 at 02:44
  • yes, but the answer(which get from rinkeby testnet) is a 8decimals number like 3000*(10ˆ8),so i caculate the price is 3000*(10ˆ8)*(10ˆ10) – mike515 Jan 20 '22 at 02:51
  • @mike515 I will take a look later – Yilmaz Jan 20 '22 at 02:54
  • thank you for the patience, actually this error didn't show (may be come back later), right now I am face a new error :list out of index . – mike515 Jan 20 '22 at 03:05
0

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()
Ziopelo
  • 3
  • 3
  • Sorry ,I didn't quite get it, ,we both make the pricefeed address a variable in the code, ,to parameterize the pricefeed addres , make it a variable and save the real address in config.yaml file – mike515 Jan 20 '22 at 02:45
0

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!

Edmond
  • 51
  • 3
0

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;
jess
  • 1
  • 1
0

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