конвертация цен с использованием цены chainlink ETHUSD

Я сохраняю стоимость продукта в долларах США в контракте.mapping (string => uint256) productUSD;

Например, если это 52 доллара, я бы сохранил его какproductUSD[_product] = 52;

Теперь, когда люди платят в ETH, я хочу убедиться, что они отправили правильную конвертированную сумму.

то есть0.013 ETH

Chainlink getThePrice()возвращает последнюю ETH/USDцену и обнаружил, что она возвращается вот так.price = 348365740274

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

Простая математика, я могу отбросить 8 знаков после запятой 348365740274и использовать их 3483, чтобы получить преобразованную сумму ETH.

то есть52 / 3483 = 0.0149296583405111 ETH

  1. как мне рассчитать это в солидности? не уверен, как удалить десятичные дроби из348365740274
  2. как проверить, что пользователь отправил правильную сумму eth? то естьrequire(msg.value >= ...)
Вам может понадобиться математическая библиотека с фиксированной точкой. См. мою тему. Какие математические библиотеки с фиксированной или плавающей запятой доступны в Solidity? .

Ответы (2)

Что касается ценовых каналов цепочки, пары ETH (USD/ETH, AAVE/ETH, UNI/ETH и т. д.) имеют 18 знаков после запятой, а пары без ETH (ETH/USD и т. д.) — 8 знаков после запятой. Источник

Целочисленное деление солидности автоматически округляется до 0. ( Справочник по документации ), поэтому вы можете сделать price/10**8округленное целое число для делимого, представляющего 8 знаков после запятой.

Чтобы убедиться, что значение, отправленное с транзакцией, больше некоторого порогового значения при сравнении ETH с долларами США, вы должны разделить минимальное требуемое значение в долларах США на доллары США за ETH, например:

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

вы можете не использовать переменные для экономии газа и использовать значения напрямую, это просто для более ясного объяснения.

Если вы используете версию компилятора Solidity ниже 0.8.x, используйте SafeMath, чтобы позаботиться о целочисленном переполнении и потере значимости.

Нет, я не думаю, что решение hack3r_Om работает. Рассмотрим мой пример:

  • Стоимость эфира в долларах США составляет 2000 долларов. Таким образом, прайсфид даст вам 2000*10**8.
  • Теперь, если вы разделите возвращаемое значение на 10**8, вы получите 2000.
  • Ваш min_required равен 50 долларам, если вы конвертируете эти 50 долларов в эфир к 50/2000, Solidity даст вам ноль, потому что он не любит десятичные числа. Что означает

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

никогда не подведет, потому что 50/2000 = 0 в солидности.

Мое решение, согласно учебнику PatrickAlpha , вы должны умножить min_required и значение, возвращаемое ценой, на некоторое число перед делением, чтобы оно не округлялось. Это мой пример контракта:

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

}