Reputation: 343
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?
Upvotes: 2
Views: 1549
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
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
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
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
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