Практические советы по разработке контрактов: опыт, полученный из кода Uniswap
Недавно, разрабатывая учебник по децентрализованным биржам, я обратился к коду реализации Uniswap V3 и узнал много интересных моментов. Для разработчика, который впервые пытается создать DeFi-контракты, эти советы будут очень полезны для новичков, желающих изучить разработку контрактов.
Давайте теперь посмотрим на эти полезные советы, некоторые из которых можно назвать настоящими хитростями.
Адрес развертывания предсказательных контрактов
Обычно адреса, получаемые при развертывании контрактов, выглядят случайными, потому что они связаны с nonce и трудно предсказуемы. Однако в некоторых сценариях нам необходимо вывести адрес контракта, основываясь на торговых парах и соответствующей информации. Это полезно для определения прав на сделки или получения адреса пула.
Uniswap использует метод CREATE2 для создания контрактов, добавляя параметр salt, чтобы адреса созданных контрактов были предсказуемыми. Логика генерации нового адреса такова: hash("0xFF", адрес создателя, salt, initcode). Этот метод делает адреса контрактов предсказуемыми, что упрощает последующие операции.
Умелое использование функций обратного вызова
В Solidity контракты могут вызывать друг друга. Обычный сценарий - это когда метод A вызывает метод B, а B в вызываемом методе вызывает обратно A. Это очень полезно в некоторых случаях.
Например, при вызове метода swap контракта UniswapV3Pool для проведения сделки он вызовет swapCallback, передавая рассчитанный токен, необходимый для этой сделки. Вызывающая сторона должна в обратном вызове перевести необходимый токен в UniswapV3Pool. Эта конструкция гарантирует полное выполнение и безопасность метода swap, исключая необходимость в сложной записи переменных.
Использование исключений для передачи информации, реализация оценки сделки с помощью try catch
В контракте Quoter Uniswap используется конструкция try catch для выполнения метода swap UniswapV3Pool. Это делается для симуляции метода swap с целью оценки необходимых токенов для сделки. Так как во время оценки фактическая замена токенов не происходит, возникает ошибка. Uniswap выбрасывает специальную ошибку в функции обратного вызова сделки, а затем захватывает эту ошибку и извлекает необходимую информацию.
Этот метод кажется хитрым, но очень практичен. Он позволяет избежать изменения метода свопа для оценки торговых потребностей, что делает логику более простой.
Решение проблемы точности с помощью больших чисел
В коде Uniswap задействовано множество вычислительной логики, такой как расчет токенов для обмена на основе текущей цены и ликвидности. Чтобы избежать потерь точности, вызванных операцией деления, Uniswap часто использует операцию "<< FixedPoint96.RESOLUTION", то есть сдвиг влево на 96 бит, что эквивалентно умножению на 2^96. Сначала происходит сдвиг влево, а затем выполняется операция деления, что позволяет в обычных условиях торговли без переполнения ( обычно использовать uint256 для вычислений ) с гарантией точности.
Хотя теоретически все еще может быть небольшая потеря точности, но такая степень погрешности обычно приемлема.
Рассчет дохода с использованием метода Share
Uniswap должен записывать доходы от комиссий ликвидности для поставщиков ликвидности LP(. Чтобы избежать больших затрат газа на запись комиссий для каждого LP при каждой сделке, Uniswap использует хитрый метод.
В структуре Position определены feeGrowthInside0LastX128 и feeGrowthInside1LastX128, которые фиксируют комиссионные сборы, причитающиеся каждому поставщику ликвидности, при последнем извлечении комиссий для каждой позиции. Таким образом, необходимо записывать только общие комиссионные сборы и комиссионные, которые должны быть распределены между каждым поставщиком ликвидности. При извлечении LP можно вычислить сумму извлекаемых комиссий на основании удерживаемой ликвидности. Это похоже на механизм дивидендов акций: при извлечении достаточно знать историческую прибыль на акцию компании и прибыль на момент последнего извлечения.
![Серия для новичков в Web3: маленькие советы по разработке контрактов, которые я узнал из кода Uniswap])https://img-cdn.gateio.im/webp-social/moments-45e66af69435e6d4412ae506e77ab893.webp(
Разумный выбор способов получения информации
Хранение на блокчейне относительно дорого, поэтому не вся информация должна быть записана в блокчейн или извлекаться из него. Например, многие интерфейсы, используемые фронтенд-сайтом Uniswap, являются традиционными интерфейсами Web2.
Списки торговых пулов, информация о торговых пулах и т. д. могут храниться в обычной базе данных, некоторые данные могут потребовать периодической синхронизации с блокчейном, но нет необходимости в реальном времени вызывать RPC-интерфейсы цепи или узла для получения соответствующих данных.
Некоторые поставщики RPC для блокчейна предлагают продвинутые интерфейсы, которые позволяют быстрее и экономичнее получать определенные данные. Эти интерфейсы обычно используют кэширование для повышения производительности и эффективности.
Конечно, ключевые сделки все еще должны проводиться в цепочке.
Изучение разделения контрактов и использования существующих стандартных контрактов
Проект может содержать несколько фактически развернутых контрактов. Даже если фактически развернут только один контракт, мы можем разделить контракт на несколько частей с помощью наследования для поддержания.
Например, контракт NonfungiblePositionManager Uniswap наследует несколько контрактов. При реализации контракта ERC721Permit непосредственно использовался контракт @openzeppelin/contracts/token/ERC721/ERC721.sol. Это не только упрощает управление позициями через NFT, но и позволяет повысить эффективность разработки, используя существующие стандартные контракты.
Итоги
Личный опыт разработки упрощенной версии децентрализованной биржи позволит вам глубже понять реализацию кода Uniswap, а также узнать больше практических аспектов из реальных проектов. Уверен, что эти навыки будут очень полезны новичкам, желающим изучить разработку контрактов.
![Web3 Новичок Серия: маленькие советы по разработке контрактов, которые я узнал из кода Uniswap])https://img-cdn.gateio.im/webp-social/moments-f95ddc9d89809cf11dbe65b9bafda157.webp(
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
10 Лайков
Награда
10
7
Поделиться
комментарий
0/400
DataPickledFish
· 20ч назад
Снова изучаю код, голова болит!
Посмотреть ОригиналОтветить0
PermabullPete
· 20ч назад
Началась ерунда, не понимаю этого. Я только теряю деньги.
Посмотреть ОригиналОтветить0
MEVSandwichVictim
· 20ч назад
Этот CREATE2 действительно довольно продвинутый, не зря это uni.
Посмотреть ОригиналОтветить0
MrRightClick
· 20ч назад
Эй, create2 это действительно круто!
Посмотреть ОригиналОтветить0
PanicSeller69
· 20ч назад
Кодеры тоже плачут.
Посмотреть ОригиналОтветить0
BearMarketBard
· 20ч назад
Старый крестный – настоящая корова
Посмотреть ОригиналОтветить0
Deconstructionist
· 20ч назад
Снова изучаю производственный код, не могу учиться дальше.
Анализ кода Uniswap: 7 полезных советов по разработке контрактов
Практические советы по разработке контрактов: опыт, полученный из кода Uniswap
Недавно, разрабатывая учебник по децентрализованным биржам, я обратился к коду реализации Uniswap V3 и узнал много интересных моментов. Для разработчика, который впервые пытается создать DeFi-контракты, эти советы будут очень полезны для новичков, желающих изучить разработку контрактов.
Давайте теперь посмотрим на эти полезные советы, некоторые из которых можно назвать настоящими хитростями.
Адрес развертывания предсказательных контрактов
Обычно адреса, получаемые при развертывании контрактов, выглядят случайными, потому что они связаны с nonce и трудно предсказуемы. Однако в некоторых сценариях нам необходимо вывести адрес контракта, основываясь на торговых парах и соответствующей информации. Это полезно для определения прав на сделки или получения адреса пула.
Uniswap использует метод CREATE2 для создания контрактов, добавляя параметр salt, чтобы адреса созданных контрактов были предсказуемыми. Логика генерации нового адреса такова: hash("0xFF", адрес создателя, salt, initcode). Этот метод делает адреса контрактов предсказуемыми, что упрощает последующие операции.
Умелое использование функций обратного вызова
В Solidity контракты могут вызывать друг друга. Обычный сценарий - это когда метод A вызывает метод B, а B в вызываемом методе вызывает обратно A. Это очень полезно в некоторых случаях.
Например, при вызове метода swap контракта UniswapV3Pool для проведения сделки он вызовет swapCallback, передавая рассчитанный токен, необходимый для этой сделки. Вызывающая сторона должна в обратном вызове перевести необходимый токен в UniswapV3Pool. Эта конструкция гарантирует полное выполнение и безопасность метода swap, исключая необходимость в сложной записи переменных.
Использование исключений для передачи информации, реализация оценки сделки с помощью try catch
В контракте Quoter Uniswap используется конструкция try catch для выполнения метода swap UniswapV3Pool. Это делается для симуляции метода swap с целью оценки необходимых токенов для сделки. Так как во время оценки фактическая замена токенов не происходит, возникает ошибка. Uniswap выбрасывает специальную ошибку в функции обратного вызова сделки, а затем захватывает эту ошибку и извлекает необходимую информацию.
Этот метод кажется хитрым, но очень практичен. Он позволяет избежать изменения метода свопа для оценки торговых потребностей, что делает логику более простой.
Решение проблемы точности с помощью больших чисел
В коде Uniswap задействовано множество вычислительной логики, такой как расчет токенов для обмена на основе текущей цены и ликвидности. Чтобы избежать потерь точности, вызванных операцией деления, Uniswap часто использует операцию "<< FixedPoint96.RESOLUTION", то есть сдвиг влево на 96 бит, что эквивалентно умножению на 2^96. Сначала происходит сдвиг влево, а затем выполняется операция деления, что позволяет в обычных условиях торговли без переполнения ( обычно использовать uint256 для вычислений ) с гарантией точности.
Хотя теоретически все еще может быть небольшая потеря точности, но такая степень погрешности обычно приемлема.
Рассчет дохода с использованием метода Share
Uniswap должен записывать доходы от комиссий ликвидности для поставщиков ликвидности LP(. Чтобы избежать больших затрат газа на запись комиссий для каждого LP при каждой сделке, Uniswap использует хитрый метод.
В структуре Position определены feeGrowthInside0LastX128 и feeGrowthInside1LastX128, которые фиксируют комиссионные сборы, причитающиеся каждому поставщику ликвидности, при последнем извлечении комиссий для каждой позиции. Таким образом, необходимо записывать только общие комиссионные сборы и комиссионные, которые должны быть распределены между каждым поставщиком ликвидности. При извлечении LP можно вычислить сумму извлекаемых комиссий на основании удерживаемой ликвидности. Это похоже на механизм дивидендов акций: при извлечении достаточно знать историческую прибыль на акцию компании и прибыль на момент последнего извлечения.
![Серия для новичков в Web3: маленькие советы по разработке контрактов, которые я узнал из кода Uniswap])https://img-cdn.gateio.im/webp-social/moments-45e66af69435e6d4412ae506e77ab893.webp(
Разумный выбор способов получения информации
Хранение на блокчейне относительно дорого, поэтому не вся информация должна быть записана в блокчейн или извлекаться из него. Например, многие интерфейсы, используемые фронтенд-сайтом Uniswap, являются традиционными интерфейсами Web2.
Списки торговых пулов, информация о торговых пулах и т. д. могут храниться в обычной базе данных, некоторые данные могут потребовать периодической синхронизации с блокчейном, но нет необходимости в реальном времени вызывать RPC-интерфейсы цепи или узла для получения соответствующих данных.
Некоторые поставщики RPC для блокчейна предлагают продвинутые интерфейсы, которые позволяют быстрее и экономичнее получать определенные данные. Эти интерфейсы обычно используют кэширование для повышения производительности и эффективности.
Конечно, ключевые сделки все еще должны проводиться в цепочке.
Изучение разделения контрактов и использования существующих стандартных контрактов
Проект может содержать несколько фактически развернутых контрактов. Даже если фактически развернут только один контракт, мы можем разделить контракт на несколько частей с помощью наследования для поддержания.
Например, контракт NonfungiblePositionManager Uniswap наследует несколько контрактов. При реализации контракта ERC721Permit непосредственно использовался контракт @openzeppelin/contracts/token/ERC721/ERC721.sol. Это не только упрощает управление позициями через NFT, но и позволяет повысить эффективность разработки, используя существующие стандартные контракты.
Итоги
Личный опыт разработки упрощенной версии децентрализованной биржи позволит вам глубже понять реализацию кода Uniswap, а также узнать больше практических аспектов из реальных проектов. Уверен, что эти навыки будут очень полезны новичкам, желающим изучить разработку контрактов.
![Web3 Новичок Серия: маленькие советы по разработке контрактов, которые я узнал из кода Uniswap])https://img-cdn.gateio.im/webp-social/moments-f95ddc9d89809cf11dbe65b9bafda157.webp(