Как работает TWAP в Uniswap V2. Часть 3
Сегодня заканчиваем говорить о TWAP и посмотрим на чуть более сложные математические примеры. И для начала поговорим о том, почему TWAP должен отслеживать два ратио. Вернемся немного к первому посту.
Цена A по отношению к B - это просто A/B и наоборот. Например, если у нас есть 2000 USDC в пуле (без учета десятичных дробей) и 1 Ether, то цена 1 Ether равна просто 2000 USDC / 1 ETH.
Таким образом, цена USDC, выраженная в ETH, - это просто это число с перевернутыми числителем и знаменателем.
Однако мы не можем просто "перевернуть" одну из цен, чтобы получить другую, когда мы накапливаем цены (не уверен в точном переводе accumulating pricing в данном случае).
Рассмотрим следующее. Если наш накопитель цен начинается с 2 и прибавляет 3, мы не можем просто сделать так:
1 / 2+3 != 1/2 + 1/3
Однако цены все еще "в некоторой степени симметричны", поэтому выбор арифметического представления с фиксированной точкой должен иметь одинаковую емкость для целых и для десятичных чисел.
Если Eth в 1 000 раз "ценнее", чем USDC, то USDC в 1 000 раз "менее ценен", чем USDC. И чтобы хранить эти значения более точно, число с фиксированной точкой должно иметь одинаковый размер по обе стороны decimals, поэтому Uniswap выбрал u112x112 (объяснение в первом посте).
Далее пара слов о значении PriceCumulativeLast, которое всегда увеличивается, пока не переполнится, а затем снова продолжает рост.
Uniswap V2 был создан до версии Solidity 0.8.0, поэтому арифметика по умолчанию могла привести к overflow/underflow. Корректные современные реализации ценового оракула должны использовать блок unchecked, чтобы все работало как положено.
В конце концов, значение priceAccumulators и временная метка блока будет переполняться в контракте. В этом случае предыдущий резерв будет выше нового. Когда оракул вычислит изменение цены, он получит отрицательное значение. Но это не имеет значения в силу правил модульной арифметики.
Чтобы упростить задачу, давайте представим целые числа, которые переполняются при 100.
Мы фиксируем priceAccumulator на 80, а через несколько транзакций/блоков priceAccumulator поднимается до 110, но переполняется до 10. Мы вычитаем 80 из 10, что дает -70. Но значение хранится как беззнаковое целое, поэтому оно дает -70 mod(100), что равно 30. Это тот же результат, который мы ожидали бы, если бы переполнения не было (110-80=30).
Это справедливо для всех границ переполнения, а не только для 100 в нашем примере.
То же самое произойдет, если мы переполним временную метку. Поскольку для ее представления мы используем uint32, отрицательных чисел не будет. Опять же, предположим, что для простоты мы переполнимся на 100. Если мы делаем снимок в момент времени 98 и обращаемся к оракулу цен в момент времени 4, то прошло 6 секунд. 4 - 98 % 100 = 6, как и ожидалось.
Теперь вы знаете о TWAP чуточку больше. Далее мы продолжим говорить о Uniswap V2, V3 и других DeFi протоколах.
#uniswap #v2 #twap
Post #1039
796
- 🔥 4
- 👌 2