Советы по разработке контрактов: опыт, полученный из кода Uniswap
Недавно, когда я писал руководство по разработке децентрализованных бирж, я ориентировался на реализацию Uniswap V3 и узнал много интересных моментов. Как новичок, впервые пробующий разработку Defi контрактов, эти приемы могут быть очень полезны для других начинающих, желающих изучить разработку контрактов.
Предсказуемый адрес развертывания контракта
Обычно адреса, полученные при развертывании контрактов, кажутся случайными и труднопредсказуемыми. Однако в некоторых случаях нам необходимо вывести адрес контракта на основе информации о сделках, например, для определения прав на сделку или получения адреса пула.
Uniswap использует метод CREATE2 для создания контрактов, добавляя параметр salt, чтобы сделать адрес предсказуемым. Логика генерации нового адреса: hash("0xFF", адрес создателя, salt, initcode). Этот метод делает адрес контракта предсказуемым, что очень удобно.
Умелое использование функций обратного вызова
Контракты в Solidity могут вызывать друг друга. В некоторых сценариях A вызывает метод B, и B вызывает A в своем вызываемом методе, эта модель очень полезна.
В своп-транзакциях Uniswap используется механизм обратного вызова. Метод swap UniswapV3Pool вызывает swapCallback, передавая фактическое количество необходимых токенов. Вызывающая сторона должна передать токены в обратном вызове, что обеспечивает полное выполнение и безопасность метода swap, без необходимости в сложной записи переменных.
Используйте исключения для передачи информации, реализуйте оценку транзакций с помощью try catch
В контракте Quoter Uniswap метод swap UniswapV3Pool обернут в блок try catch. Это сделано для того, чтобы смоделировать swap для оценки необходимых токенов для сделки, но при оценке токены фактически не обмениваются, поэтому возникает ошибка.
Uniswap выбрасывает специальные ошибки в функции обратного вызова, а затем перехватывает эти ошибки и извлекает необходимую информацию. Этот подход кажется хитрым, но очень практичен, так как не требует специальной переработки метода swap для оценки потребностей, а логика остается более лаконичной.
Использование больших чисел для решения проблем с точностью
В коде Uniswap задействовано множество вычислений, таких как расчет количества токенов для обмена на основе текущей цены и ликвидности. Чтобы избежать потерь точности при делении, в процессе вычислений часто используется операция "<< FixedPoint96.RESOLUTION", то есть сдвиг влево на 96 бит, что эквивалентно умножению на 2^96.
Сначала сдвиньте влево, а затем выполните деление, чтобы гарантировать точность при нормальных сделках без переполнения. Хотя теоретически все равно будет небольшая потеря точности, она уже приемлема.
Расчет дохода с помощью Share
Uniswap должен записывать доходы от комиссии для поставщика ликвидности LP(, а также для ). Очевидно, что нельзя записывать комиссии для каждого LP при каждой сделке, так как это потребует большого количества газа.
Решение заключается в записи feeGrowthInside0LastX128 и feeGrowthInside1LastX128 в структуре Position, которые представляют собой комиссионные сборы, причитающиеся за каждую единицу ликвидности при последнем извлечении комиссии для каждого положения.
Необходимо лишь записывать общую комиссию и комиссию, распределяемую на каждую единицу ликвидности. При выводе LP можно рассчитать доступную для вывода комиссию на основе удерживаемой ликвидности. Это похоже на удержание акций: для вывода дохода нужно знать историческую прибыль на акцию и доход, полученный при последнем выводе.
Не вся информация должна быть получена из цепочки
Хранение на блокчейне относительно дорого, не вся информация должна быть записана в цепочку или извлекаться из нее. Многие интерфейсы, используемые фронтендом Uniswap, являются традиционными Web2 интерфейсами.
Список торговых пулов, информация и т.д. могут храниться в обычной базе данных, часть из них необходимо периодически синхронизировать с блокчейном, но нет необходимости в реальном времени вызывать данные из цепи или интерфейса RPC узла.
Многие поставщики RPC для блокчейна также предлагают продвинутые интерфейсы, которые позволяют быстрее и дешевле получать определенные данные. Эти интерфейсы обычно используют кэширование для повышения производительности и эффективности.
Конечно, ключевые сделки все еще проводятся в цепочке.
Научитесь разделять контракты и использовать существующие стандартные контракты
Проект может содержать несколько фактически развернутых контрактов. Даже если развернут только один контракт, код может быть разделен на несколько контрактов для поддержки через наследование.
Как и контракт NonfungiblePositionManager Uniswap, он наследует несколько контрактов. Контракт ERC721Permit напрямую использует реализацию ERC721 от OpenZeppelin, что удобно для управления позициями с помощью NFT и повышает эффективность разработки.
Резюме
Разработайте простую версию децентрализованной биржи, чтобы глубже понять реализацию Uniswap и изучить больше практических знаний из реальных проектов. Теоретическое обучение, безусловно, важно, но практический опыт еще более ценен. Надеюсь, что эти небольшие советы помогут вам в разработке ваших контрактов.
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
19 Лайков
Награда
19
7
Поделиться
комментарий
0/400
GasWaster
· 07-16 11:49
Все, кто изучает контракты, должны посмотреть
Посмотреть ОригиналОтветить0
MissedAirdropAgain
· 07-16 07:39
Учиться контрактам не успели...
Посмотреть ОригиналОтветить0
YieldWhisperer
· 07-14 20:20
видел этот точный паттерн на dyydx в 2020 году... по правде говоря, ничего нового
Разбор кода Uniswap: 7 советов по разработке смарт-контрактов
Советы по разработке контрактов: опыт, полученный из кода Uniswap
Недавно, когда я писал руководство по разработке децентрализованных бирж, я ориентировался на реализацию Uniswap V3 и узнал много интересных моментов. Как новичок, впервые пробующий разработку Defi контрактов, эти приемы могут быть очень полезны для других начинающих, желающих изучить разработку контрактов.
Предсказуемый адрес развертывания контракта
Обычно адреса, полученные при развертывании контрактов, кажутся случайными и труднопредсказуемыми. Однако в некоторых случаях нам необходимо вывести адрес контракта на основе информации о сделках, например, для определения прав на сделку или получения адреса пула.
Uniswap использует метод CREATE2 для создания контрактов, добавляя параметр salt, чтобы сделать адрес предсказуемым. Логика генерации нового адреса: hash("0xFF", адрес создателя, salt, initcode). Этот метод делает адрес контракта предсказуемым, что очень удобно.
Умелое использование функций обратного вызова
Контракты в Solidity могут вызывать друг друга. В некоторых сценариях A вызывает метод B, и B вызывает A в своем вызываемом методе, эта модель очень полезна.
В своп-транзакциях Uniswap используется механизм обратного вызова. Метод swap UniswapV3Pool вызывает swapCallback, передавая фактическое количество необходимых токенов. Вызывающая сторона должна передать токены в обратном вызове, что обеспечивает полное выполнение и безопасность метода swap, без необходимости в сложной записи переменных.
Используйте исключения для передачи информации, реализуйте оценку транзакций с помощью try catch
В контракте Quoter Uniswap метод swap UniswapV3Pool обернут в блок try catch. Это сделано для того, чтобы смоделировать swap для оценки необходимых токенов для сделки, но при оценке токены фактически не обмениваются, поэтому возникает ошибка.
Uniswap выбрасывает специальные ошибки в функции обратного вызова, а затем перехватывает эти ошибки и извлекает необходимую информацию. Этот подход кажется хитрым, но очень практичен, так как не требует специальной переработки метода swap для оценки потребностей, а логика остается более лаконичной.
Использование больших чисел для решения проблем с точностью
В коде Uniswap задействовано множество вычислений, таких как расчет количества токенов для обмена на основе текущей цены и ликвидности. Чтобы избежать потерь точности при делении, в процессе вычислений часто используется операция "<< FixedPoint96.RESOLUTION", то есть сдвиг влево на 96 бит, что эквивалентно умножению на 2^96.
Сначала сдвиньте влево, а затем выполните деление, чтобы гарантировать точность при нормальных сделках без переполнения. Хотя теоретически все равно будет небольшая потеря точности, она уже приемлема.
Расчет дохода с помощью Share
Uniswap должен записывать доходы от комиссии для поставщика ликвидности LP(, а также для ). Очевидно, что нельзя записывать комиссии для каждого LP при каждой сделке, так как это потребует большого количества газа.
Решение заключается в записи feeGrowthInside0LastX128 и feeGrowthInside1LastX128 в структуре Position, которые представляют собой комиссионные сборы, причитающиеся за каждую единицу ликвидности при последнем извлечении комиссии для каждого положения.
Необходимо лишь записывать общую комиссию и комиссию, распределяемую на каждую единицу ликвидности. При выводе LP можно рассчитать доступную для вывода комиссию на основе удерживаемой ликвидности. Это похоже на удержание акций: для вывода дохода нужно знать историческую прибыль на акцию и доход, полученный при последнем выводе.
Не вся информация должна быть получена из цепочки
Хранение на блокчейне относительно дорого, не вся информация должна быть записана в цепочку или извлекаться из нее. Многие интерфейсы, используемые фронтендом Uniswap, являются традиционными Web2 интерфейсами.
Список торговых пулов, информация и т.д. могут храниться в обычной базе данных, часть из них необходимо периодически синхронизировать с блокчейном, но нет необходимости в реальном времени вызывать данные из цепи или интерфейса RPC узла.
Многие поставщики RPC для блокчейна также предлагают продвинутые интерфейсы, которые позволяют быстрее и дешевле получать определенные данные. Эти интерфейсы обычно используют кэширование для повышения производительности и эффективности.
Конечно, ключевые сделки все еще проводятся в цепочке.
Научитесь разделять контракты и использовать существующие стандартные контракты
Проект может содержать несколько фактически развернутых контрактов. Даже если развернут только один контракт, код может быть разделен на несколько контрактов для поддержки через наследование.
Как и контракт NonfungiblePositionManager Uniswap, он наследует несколько контрактов. Контракт ERC721Permit напрямую использует реализацию ERC721 от OpenZeppelin, что удобно для управления позициями с помощью NFT и повышает эффективность разработки.
Резюме
Разработайте простую версию децентрализованной биржи, чтобы глубже понять реализацию Uniswap и изучить больше практических знаний из реальных проектов. Теоретическое обучение, безусловно, важно, но практический опыт еще более ценен. Надеюсь, что эти небольшие советы помогут вам в разработке ваших контрактов.