2

I am just wondering why Uniswap use reserve and getReserves() instead of just using tokenA.balanceOf(this) and tokenB.balanceOf(this)?

Is there any reason that I do not see, like flash loans or so? (Because it is possible to call .sync() anyway... so I do not realy understand why they use this strange implementation)

Maybe someone can help me there... Thank you :)

To make it more clear:

Why Uniswap use this method:

function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
        _reserve0 = reserve0;
        _reserve1 = reserve1;
        _blockTimestampLast = blockTimestampLast;
    }

And not something like:

function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
            _reserve0 = token0.balanceOf(this);
            _reserve1 = token1.balanceOf(this);
            _blockTimestampLast = blockTimestampLast;
        }
3
  • doesnt reserves refer to the LP pools not the token?
    – johnny 5
    Commented Dec 27, 2021 at 22:35
  • @johnny5 yes this are attributes/methodes of the UniswapV2Pair contract. But it does not matter... I will edit the post to make it more clear what I mean.
    – MaTok
    Commented Dec 27, 2021 at 23:09
  • 1. The later requires more gas.
    – johnny 5
    Commented Dec 27, 2021 at 23:16

1 Answer 1

2

Reserves stored as uint112 and this:

  1. Helps to handle possible underflow/overflow issues (doubling down on precision from 256 to 112, creating more space for calculations)
  2. Saves gas, during intense rewriting the positions of reserve0 and reserve1 in storage

From Uniswap v2 Core White Paper (2.2.1 Precision):

The UQ112.112 format was chosen for a pragmatic reason — because these numbers can be stored in a uint224, this leaves 32 bits of a 256 bit storage slot free. It also happens that the reserves, each stored in a uint112, also leave 32 bits free in a (packed) 256 bit storage slot. These free spaces are used for the accumulation process described above. Specifically, the reserves are stored alongside the timestamp of the most recent block with at least one trade, modded with 232 so that it fits into 32 bits. Additionally, although the price at any given moment (stored as a UQ112.112 number) is guaranteed to fit in 224 bits, the accumulation of this price over an interval is not. The extra 32 bits on the end of the storage slots for the accumulated price of A/B and B/A are used to store overflow bits resulting from repeated summations of prices. This design means that the price oracle only adds an additional three SSTORE operations (a current cost of about 15,000 gas) to the first trade in each block. The primary downside is that 32 bits isn’t quite enough to store timestamp values that will reasonably never overflow. In fact, the date when the Unix timestamp overflows a uint32 is 02/07/2106. To ensure that this system continues to function properly after this date, and every multiple of 232 − 1 seconds thereafter, oracles are simply required to check prices at least once per interval (approximately 136 years). This is because the core method of accumulation (and modding of timestamp), is actually overflow-safe, meaning that trades across overflow intervals can be appropriately accounted for given that oracles are using the proper (simple) overflow arithmetic to compute deltas.

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.