Предисловие
Благодаря быстрому развитию децентрализованных финансов (DeFi) Uniswap, как ведущая децентрализованная биржа, оказалась в авангарде инноваций. В этой статье будет представлен углубленный анализ основного механизма протокола Uniswap v3 и подробное объяснение его функционального дизайна, включая ключевые функции, такие как централизованная ликвидность, множественные ставки, обмен токенами и мгновенные кредиты, а также предоставятся соответствующие точки аудита для аудиторы. (Примечание. Изображения в этой статье можно просмотреть в высоком разрешении по адресу https://www.figma.com/board/QyIpAUR93MxZ4XZZf2QjDk/uniswap-v3.)
Анализ архитектуры
Протокол Uniswap v3 в основном состоит из четырех модулей:
- PositionManager: основной интерфейс для пользователей для выполнения операций с ликвидностью, с помощью которого пользователи могут создавать пулы токенов, предоставлять/удалять ликвидность и использовать ERC721 в качестве учетных данных для поставщиков ликвидности (LP).
- SwapRouter: доступ пользователей к обмену токенов. Пользователи могут выполнять операции обмена токенов через этот модуль.
- Пул: отвечает за реализацию транзакций токенов, управление ликвидностью, сбор комиссий за транзакции и функции управления данными Oracle. Среди них механизм Tick делит диапазон цен на несколько тонких шкал.
- Фабрика: используется для создания контрактов пула и управления ими.
Процесс сортировки
Создать пару токенов
Пользователи могут сделать это с помощью функции createAndInitializePoolIfNecessary. Пользователю необходимо передать token0, token1, комиссию за обработку (комиссию) и начальную цену () пары токенов. Сначала система проверит, существует ли уже пара токенов с помощью функции getPool. Если она не была создана, будет вызвана функция createPool и для развертывания торговой пары будет использована инструкция CREATE2. Наконец, функция инициализации используется для завершения инициализации цены, комиссии за обработку, тика, оракула и других связанных параметров.
Обеспечить ликвидность
Обеспечить ликвидность
Пользователи могут создавать новые позиции ликвидности и генерировать соответствующие NFT с помощью функции монетного двора или добавлять ликвидность к существующим позициям ликвидности NFT с помощью функции увеличения ликвидности. Сначала система проверит, выполнена ли транзакция в указанном диапазоне времени, а затем вызовет функцию addLiquidity для завершения конкретной операции. В этой функции сначала рассчитываются адрес и ликвидность пула, а затем вызывается _updatePosition для обновления позиции пользователя, изменения нижнего и верхнего тика, а также общей накопленной комиссии за обработку. Впоследствии система добавляет ликвидность через _modifyPosition, проверяет соответствие тика условиям верхней и нижней границы, возвращает рассчитанное количество token0 и token1 (int256) и отправляет его в пул. Наконец, система обновляет соответствующую информацию о позиции на основе идентификатора токена пользователя.
Удалить ликвидность
Пользователи могут удалить ликвидность с помощью функции уменьшения ликвидности. Сначала система проверит авторитетность сертификата LP и срок действия транзакции. При условии, что в пуле имеется достаточная ликвидность, вызовите функцию сжигания для удаления ликвидности. Впоследствии система проверит, соответствует ли фактическое количество удаленных токенов минимальным требованиям, установленным пользователем, и соответствующим образом обновит информацию о позиции пользователя.
менять
Пользователи могут указать количество токенов, подлежащих выплате, и минимальное количество токенов, которые, как ожидается, будут получены с помощью функции точного ввода, или указать максимальное количество токенов, подлежащих выплате, и установить количество токенов, которые, как ожидается, будут получены, с помощью функции точного вывода. Система сначала анализирует путь (путь), а затем последовательно вызывает функцию «exactInputInternal» или «exactOutputInternal» для завершения каждого шага операции подкачки.
В функции обмена система сначала блокирует разблокированное состояние, чтобы другие транзакции не мешали обновлению переменных состояния. После входа в цикл система находит следующую цену транзакции через тик и вызывает функцию ComputeSwapStep для расчета обмена на каждом этапе, пока tokenIn или tokenOut не достигнет ожидания пользователя. В то же время система обновит соответствующие значения комиссий, ликвидности, тиков и цен. Если тик изменится, данные Oracle также необходимо обновить. После завершения этих операций система выплачивает пользователю tokenOut, а пользователь выплачивает tokenIn через функцию обратного вызова uniswapV3SwapCallback. Этот механизм можно рассматривать как флэш-своп. Впоследствии система проверит соответствие баланса контракта и разблокирует статус разблокировки после подтверждения.
Транзакция завершается успешно, когда все операции обмена на пути завершены и транзакция соответствует ожиданиям пользователя.
вспышка
Пользователи могут выполнять операции флэш-кредитования с помощью флэш-функций. Сначала система рассчитает комиссию за заимствование, а затем отправит токен, необходимый пользователю, на указанный адрес кредитования. Далее система вызывает обратно функцию uniswapV3FlashCallback, реализованную пользователем, и пользователь завершает операцию погашения в этой функции. Система проверит изменение баланса контракта после обратного вызова, чтобы убедиться, что оно соответствует сумме кредита пользователя, и обновит соответствующую комиссию за обработку. В дополнение к функции флэш-займа пользователи также могут реализовать аналогичные функции флэш-кредитования посредством операций свопа, то есть сначала заимствовать, а затем погашать токены в процессе транзакции.
Точки аудита
Точки аудита
1. Проверьте, вызывается ли returnETH после операции свопа.
В функции точного ввода пользователю необходимо указать количество токенов для оплаты и минимальное количество токенов, которое ожидается получить. Перед вызовом uniswapV3SwapCallback система пересчитает суммы 0 и 1, чтобы гарантировать, что пользователи смогут отправлять токены точно. Однако при обмене с помощью ETH пользователям необходимо отправить ETH вместе с транзакцией. Даже если весь ETH не будет использован во время транзакции, функция не вернет излишки автоматически. Функция strictInput возвращает только sumOut, поэтому трейдеры не могут напрямую узнать, сколько ETH фактически было израсходовано этой биржей.
Кроме того, любой может вызвать функцию returnETH, чтобы вывести из контракта неиспользованный ETH. Поэтому рекомендуется проверить, вызывается ли returnETH после операции обмена, чтобы пользователи не оставляли неиспользуемые ETH в протоколе, или использовать функцию MultiCall для выполнения нескольких вызовов функций за одну операцию.
2. Проверьте, реализован ли TWAP для получения цены оракула.
При использовании Uniswap в качестве источника цен может возникнуть риск манипулирования ценами, когда внешний протокол напрямую обращается к Slot0 для получения sqrtPriceX96. Злоумышленники могут манипулировать состоянием пула ликвидности посредством свопа и других методов для получения выгодных цен при выполнении транзакций.
Чтобы снизить этот риск, разработчикам рекомендуется дополнительно внедрить средневзвешенную по времени цену (TWAP) для получения цен, поскольку TWAP может эффективно снизить влияние резких колебаний цен в краткосрочной перспективе, что затрудняет манипулирование ценами.
3. Рекомендуется разрешить пользователям самостоятельно устанавливать параметры проскальзывания.
Когда другие протоколы используют Uniswap v3 для операций подкачки, разработчикам рекомендуется установить защиту от проскальзывания на основе бизнес-сценариев и позволить пользователям самостоятельно настраивать параметры для предотвращения сэндвич-атак. В этой функции свопа четвертый параметр sqrtPriceLimitX96 используется для указания минимальной или максимальной цены, по которой пользователь готов выполнить своп. Этот параметр может эффективно предотвращать резкие колебания цен во время процесса транзакции, тем самым уменьшая потери пользователей из-за чрезмерного проскальзывания.
4. Рекомендуется внедрить механизм белого списка пула ликвидности.
В Uniswap v3 одна и та же пара токенов ERC20 может существовать в нескольких пулах ликвидности (Пулах) одновременно на основе разных комиссий. Как правило, несколько пулов ликвидности содержат большую часть ликвидности, в то время как другие пулы могут иметь очень небольшой общий заблокированный объем (TVL) или даже еще не созданы. Эти пулы с более низким значением TVL с большей вероятностью станут объектами манипулирования ценами.
Поэтому, когда стороны проекта решают использовать данные пула ликвидности, им следует избегать простого использования LP в качестве источника данных. Для обеспечения достоверности данных рекомендуется ввести механизм «белых списков» для отсеивания пулов с достаточной ликвидностью и сложностью манипулирования. Этот механизм может значительно снизить риск, гарантируя безопасность и точность справочных данных о ценах, а также предотвращая потенциальные потери, вызванные манипулированием пулами со слишком низким TVL.
5. Проверьте, используется ли флажок в TickMath.sol, FullMath.sol и Position.sol.
Такие модули, как TickMath, FullMath и Position, используются в Uniswap v3 для выполнения сложных математических вычислений, которые основаны на механизме обработки переполнения в Solidity. В более ранних версиях Solidity (<0.8.0) поведение целочисленного переполнения и опустошения не вызывало исключений по умолчанию, поэтому код мог работать нормально на основе этого предположения. Однако, начиная с версии Solidity 0.8.0, переполнение и опустошение автоматически вызывают исключения, которые влияют на выполнение существующего кода. Чтобы гарантировать правильную работу этих модулей в Solidity 0.8.0 и выше, разработчикам необходимо вручную отключить проверку переполнения, используя непроверенные блоки кода в определенных функциях. Это восстанавливает поведение предыдущих версий и обеспечивает эффективное выполнение операций, чувствительных к переполнению.
Официальная поддержка и корректировки сделаны для Solidity 0.8.0 и выше. Подробности см. в этом обновлении (https://github.com/Uniswap/v3-core/commit/6562c52e8f75f0c10f9deaf44861847585fc8129). Это изменение гарантирует, что TickMath, FullMath и другие связанные модули будут продолжать корректно работать в новых версиях компилятора.
6. Проверьте, совпадают ли методы кодирования и декодирования пути.
В функциях точного ввода и точного вывода Uniswap v3 пользователям необходимо ввести параметр пути, который должен быть закодирован и декодирован в соответствии с фиксированным форматом, а именно tokenA-fee-tokenB, для пошаговых операций обмена токенов. Эта структура пути явно определяет два токена, участвующих в каждом переходе транзакции, и уровень комиссии между ними. Если внешний протокол выбирает другой метод декодирования пути при использовании функции обмена токенами Uniswap v3, это может привести к тому, что формат пути не будет соответствовать ожидаемому формату пути Uniswap. В этом случае протокол может оказаться не в состоянии правильно определить путь и, следовательно, не сможет успешно выполнить намеченную операцию обмена токенами.
Поэтому разработчикам рекомендуется обеспечить, чтобы внешние протоколы строго следовали правилам кодирования пути Uniswap при интеграции функции обмена токенами Uniswap v3. Чтобы предотвратить ошибки декодирования пути, внешние протоколы должны тщательно проверять формат параметра пути при вызове точного ввода и точного вывода, чтобы избежать сбоев транзакций или неожиданных результатов.
Поэтому разработчикам рекомендуется обеспечить, чтобы внешние протоколы строго следовали правилам кодирования пути Uniswap при интеграции функции обмена токенами Uniswap v3. Чтобы предотвратить ошибки декодирования пути, внешние протоколы должны тщательно проверять формат параметра пути при вызове точного ввода и точного вывода, чтобы избежать сбоев транзакций или неожиданных результатов.
7. Проверьте, влияет ли порядок токенов на логику проекта.
В Uniswap token0 является токеном низшего порядка и используется в качестве базового токена, а token1 — токеном более высокого порядка и используется в качестве токена котировки. Uniswap сортирует адреса двух токенов лексикографически, чтобы гарантировать, что порядок пар токенов всегда согласован в пуле.
Однако, поскольку адреса контрактов одного и того же токена в разных сетях блокчейнов могут различаться, особенно для контрактов, развернутых в разных цепочках, порядок сортировки токенов может измениться. Это изменение приведет к тому, что роли token0 и token1 поменяются местами, что повлияет на динамику цены. Например, в некоторых цепочках конкретный токен может быть token0, но в других цепочках он может быть упорядочен как token1, что приводит к разным отношениям между базовым токеном и котируемым токеном, что в конечном итоге влияет на отображаемую цену. Поэтому разработчикам рекомендуется проверить, повлияет ли порядок токенов на логику проекта. Особенно в среде с несколькими цепочками обязательно учитывайте проблемы с ценами, которые могут быть вызваны порядком токенов, чтобы избежать негативного влияния на производительность и эффективность цен. логика транзакции.
Подвести итог
Вышеуказанные основные элементы проверки основаны на текущей версии Uniswap v3 и используются аудиторами для проверки проектов, взаимодействующих с Uniswap v3. Реализация различных проектов имеет свои особенности, поэтому аудиторам необходимо глубоко понимать условия соглашения и проводить строгие проверки, исходя из реальной ситуации. Для проектов, находящихся в стадии разработки, команда безопасности SlowMist рекомендует разработчикам тщательно учитывать эти проверки в процессе разработки, чтобы обеспечить безопасность и надежность протокола.
Автор |
Редактор | Лиз
Все комментарии