Изучение основных механизмов UniswapV4

ПродвинутыйDec 24, 2023
В этой статье рассматриваются три инновационные особенности UniswapV4 - Flash Accounting, Singleton Contract и Hooks Architecture - с точки зрения кода и реализации.
Изучение основных механизмов UniswapV4

Введение:

С момента анонса UniswapV4 эта своп-платформа претерпела значительные изменения, превратившись из простой своп-платформы в поставщика инфраструктурных услуг. В частности, широкое внимание привлекла функция Hooks в V4. Проведя глубокое исследование, я собрал некоторые материалы, чтобы помочь всем лучше понять эту трансформацию и ее реализацию.

Инновации UniswapV4 направлены не только на улучшение технологии AMM, но и на расширение экосистемы. В частности, эта инновация включает в себя следующие ключевые особенности:

  • Flash Accounting
  • Контракт с синглтоном
  • Hooks Architecture

В следующих разделах я подробно расскажу о значении этих функций и принципах их реализации.

source: https://twitter.com/jermywkh/status/1670779830621851650

Flash Accounting

Бухгалтерский учет с двойной записью

В UniswapV4 используется метод учета, похожий на метод двойной записи, для отслеживания изменений баланса токенов, соответствующих каждой операции. Этот метод двойной записи требует одновременного отражения каждой операции на нескольких счетах и обеспечения баланса активов между этими счетами. Например, предположим, что пользователь обменивает 100 TokenA на 50 TokenB из пула. Запись в бухгалтерской книге будет выглядеть следующим образом:

  • ПОЛЬЗОВАТЕЛЬ: ЖетонА уменьшился на 100 единиц (-100), а ЖетонВ увеличился на 50 единиц (+50).
  • POOL: ЖетонА увеличился на 100 единиц (+100), а ЖетонВ уменьшился на 50 единиц (-50).

Токен Delta и сопутствующие операции

В UniswapV4 этот метод ведения записей используется в основном для основных операций, и переменная хранения с именем lockState.currencyDelta[currency] используется в коде для записи суммы изменений баланса токенов. Если значение этой дельты положительное, оно представляет собой ожидаемое увеличение количества токенов в пуле, в то время как отрицательное значение представляет собой ожидаемое уменьшение количества токенов. Как вариант, если значение положительное, оно указывает на недостаток токенов в пуле (ожидаемая сумма для получения), а отрицательное значение указывает на избыток токенов в пуле (ожидаемая сумма для снятия пользователями). В следующем списке показано влияние различных операций на Token Delta:

  • modifyPosition: Представляет собой операцию добавления/удаления ликвидности. Для ликвидности Add, TokenDelta обновляется с помощью добавления (представляющего собой ожидаемое количество TokenA, которое будет добавлено в пул). Для удаления ликвидности TokenDelta обновляется с помощью вычитания (представляющего собой ожидаемое количество TokenB, которое будет изъято из пула).
  • swap: Представляет собой операцию Swap. Если поменять TokenA на TokenB, то TokenADelta будет обновляться с помощью сложения, а TokenBDelta - с помощью вычитания.
  • Урегулируйте: Сопровождает передачу жетонов в пул. Пул вычисляет увеличение количества токенов до и после и обновляет TokenDelta методом вычитания. Если пул получит ожидаемое количество жетонов, вычитание обнулит TokenDelta.
  • Возьмите: Сопровождает изъятие жетонов из пула. TokenDelta обновляется с помощью добавления, указывая на то, что токены были удалены из пула.
  • Мята: Поведение обновления TokenDelta похоже на "take", но вместо фактического изъятия токенов из пула, в качестве доказательства изъятия выпускаются токены ERC1155, а сами токены остаются в пуле. Позже пользователи могут получить токены из пула, сжигая токены ERC1155. Цель такого подхода может быть двоякой: 1. Сэкономить затраты на газ для передачи токенов ERC20 (вызов контракта + одна меньшая запись в хранилище) и использовать сжигание токенов ERC1155 в будущем для обновления TokenDelta для транзакций. 2. Сохраняйте ликвидность в пуле, чтобы поддерживать глубокий пул ликвидности для лучшего обмена между пользователями.
  • donate: Эта операция объявляет о пожертвовании токенов в пул, но на самом деле токены все равно должны быть переданы в пул с помощью операции "settle". Поэтому в этом случае TokenDelta обновляется с помощью сложения.

Среди этих операций только "settle" и "take" связаны с фактической передачей токенов, в то время как остальные операции отвечают только за обновление значения TokenDelta.

Пример дельты токена

Здесь мы используем простой пример, чтобы проиллюстрировать, как обновить TokenDelta. Предположим, что сегодня мы обменяли 100 TokenA на 50 TokenB:

  1. Перед началом транзакции TokenADelta и TokenBDelta равны 0.
  2. Обмен: Рассчитайте, сколько ТокеновА необходимо получить Пулу и сколько ТокеновВ получит пользователь. В этот момент TokenADelta = 100, TokenBDelta = -50.
  3. Урегулируйте: Отправьте 100 TokenA в Пул и обновите TokenADelta = 100 - 100 = 0.
  4. возьмите: Переведите 50 TokenB из пула на счет пользователя и обновите TokenBDelta = -50 + 50 = 0.
  5. После завершения транзакции TokenADelta и TokenBDelta равны 0.

Когда вся операция обмена завершена, TokenADelta и TokenBDelta обнуляются до 0. Это означает, что операция была полностью сбалансирована, что обеспечивает постоянство баланса счетов.

EIP-1153: Опкоды переходного хранения

Ранее упоминалось, что UniswapV4 использует переменные хранения для записи TokenDelta. Однако в рамках контракта чтение и запись в переменные хранения стоят довольно дорого. Это подводит нас к еще одному EIP, представленному Uniswap: EIP1153 - опкоды переходного хранения.

UniswapV4 планирует использовать опкоды TSTORE и TLOAD, предоставленные EIP1153, для обновления TokenDelta. Переменные хранения, использующие опкоды переходного хранения, будут отбрасываться после завершения транзакции (аналогично переменным памяти), что позволит снизить плату за газ.

Было подтверждено, что EIP1153 будет включен в предстоящее обновление Cancun, и UniswapV4 также заявил, что он появится после обновления Cancun, как сообщается здесь.

источник: https://etherworld.co/2022/12/13/transient-storage-for-beginners/

Флэш-бухгалтерия - блокировка

В UniswapV4 появился механизм блокировки, который означает, что перед выполнением любой операции с пулом Вы должны сначала вызвать PoolManager.lock(), чтобы получить блокировку. Во время выполнения lock() проверяется, равно ли значение TokenDelta 0, в противном случае произойдет возврат. После того, как PoolManager.lock() успешно получен, он вызывает функцию lockAcquired() в msg.sender. Внутри функции lockAcquired() выполняются операции, связанные с пулом, такие как swap и modifyPosition.

Этот процесс показан ниже. Когда пользователю необходимо выполнить операцию обмена токенов, он должен вызвать смарт-контракт с функцией lockAcquired() (именуемый Контрактом обратного вызова). Контракт обратного вызова сначала вызывает PoolManager.lock(), а затем PoolManager вызывает функцию lockAcquired() контракта обратного вызова. Внутри функции lockAcquired() определяется логика, связанная с операциями Pool, такими как swap, settle и take. Наконец, когда блокировка() подходит к концу, PoolManager проверяет, была ли TokenDelta, связанная с этой операцией, сброшена в 0, гарантируя, что баланс активов в Пуле останется нетронутым.

Контракт с синглтоном

Singleton Contract означает, что UniswapV4 отказался от предыдущей модели Factory-Pool. Каждый пул больше не является независимым смарт-контрактом, но все пулы используют один единственный контракт. Такая конструкция, в сочетании с механизмом Flash Accounting, требует только обновления необходимых переменных хранения, что еще больше снижает сложность и стоимость операций.

В приведенном ниже примере с использованием UniswapV3 обмен ETH на DAI потребует как минимум четыре передачи токенов (операции записи в хранилище). Сюда входят многочисленные изменения, зафиксированные для токенов USDC, USDT и DAI. Однако благодаря усовершенствованиям в UniswapV4 в сочетании с механизмом Flash Accounting требуется только одна передача токена (перемещение DAI от пула к пользователю), что значительно сокращает количество операций и расходы.

source: https://twitter.com/Uniswap/status/1671208668304486404

Hooks Architecture

В последнем обновлении UniswapV4 наиболее заметной особенностью является архитектура крючков. Это обновление обеспечивает большую гибкость в плане доступности Пула. Крючки - это дополнительные действия, которые запускаются через Контракт крючков при выполнении определенных операций с Пулом. Эти действия делятся на initialize (создание пула), modifyPosition (добавление/удаление ликвидности), swap и donate. В каждой категории есть действия до и после выполнения.

  • beforeInitialize / afterInitialize
  • beforeModifyPosition / afterModifyPosition
  • beforeSwap / afterSwap
  • доДоната / послеДоната

Такая конструкция позволяет пользователям выполнять пользовательскую логику до и после определенных операций, что делает ее более гибкой и расширяет функциональность UniswapV4.

источник: https://github.com/Uniswap/v4-core/blob/main/whitepaper-v4-draft.pdf

Пример крючка - крючок лимитного ордера

Далее мы используем пример лимитного ордера, чтобы объяснить реальный процесс работы крючков в UniswapV4. Прежде чем мы начнем, давайте вкратце объясним принцип реализации лимитных ордеров в UniswapV4.

Механизм лимитных заказов UniswapV4

Реализация лимитного ордера в UniswapV4 работает, добавляя ликвидность в определенный ценовой диапазон, а затем выполняя операцию удаления ликвидности, если ликвидность в этом диапазоне поменялась местами.

Например, допустим, мы добавляем ликвидность в ценовой диапазон 1900-2000 для ETH, и тогда цена ETH поднимается с 1800 до 2100. На данный момент вся ликвидность ETH, которую мы ранее добавили в ценовом диапазоне 1900-2000, была обменена на USDC (предполагается, что в пуле ETH-USDC). Убрав ликвидность в этот момент, мы можем добиться эффекта, аналогичного исполнению рыночного ордера на ETH в текущем ценовом диапазоне 1900-2000.

Лимитный ордер Контракт на крючок

Этот пример взят с GitHub из UniswapV4. В этом примере контракт Limit Order Hook предоставляет два крючка, а именно afterInitialize и afterSwap. Хук afterInitialize используется для записи ценового диапазона (тика) при создании пула, чтобы определить, какие лимитные ордера были сопоставлены после того, как кто-то поменялся.

Разместить ордер

Когда пользователю нужно разместить ордер, контракт Hook выполняет операцию добавления ликвидности на основе указанного пользователем диапазона цен и количества. В контракте Hook для лимитных ордеров Вы можете увидеть функцию place(). Основная логика заключается в вызове функции lockAcquiredPlace() после получения блокировки для выполнения операции добавления ликвидности, что эквивалентно размещению лимитного ордера.

источник: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L246

Крючок afterSwap

После того, как пользователь завершит обмен токенами в этом пуле, пул вызовет функцию afterSwap() контракта Hook. Основная логика afterSwap заключается в том, чтобы удалить ликвидность ранее размещенных ордеров, которые были исполнены между предыдущим и текущим ценовым диапазоном. Такое поведение эквивалентно тому, что заказ будет выполнен.

источник: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L192

Поток лимитных заказов

Вот блок-схема, иллюстрирующая процесс выполнения лимитного ордера:

  1. Устройство размещения заказов отправляет заказ контракту Hook.
  2. Контракт Hook выполняет операции по добавлению ликвидности на основе информации о заказе.
  3. Обычные пользователи выполняют операции Token Swap в пуле.
  4. После завершения операции обмена токенов Пул вызывает функцию afterSwap() контракта Hook.
  5. Контракт Hook выполняет операции по удалению ликвидности для заполненных лимитных ордеров, основываясь на изменении ценового диапазона обмененных токенов.

Выше описан весь процесс реализации Limit-Order с помощью механизма Hook.

Крючок: Прочие особенности

У Хукса есть несколько интересных моментов, которыми, на мой взгляд, стоит поделиться.

Бит адреса контракта крючков

Решение о выполнении определенных операций до/после определяется крайним левым 1 байтом адреса контракта Hook. 1 байт равен 8 битам, что соответствует 8 дополнительным действиям. Пул будет проверять, равен ли бит этого действия 1, чтобы определить, вызывать ли соответствующую функцию крючка контракта Hook. Это также означает, что адрес контракта Hook должен быть разработан особым образом и не может быть произвольно выбран в качестве контракта Hook. Эта конструкция в основном направлена на снижение потребления газа и перенос затрат на контрактное развертывание для достижения более эффективной работы. (PS: На практике различные соли CREATE2 могут быть использованы для перебора адресов контрактов, удовлетворяющих условиям)

Динамическая плата

Помимо возможности выполнять дополнительные операции до и после каждого действия, крючки также поддерживают реализацию динамических сборов. При создании пула Вы можете указать, нужно ли включить динамическую оплату. Если динамические комиссии включены, при обмене токенов вызывается функция getFee() контракта Hook. Контракт с Крюком может определять размер взимаемой платы в зависимости от текущего состояния Пула. Такая конструкция позволяет гибко рассчитывать плату в зависимости от фактических обстоятельств, что повышает гибкость системы.

Создание бассейна

Каждый пул должен определить контракт с крючком во время своего создания, и он не может быть изменен после этого (хотя разные пулы могут использовать один и тот же контракт с крючком). Это происходит потому, что крючки считаются частью PoolKey, а PoolManager использует PoolKey, чтобы определить, с каким пулом работать. Даже если активы одинаковы, если договор Hook отличается, он будет считаться другим Pool. Такая конструкция позволяет управлять состоянием и операциями разных пулов независимо друг от друга, обеспечивая согласованность пулов. Однако это также увеличивает сложность маршрутизации по мере увеличения количества пулов (возможно, UniswapX призван решить эту проблему).

TL;DR

  • Flash Accounting используется для отслеживания изменений количества каждого токена, чтобы гарантировать, что все изменения будут обнулены после завершения транзакции. Чтобы сэкономить на оплате газа, Flash Accounting использует специальный метод хранения, предусмотренный EIP1153.
  • Конструкция Singleton Contract помогает снизить расход газа, избегая обновления нескольких переменных хранения.
  • Архитектура крючков предоставляет дополнительные операции, разделенные на этапы до и после выполнения. Это позволяет добиться большей гибкости в работе каждого пула, но также усложняет маршрутизацию пулов.

UniswapV4 явно делает акцент на расширении всей экосистемы Uniswap, превращая ее в инфраструктуру, позволяющую создавать больше сервисов на основе пулов Uniswap. Это помогает повысить конкурентоспособность Uniswap и снижает риск, связанный с альтернативными услугами. Однако достигнет ли он ожидаемого успеха, еще предстоит выяснить. Среди основных моментов - сочетание Flash Accounting и EIP1153, и мы уверены, что в будущем все больше сервисов будут использовать эти функции, что приведет к появлению различных сценариев применения. Это основная концепция UniswapV4, и мы надеемся, что она дает более глубокое понимание того, как работает UniswapV4. Если в статье есть ошибки, пожалуйста, не стесняйтесь указывать на них. Мы также приветствуем обсуждения и отзывы.

Наконец, мы хотели бы поблагодарить Антона Ченга и Пин Чена за рецензирование статьи и ценные замечания!

Отказ от ответственности:

  1. Эта статья перепечатана с[medium]. Все авторские права принадлежат оригинальному автору[林瑋宸 Альберт Лин]. Если у Вас есть возражения против этой перепечатки, пожалуйста, свяжитесь с командой GateLearn(gatelearn@gate.io), и они оперативно рассмотрят их.
  2. Предупреждение об ответственности: Мнения и взгляды, выраженные в этой статье, принадлежат исключительно автору и не являются инвестиционным советом.
  3. Перевод статьи на другие языки осуществляется командой Gate Learn. Если не указано, копирование, распространение или плагиат переведенных статей запрещены.
* Информация не предназначена и не является финансовым советом или любой другой рекомендацией любого рода, предложенной или одобренной Gate.io.
* Эта статья не может быть опубликована, передана или скопирована без ссылки на Gate.io. Нарушение является нарушением Закона об авторском праве и может повлечь за собой судебное разбирательство.

Изучение основных механизмов UniswapV4

ПродвинутыйDec 24, 2023
В этой статье рассматриваются три инновационные особенности UniswapV4 - Flash Accounting, Singleton Contract и Hooks Architecture - с точки зрения кода и реализации.
Изучение основных механизмов UniswapV4

Введение:

С момента анонса UniswapV4 эта своп-платформа претерпела значительные изменения, превратившись из простой своп-платформы в поставщика инфраструктурных услуг. В частности, широкое внимание привлекла функция Hooks в V4. Проведя глубокое исследование, я собрал некоторые материалы, чтобы помочь всем лучше понять эту трансформацию и ее реализацию.

Инновации UniswapV4 направлены не только на улучшение технологии AMM, но и на расширение экосистемы. В частности, эта инновация включает в себя следующие ключевые особенности:

  • Flash Accounting
  • Контракт с синглтоном
  • Hooks Architecture

В следующих разделах я подробно расскажу о значении этих функций и принципах их реализации.

source: https://twitter.com/jermywkh/status/1670779830621851650

Flash Accounting

Бухгалтерский учет с двойной записью

В UniswapV4 используется метод учета, похожий на метод двойной записи, для отслеживания изменений баланса токенов, соответствующих каждой операции. Этот метод двойной записи требует одновременного отражения каждой операции на нескольких счетах и обеспечения баланса активов между этими счетами. Например, предположим, что пользователь обменивает 100 TokenA на 50 TokenB из пула. Запись в бухгалтерской книге будет выглядеть следующим образом:

  • ПОЛЬЗОВАТЕЛЬ: ЖетонА уменьшился на 100 единиц (-100), а ЖетонВ увеличился на 50 единиц (+50).
  • POOL: ЖетонА увеличился на 100 единиц (+100), а ЖетонВ уменьшился на 50 единиц (-50).

Токен Delta и сопутствующие операции

В UniswapV4 этот метод ведения записей используется в основном для основных операций, и переменная хранения с именем lockState.currencyDelta[currency] используется в коде для записи суммы изменений баланса токенов. Если значение этой дельты положительное, оно представляет собой ожидаемое увеличение количества токенов в пуле, в то время как отрицательное значение представляет собой ожидаемое уменьшение количества токенов. Как вариант, если значение положительное, оно указывает на недостаток токенов в пуле (ожидаемая сумма для получения), а отрицательное значение указывает на избыток токенов в пуле (ожидаемая сумма для снятия пользователями). В следующем списке показано влияние различных операций на Token Delta:

  • modifyPosition: Представляет собой операцию добавления/удаления ликвидности. Для ликвидности Add, TokenDelta обновляется с помощью добавления (представляющего собой ожидаемое количество TokenA, которое будет добавлено в пул). Для удаления ликвидности TokenDelta обновляется с помощью вычитания (представляющего собой ожидаемое количество TokenB, которое будет изъято из пула).
  • swap: Представляет собой операцию Swap. Если поменять TokenA на TokenB, то TokenADelta будет обновляться с помощью сложения, а TokenBDelta - с помощью вычитания.
  • Урегулируйте: Сопровождает передачу жетонов в пул. Пул вычисляет увеличение количества токенов до и после и обновляет TokenDelta методом вычитания. Если пул получит ожидаемое количество жетонов, вычитание обнулит TokenDelta.
  • Возьмите: Сопровождает изъятие жетонов из пула. TokenDelta обновляется с помощью добавления, указывая на то, что токены были удалены из пула.
  • Мята: Поведение обновления TokenDelta похоже на "take", но вместо фактического изъятия токенов из пула, в качестве доказательства изъятия выпускаются токены ERC1155, а сами токены остаются в пуле. Позже пользователи могут получить токены из пула, сжигая токены ERC1155. Цель такого подхода может быть двоякой: 1. Сэкономить затраты на газ для передачи токенов ERC20 (вызов контракта + одна меньшая запись в хранилище) и использовать сжигание токенов ERC1155 в будущем для обновления TokenDelta для транзакций. 2. Сохраняйте ликвидность в пуле, чтобы поддерживать глубокий пул ликвидности для лучшего обмена между пользователями.
  • donate: Эта операция объявляет о пожертвовании токенов в пул, но на самом деле токены все равно должны быть переданы в пул с помощью операции "settle". Поэтому в этом случае TokenDelta обновляется с помощью сложения.

Среди этих операций только "settle" и "take" связаны с фактической передачей токенов, в то время как остальные операции отвечают только за обновление значения TokenDelta.

Пример дельты токена

Здесь мы используем простой пример, чтобы проиллюстрировать, как обновить TokenDelta. Предположим, что сегодня мы обменяли 100 TokenA на 50 TokenB:

  1. Перед началом транзакции TokenADelta и TokenBDelta равны 0.
  2. Обмен: Рассчитайте, сколько ТокеновА необходимо получить Пулу и сколько ТокеновВ получит пользователь. В этот момент TokenADelta = 100, TokenBDelta = -50.
  3. Урегулируйте: Отправьте 100 TokenA в Пул и обновите TokenADelta = 100 - 100 = 0.
  4. возьмите: Переведите 50 TokenB из пула на счет пользователя и обновите TokenBDelta = -50 + 50 = 0.
  5. После завершения транзакции TokenADelta и TokenBDelta равны 0.

Когда вся операция обмена завершена, TokenADelta и TokenBDelta обнуляются до 0. Это означает, что операция была полностью сбалансирована, что обеспечивает постоянство баланса счетов.

EIP-1153: Опкоды переходного хранения

Ранее упоминалось, что UniswapV4 использует переменные хранения для записи TokenDelta. Однако в рамках контракта чтение и запись в переменные хранения стоят довольно дорого. Это подводит нас к еще одному EIP, представленному Uniswap: EIP1153 - опкоды переходного хранения.

UniswapV4 планирует использовать опкоды TSTORE и TLOAD, предоставленные EIP1153, для обновления TokenDelta. Переменные хранения, использующие опкоды переходного хранения, будут отбрасываться после завершения транзакции (аналогично переменным памяти), что позволит снизить плату за газ.

Было подтверждено, что EIP1153 будет включен в предстоящее обновление Cancun, и UniswapV4 также заявил, что он появится после обновления Cancun, как сообщается здесь.

источник: https://etherworld.co/2022/12/13/transient-storage-for-beginners/

Флэш-бухгалтерия - блокировка

В UniswapV4 появился механизм блокировки, который означает, что перед выполнением любой операции с пулом Вы должны сначала вызвать PoolManager.lock(), чтобы получить блокировку. Во время выполнения lock() проверяется, равно ли значение TokenDelta 0, в противном случае произойдет возврат. После того, как PoolManager.lock() успешно получен, он вызывает функцию lockAcquired() в msg.sender. Внутри функции lockAcquired() выполняются операции, связанные с пулом, такие как swap и modifyPosition.

Этот процесс показан ниже. Когда пользователю необходимо выполнить операцию обмена токенов, он должен вызвать смарт-контракт с функцией lockAcquired() (именуемый Контрактом обратного вызова). Контракт обратного вызова сначала вызывает PoolManager.lock(), а затем PoolManager вызывает функцию lockAcquired() контракта обратного вызова. Внутри функции lockAcquired() определяется логика, связанная с операциями Pool, такими как swap, settle и take. Наконец, когда блокировка() подходит к концу, PoolManager проверяет, была ли TokenDelta, связанная с этой операцией, сброшена в 0, гарантируя, что баланс активов в Пуле останется нетронутым.

Контракт с синглтоном

Singleton Contract означает, что UniswapV4 отказался от предыдущей модели Factory-Pool. Каждый пул больше не является независимым смарт-контрактом, но все пулы используют один единственный контракт. Такая конструкция, в сочетании с механизмом Flash Accounting, требует только обновления необходимых переменных хранения, что еще больше снижает сложность и стоимость операций.

В приведенном ниже примере с использованием UniswapV3 обмен ETH на DAI потребует как минимум четыре передачи токенов (операции записи в хранилище). Сюда входят многочисленные изменения, зафиксированные для токенов USDC, USDT и DAI. Однако благодаря усовершенствованиям в UniswapV4 в сочетании с механизмом Flash Accounting требуется только одна передача токена (перемещение DAI от пула к пользователю), что значительно сокращает количество операций и расходы.

source: https://twitter.com/Uniswap/status/1671208668304486404

Hooks Architecture

В последнем обновлении UniswapV4 наиболее заметной особенностью является архитектура крючков. Это обновление обеспечивает большую гибкость в плане доступности Пула. Крючки - это дополнительные действия, которые запускаются через Контракт крючков при выполнении определенных операций с Пулом. Эти действия делятся на initialize (создание пула), modifyPosition (добавление/удаление ликвидности), swap и donate. В каждой категории есть действия до и после выполнения.

  • beforeInitialize / afterInitialize
  • beforeModifyPosition / afterModifyPosition
  • beforeSwap / afterSwap
  • доДоната / послеДоната

Такая конструкция позволяет пользователям выполнять пользовательскую логику до и после определенных операций, что делает ее более гибкой и расширяет функциональность UniswapV4.

источник: https://github.com/Uniswap/v4-core/blob/main/whitepaper-v4-draft.pdf

Пример крючка - крючок лимитного ордера

Далее мы используем пример лимитного ордера, чтобы объяснить реальный процесс работы крючков в UniswapV4. Прежде чем мы начнем, давайте вкратце объясним принцип реализации лимитных ордеров в UniswapV4.

Механизм лимитных заказов UniswapV4

Реализация лимитного ордера в UniswapV4 работает, добавляя ликвидность в определенный ценовой диапазон, а затем выполняя операцию удаления ликвидности, если ликвидность в этом диапазоне поменялась местами.

Например, допустим, мы добавляем ликвидность в ценовой диапазон 1900-2000 для ETH, и тогда цена ETH поднимается с 1800 до 2100. На данный момент вся ликвидность ETH, которую мы ранее добавили в ценовом диапазоне 1900-2000, была обменена на USDC (предполагается, что в пуле ETH-USDC). Убрав ликвидность в этот момент, мы можем добиться эффекта, аналогичного исполнению рыночного ордера на ETH в текущем ценовом диапазоне 1900-2000.

Лимитный ордер Контракт на крючок

Этот пример взят с GitHub из UniswapV4. В этом примере контракт Limit Order Hook предоставляет два крючка, а именно afterInitialize и afterSwap. Хук afterInitialize используется для записи ценового диапазона (тика) при создании пула, чтобы определить, какие лимитные ордера были сопоставлены после того, как кто-то поменялся.

Разместить ордер

Когда пользователю нужно разместить ордер, контракт Hook выполняет операцию добавления ликвидности на основе указанного пользователем диапазона цен и количества. В контракте Hook для лимитных ордеров Вы можете увидеть функцию place(). Основная логика заключается в вызове функции lockAcquiredPlace() после получения блокировки для выполнения операции добавления ликвидности, что эквивалентно размещению лимитного ордера.

источник: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L246

Крючок afterSwap

После того, как пользователь завершит обмен токенами в этом пуле, пул вызовет функцию afterSwap() контракта Hook. Основная логика afterSwap заключается в том, чтобы удалить ликвидность ранее размещенных ордеров, которые были исполнены между предыдущим и текущим ценовым диапазоном. Такое поведение эквивалентно тому, что заказ будет выполнен.

источник: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L192

Поток лимитных заказов

Вот блок-схема, иллюстрирующая процесс выполнения лимитного ордера:

  1. Устройство размещения заказов отправляет заказ контракту Hook.
  2. Контракт Hook выполняет операции по добавлению ликвидности на основе информации о заказе.
  3. Обычные пользователи выполняют операции Token Swap в пуле.
  4. После завершения операции обмена токенов Пул вызывает функцию afterSwap() контракта Hook.
  5. Контракт Hook выполняет операции по удалению ликвидности для заполненных лимитных ордеров, основываясь на изменении ценового диапазона обмененных токенов.

Выше описан весь процесс реализации Limit-Order с помощью механизма Hook.

Крючок: Прочие особенности

У Хукса есть несколько интересных моментов, которыми, на мой взгляд, стоит поделиться.

Бит адреса контракта крючков

Решение о выполнении определенных операций до/после определяется крайним левым 1 байтом адреса контракта Hook. 1 байт равен 8 битам, что соответствует 8 дополнительным действиям. Пул будет проверять, равен ли бит этого действия 1, чтобы определить, вызывать ли соответствующую функцию крючка контракта Hook. Это также означает, что адрес контракта Hook должен быть разработан особым образом и не может быть произвольно выбран в качестве контракта Hook. Эта конструкция в основном направлена на снижение потребления газа и перенос затрат на контрактное развертывание для достижения более эффективной работы. (PS: На практике различные соли CREATE2 могут быть использованы для перебора адресов контрактов, удовлетворяющих условиям)

Динамическая плата

Помимо возможности выполнять дополнительные операции до и после каждого действия, крючки также поддерживают реализацию динамических сборов. При создании пула Вы можете указать, нужно ли включить динамическую оплату. Если динамические комиссии включены, при обмене токенов вызывается функция getFee() контракта Hook. Контракт с Крюком может определять размер взимаемой платы в зависимости от текущего состояния Пула. Такая конструкция позволяет гибко рассчитывать плату в зависимости от фактических обстоятельств, что повышает гибкость системы.

Создание бассейна

Каждый пул должен определить контракт с крючком во время своего создания, и он не может быть изменен после этого (хотя разные пулы могут использовать один и тот же контракт с крючком). Это происходит потому, что крючки считаются частью PoolKey, а PoolManager использует PoolKey, чтобы определить, с каким пулом работать. Даже если активы одинаковы, если договор Hook отличается, он будет считаться другим Pool. Такая конструкция позволяет управлять состоянием и операциями разных пулов независимо друг от друга, обеспечивая согласованность пулов. Однако это также увеличивает сложность маршрутизации по мере увеличения количества пулов (возможно, UniswapX призван решить эту проблему).

TL;DR

  • Flash Accounting используется для отслеживания изменений количества каждого токена, чтобы гарантировать, что все изменения будут обнулены после завершения транзакции. Чтобы сэкономить на оплате газа, Flash Accounting использует специальный метод хранения, предусмотренный EIP1153.
  • Конструкция Singleton Contract помогает снизить расход газа, избегая обновления нескольких переменных хранения.
  • Архитектура крючков предоставляет дополнительные операции, разделенные на этапы до и после выполнения. Это позволяет добиться большей гибкости в работе каждого пула, но также усложняет маршрутизацию пулов.

UniswapV4 явно делает акцент на расширении всей экосистемы Uniswap, превращая ее в инфраструктуру, позволяющую создавать больше сервисов на основе пулов Uniswap. Это помогает повысить конкурентоспособность Uniswap и снижает риск, связанный с альтернативными услугами. Однако достигнет ли он ожидаемого успеха, еще предстоит выяснить. Среди основных моментов - сочетание Flash Accounting и EIP1153, и мы уверены, что в будущем все больше сервисов будут использовать эти функции, что приведет к появлению различных сценариев применения. Это основная концепция UniswapV4, и мы надеемся, что она дает более глубокое понимание того, как работает UniswapV4. Если в статье есть ошибки, пожалуйста, не стесняйтесь указывать на них. Мы также приветствуем обсуждения и отзывы.

Наконец, мы хотели бы поблагодарить Антона Ченга и Пин Чена за рецензирование статьи и ценные замечания!

Отказ от ответственности:

  1. Эта статья перепечатана с[medium]. Все авторские права принадлежат оригинальному автору[林瑋宸 Альберт Лин]. Если у Вас есть возражения против этой перепечатки, пожалуйста, свяжитесь с командой GateLearn(gatelearn@gate.io), и они оперативно рассмотрят их.
  2. Предупреждение об ответственности: Мнения и взгляды, выраженные в этой статье, принадлежат исключительно автору и не являются инвестиционным советом.
  3. Перевод статьи на другие языки осуществляется командой Gate Learn. Если не указано, копирование, распространение или плагиат переведенных статей запрещены.
* Информация не предназначена и не является финансовым советом или любой другой рекомендацией любого рода, предложенной или одобренной Gate.io.
* Эта статья не может быть опубликована, передана или скопирована без ссылки на Gate.io. Нарушение является нарушением Закона об авторском праве и может повлечь за собой судебное разбирательство.
Начните торговать сейчас
Зарегистрируйтесь сейчас и получите ваучер на
$100
!