6

Is it possible to read USD/ETH rate directly from some known smart contract without an oracle?

I have a working solution via an oracle. However, my client says it should be possible to read the current exchange rate directly from an exchange contract, for example Pancake swap or Uniswap, where there would be a pair ETH:USD and there is information (spread?) on both sides so we can read the two values and derive the exchange rate.

Alternatively extract such rate from a pegged stablecoin like DAI.

Has anyone been successful in implementing such direct reading?

3 Answers 3

13

TL;DR: It is not secure to read pricing information from an exchange or other protocol. Always use a decentralized oracle.

You're setting yourself up to be hacked when building smart contracts. Getting price information from a decentralized oracle is ALWAYS what you should be doing. Reading pricing information is especially easy from a decentralized oracle like Chainlink.

This is a great question, and one that can be really tough for new engineers to grasp, let's break it down.

@Mikko in another answer also gives a number of helpful links for more information.


The naive approach

Reading the price from a DEX(decentralized exchange) is easy, especially from AMMs. One of the most popular DEX's Uniswap has a function called getReserves. You can "basically" call this function and calculate the "price" of an asset using this where the assets are reserve0 and reserve1.

function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

To get the price of reserve0, you'd just divide.

price = reserve0 / reserve1

And now you have the price of the asset. However, this can run into MAJOR issues when working with smart contracts. Your "price" is now dependent on the liquidity of the exchange or said another way, your price is dependent on a centralized point of failure.

What do you mean, centralized?

Now you may be thinking "oh, a DEX is a 'decentralized exchange', so what do you mean the price is centralized?". Great question. When you get the price from a DEX, you're getting the price from 1 DEX. The trading of the assets is decentralized, but the pricing of the asset is coming from 1 DEX, a centralized location.

If the reserves of your DEX somehow dramatically change, the DEX may deliver an incredibly inaccurate price, even if it's just for a moment.

The two most common attacks in defi are reentrancy, and oracle manipulation attacks

An easy attack vector that has plagued and destroyed countless protocols is called a "flash loan attack" or more accurately "price oracle attack". Oftentimes, a hacker will see another protocol is using a DEX as their pricing information and will use a flash loan to temporarily drastically increase or decrease the reserves of an asset to inflate or deflate the price and then use that price to attack your protocol. Let's look at an example.

Let's use the same math as above, let's say a protocol has a trading pair of 100 USDT and 1 ETH. If we do the math here:

price = reserve0 / reserve1

This means, that $100 USDT = 1 ETH.

Now let's say an ETH whale or someone using a flash loan comes along and dumps 49 ETH into our exchange. Well, the pools have now changed, and the price will look like this now:

price = 100 / 50

The price of ETH is now $2. $50 -> $2, instantly. If you have liquidations, rewards, or anything based on this price, you have now screwed your users into false actions due to this manipulation.

In fact, the streets are littered with protocols who have been hit exactly by this, or some derivative.

The safer, more reliable, and more accurate approach

Using a decentralized blockchain oracle will protect you from these harms. In the scenario above, even if someone flash loan attacks the DEX, your pricing information is still secured because the data is coming from a decentralized collective. So if one or two data sources are drastically incorrect, it doesn't matter.

Additionally, it's really easy to pull from an oracle feed. The following is some valid solidity code that will pull the latest ETH / USD feed from the kovan testnet.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract PriceConsumerV3 {

    AggregatorV3Interface internal priceFeed;

    /**
     * Network: Kovan
     * Aggregator: ETH/USD
     * Address: 0x9326BFA02ADD2366b30bacB125260Af641031331
     */
    constructor() {
        priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
    }

    /**
     * Returns the latest price
     */
    function getLatestPrice() public view returns (int) {
        (
            uint80 roundID, 
            int price,
            uint startedAt,
            uint timeStamp,
            uint80 answeredInRound
        ) = priceFeed.latestRoundData();
        return price;
    }
}

More information:

1
  • 1
    Wow such a great book quality answer, thank you Patrick. In my case the USD price wasn't impacting anything, it's just to better inform the user, but I'm sure many here will benefit from your answer as I did already. And yes, have gone ahead with Uniswap oracle implementation. Commented Dec 8, 2021 at 21:43
2

You can use the USDC/ETH rate e.g. on Uniswap v2 pools. You can calculate the token price from reserve ratio of tokens on this pools, because reserves follow simple XY liquidity model. Range based liquidity models, like Uniswap v3, often provide their own price oracle.

However, depending on your use case, using any of these prices may not be safe. A price of a single market can be quite easily manipulated and a lot of DeFi projects have been subject to what is known as "economic attack." While the Solidity code itself is safe, the programming logic does not account for huge price swings. On the other hand, if there is no money at the risk, using these kind of prices as a reference price is ok.

More about Uniswap oracles

2
  • 1
    Many thanks for your response Mikko and for improving my question via the edit, very useful and to the point. I was going to mark it as the right answer but then Patrick has posted an even more detailed one. In my case the safety is less of a concern as we only display USD converted price to inform the user and we keep using ETH value as the source of truth. However have decided to stick with the Uniswap implementation based on feedback here. Commented Dec 8, 2021 at 21:38
  • 1
    Patrick is the man with many prices. Commented Dec 8, 2021 at 21:56
1

Patrick gave a great answer on why an exchange based oracle is bad, but unfortunately LINK is pretty far from trustless. Depending on the size of your contract or what you're using it for, an AMM pool might be just fine (and faster), or if it is critical that it's censorship resistant, use an actual decentralized oracle like Tellor.

Your Answer

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

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