3

I'm storing a product's USD value in contract. mapping (string => uint256) productUSD;

For example, if it's $52 I'd store it as productUSD[_product] = 52;

Now, when people paying in ETH, I want to make sure they sent in a correct converted amount.

i.e. 0.013 ETH

Chainlink's getThePrice() returns the latest ETH/USD price and found it was returning like this. price = 348365740274

    function getThePrice() public view returns (int) {
        (
            uint80 roundID, 
            int price,
            uint startedAt,
            uint timeStamp,
            uint80 answeredInRound
        ) = priceFeed.latestRoundData();
        return price;
    }

Simple math, I can drop 8 decimals from 348365740274 and use 3483 to get a converted ETH amount

i.e. 52 / 3483 = 0.0149296583405111 ETH

  1. how do I calculate this in solidity? not sure how to drop decimals from 348365740274
  2. how do I verify user has sent correct eth amount? i.e. require(msg.value >= ...)
1

2 Answers 2

6
+50

As far as chainlink price feeds are concerned, ETH pairs (USD/ETH, AAVE/ETH, UNI/ETH, etc.) have 18 decimals while non-ETH pairs (ETH/USD, etc.) have 8 decimals. Source

solidity integer division automatically rounds off towards 0.(Docs Reference), so you can do price/10**8 to get rounded off integer for dividend representing 8 decimals.

To verify the value sent with the transaction is greater than some threshold when ETH compared with USD, you would divide the minimum required value in USD with USD per ETH, for e.g:

int min_required = 50; // minimum required in USD
int _price = getThePrice() / 10 ** 8; // price of 1 ether in USD

require(msg.value >= min_required / _price, "NOT ENOUGH ETHER");

you can omit using variables to save gas and use values directly, this is just for a clearer explanation.

If you are using a solidity compiler version less than 0.8.x then use SafeMath to take care of integer overflow and underflow

0
2

No, I don't think hack3r_Om's solution works. Consider my example:

  • The ether price in USD is 2000 dollars. So the pricefeed will give you 2000*10**8.
  • Now if you divide the returned value by 10**8, you will get 2000.
  • Your min_required is 50 dollars, if you convert that 50 dollars to ether by 50/2000, solidity will give you zero because it don't like decimal. Which means the

require(msg.value >= min_required / _price, "NOT ENOUGH ETHER");

will never fails, because 50/2000 = 0 in solidity.

My solution is, according to PatrickAlpha's tutorial, you have to multiply your min_required and the pricefeed returned value to some number before dividing, so that it will not be rounded. This is my example contract:

contract Test{
uint256 minRequiredUSD;
uint256 etherPriceUSD;
uint256 public minRequiredEther;

constructor() {
    minRequiredUSD = 50*10**18; // multiply your minRequired to 10**18
    etherPriceUSD = 2000*10**18; // multiply your etherPrice to 10**18

    // this means (50*10*18)/2000, it converts your minReqiredEther to wei first
    // before divide. The result is 25*10**15 wei.
    minRequiredEther = (minRequiredUSD*10**18)/etherPriceUSD; 
} 

event ReceivedEther(uint256 _amount);
function donate() public payable {
    require(msg.value > minRequireEther);
    emit ReceivedEther(msg.value);
}

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.