11

I would like (if possible) to infer a token price from the blockchain using UniSwap data. After reading the following article, I understood that it is feasible:

https://blocklytics.org/blog/uniswap-api/

“The price of a given token on a given exchange can be calculated as the exchange contract's token_balance divided by its ether_balance.”

My first attempt was to check some transaction data, for example this transaction: https://etherscan.io/tx/0x10de93fd474b5c45035ea5d9ef42172ba6026e024cf77275a72c2b291b118a6d

This page explains in a more readable way (for me) the transaction: https://etherscan.io/address/0x2bf5a5ba29e60682fc56b2fcf9ce07bef4f6196f#events

I understand we have:

uint256 tokens_sold
25661215840000000000
uint256 eth_bought
3014603688879169830

So this would mean a ratio of: 25661215840000000000 / 3014603688879169830 = 8.512302 For this token swap NMR / ETH.

This seems close to the current ration between these two tokens (prices from CoinMarketCap this morning): 203.64 / 23.77 = 8.567101

Is this approach correct?

Also, when I look at the same transaction data in BigQuery, I get:

Input = 0x95e3c50b000000000000000000000000000000000000000000000001641ef3d8f7d3c00000000000000000000000000000000000000000000000000029a07940a8276bdd000000000000000000000000000000000000000000000000000000005ecbd296

which I can decompose into:

0x95e3c50b = MethodID

000000000000000000000000000000000000000000000001641ef3d8f7d3c000 = 25661215840000000000 in Decimal This seems fine: I find the same tokens_sold as above.

00000000000000000000000000000000000000000000000029a07940a8276bdd = 2999530670434773981 What is this?

000000000000000000000000000000000000000000000000000000005ecbd296 = 1590416022 What is this?

I am struggling to find the same eth_bought amount as above: 3014603688879169830.

Can someone help?

10

“The price of a given token on a given exchange can be calculated as the exchange contract's token_balance divided by its ether_balance.”

This description means:

  1. On-chain price: In opposed to off-chain price, which is what you may see on various exchanges, and which can of course be different on every exchange.

  2. Spot price: This is the rate that you will get for 1 wei, but it doesn't tell you how much you will get in return for more than 1 wei.

It is important to understand the difference between rate and return here.

A rate tells you how much you will get for 1 unit.

This is a common method of interaction when you go to any exchange on any street in any country.

For example, you go to an exchange in London and ask how much is the dollar rate, and they will tell you 1 pound = 2 dollars.

In this real-world example, the terms rate and return are equivalent, because the rate is linear, which means that for 2 pounds you'll get 4 dollars, for 3 pounds you'll get 6 dollars and so on.

On UniSwap's trading system (as in many other trading systems on the blockchain), rate and return are not equivalent.

For example, if your ETH/TKN spot-price is 10 on UniSwap, then it means that for 1 wei of your TKN, you will get 10 wei of ETH.

But for 1234 wei of your TKN, you will necessarily get less than 12340 wei of ETH.

This is because your conversion is subjected to slippage (loss).

It may lead you to think that this spot-price is a charade (a hoax).

But it is nevertheless useful for some measurements of a pool.

However, you should definitely not rely on this rate in order to calculate the expected return for some given amount.

In order to do that, you may use Y * x / (X + x), where:

  • x is your input amount of source tokens
  • X is the balance of the pool in the source token
  • Y is the balance of the pool in the target token

Note that as your input amount gets closer to 1, the expected return becomes closer to the rate (i.e., the spot-price, which as quoted from your question at the top of this answer, is Y / X).

5

If you want to do it programmatically, you can query the contract for the uniswap pool for your token.

For example, take USDC token. You can query the uniswap usdc-eth contract to get the # of usdc and eth: the price of eth is then (number of usdc) / (number of eth).

In this case, I'm using the ethers.js library. You can also do this with web3.

import { ethers } from "ethers";
const { ethereum } = window;
if (ethereum) {
    var provider = new ethers.providers.Web3Provider(ethereum);
}

const uniswapUsdcAddress = "0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc";
const uniswapAbi = ... // get the abi from https://etherscan.io/address/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc#code

const getUniswapContract = async address => await new ethers.Contract(address, uniswapAbi, provider);

const getEthUsdPrice = async () => await getUniswapContract(uniswapUsdcAddress)
    .then(contract => contract.getReserves())
    .then(reserves => Number(reserves._reserve0) / Number(reserves._reserve1) * 1e12); // times 10^12 because usdc only has 6 decimals

Result:

await getEthUsdPrice3()
1330.8207823355428
1
  • This gets you the mid_price though, not the execution_price, right? I think you should use getAmountsOut() from the router contract. But I couldn't still get 100% match with the UI price. Maybe do you know how? – senty yesterday
2

For the second half of the question, using https://www.4byte.directory/signatures/?bytes4_signature=0x95e3c50b gives you the tokenToEthSwapInput function.

https://uniswap.org/docs/v1/smart-contracts/exchange/#tokentoethswapinput

tokenToEthSwapInput
Parameter   Type    Description
tokens_sold uint256 Amount of ERC20 tokens sold
min_eth     uint256 Minimum ETH bought
deadline    uint256 Transaction deadline

Deadlines are described as:

Many Uniswap functions include a transaction deadline that sets a time after which a transaction can no longer be executed. This limits miners holding signed transactions for extended durations and executing them based off market movements. It also reduces uncertainty around transactions that take a long time to execute due to issues with gas price.

Deadlines are calculated by adding the desired amount of time (in seconds) to the latest Ethereum block timestamp.

web3.eth.getBlock('latest', (error, block) => {
  deadline = block.timestamp + 300 // transaction expires in 300 seconds (5 minutes)
})

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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