Обмен контрактами: изучение исходного кода Uniswap
Недавно, когда я писал руководство по разработке децентрализованной биржи, я参考ировал реализацию кода Uniswap V3 и узнал много ценных знаний. Для разработчика, который впервые пытается создать Defi контракт, эти советы будут очень полезны для новичков, желающих изучить разработку контрактов.
Ниже я поделюсь некоторыми маленькими хитростями, некоторые из которых можно назвать настоящими искусными трюками.
Предсказуемый адрес развертывания контракта
Обычно адрес, получаемый при развертывании контракта, кажется случайным, поскольку он связан с nonce, поэтому предсказать адрес контракта сложно. Но в некоторых случаях нам необходимо вывести адрес контракта через пару сделок и связанную информацию. Это полезно в таких случаях, как определение прав на транзакции или получение адреса пула.
Uniswap создает контракты, добавляя параметр salt и используя CREATE2, что позволяет предсказать адрес созданного контракта. Логика генерации адреса: новый адрес = hash("0xFF", адрес создателя, salt, initcode).
Умелое использование функций обратного вызова
В некоторых сценариях контракт A вызывает метод контракта B, а B в вызываемом методе вызывает A, такой подход очень практичен.
Например, в Uniswap, при вызове метода swap контракта UniswapV3Pool для совершения сделки, он вызовет swapCallback, передавая рассчитанные токены, необходимые для этой сделки. Вызывающая сторона должна в колбэке перевести необходимые токены в UniswapV3Pool, а не разбивать метод swap на две части для вызова вызывающей стороной. Это обеспечивает безопасность метода swap, гарантируя, что вся логика будет выполнена полностью, без необходимости в сложной записи переменных для обеспечения безопасности.
Использование исключений для передачи информации, реализация оценки транзакций с помощью try catch
В контракте Quoter Uniswap метод swap UniswapV3Pool обернут в блок try catch для выполнения. Это сделано для имитации метода swap, чтобы оценить необходимые токены для сделки. Поскольку при оценке фактический обмен токенов не происходит, возникает ошибка. Uniswap генерирует специальную ошибку в функции обратного вызова транзакции, а затем ловит эту ошибку, извлекая необходимую информацию из сообщения об ошибке.
Этот метод кажется хитрым, но он очень практичен. Не нужно модифицировать метод свопа для оценки торговых потребностей, логика проще.
Использование больших чисел для решения проблемы точности
В коде Uniswap содержится множество вычислительной логики, например, расчёт токенов для обмена на основе текущей цены и ликвидности. Чтобы избежать потери точности при операциях деления, в процессе вычислений часто используется операция "<< FixedPoint96.RESOLUTION", то есть сдвиг влево на 96 бит, что эквивалентно умножению на 2^96. После сдвига выполняется операция деления, что гарантирует точность при нормальных сделках, не приводящих к переполнению.
Расчет дохода с помощью Share
На Uniswap необходимо учитывать комиссионные доходы провайдера ликвидности LP(. Очевидно, что невозможно записывать комиссионные для каждого LP при каждой сделке, это потребует большого количества газа.
Решение Uniswap заключается в том, чтобы записывать feeGrowthInside0LastX128 и feeGrowthInside1LastX128 в структуре Position, что указывает на сумму комиссии, которую каждый ликвидный актив должен получить в момент последнего извлечения комиссии. Нужно просто записать общую сумму комиссии и сумму комиссии, которая должна быть распределена между каждым ликвидным активом; при извлечении LP можно рассчитывать на извлекаемую сумму комиссии на основе удерживаемого ликвидного актива. Это похоже на владение акциями компании, где для извлечения дохода нужно знать историческую прибыль на акцию компании и прибыль на момент последнего извлечения.
![Web3 новичок серия: маленькие советы по разработке контрактов, которые я узнал из кода Uniswap])https://img-cdn.gateio.im/webp-social/moments-45e66af69435e6d4412ae506e77ab893.webp(
Необязательную информацию не нужно получать из цепочки
Онлайн-хранение относительно дорого, и не вся информация должна быть на блокчейне или получена с блокчейна. Например, многие интерфейсы, используемые фронтенд-сайтом Uniswap, являются традиционными интерфейсами Web2.
Список торговых пулов, информация о торговых пулах и т. д. могут храниться в обычной базе данных, часть из них может потребовать периодической синхронизации с блокчейном, но нет необходимости в реальном времени вызывать 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 или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
9 Лайков
Награда
9
8
Поделиться
комментарий
0/400
SchrodingerWallet
· 07-09 09:07
Слишком просто, я ускользнул~
Посмотреть ОригиналОтветить0
LiquidityWizard
· 07-08 13:06
Просто скопируй и все.
Посмотреть ОригиналОтветить0
PoolJumper
· 07-07 22:21
合约про救命鸭
Посмотреть ОригиналОтветить0
IntrovertMetaverse
· 07-06 09:37
Снова пришло время для торговли контрактами.
Посмотреть ОригиналОтветить0
SerumSurfer
· 07-06 09:37
Этот исходный код v3 довольно хорош.
Посмотреть ОригиналОтветить0
FlyingLeek
· 07-06 09:36
Смотрится неплохо, жду, когда разыграют людей как лохов
Разработка исходного кода Uniswap: 7 основных советов по разработке контрактов, которые помогут новичкам На луну в DeFi.
Обмен контрактами: изучение исходного кода Uniswap
Недавно, когда я писал руководство по разработке децентрализованной биржи, я参考ировал реализацию кода Uniswap V3 и узнал много ценных знаний. Для разработчика, который впервые пытается создать Defi контракт, эти советы будут очень полезны для новичков, желающих изучить разработку контрактов.
Ниже я поделюсь некоторыми маленькими хитростями, некоторые из которых можно назвать настоящими искусными трюками.
Предсказуемый адрес развертывания контракта
Обычно адрес, получаемый при развертывании контракта, кажется случайным, поскольку он связан с nonce, поэтому предсказать адрес контракта сложно. Но в некоторых случаях нам необходимо вывести адрес контракта через пару сделок и связанную информацию. Это полезно в таких случаях, как определение прав на транзакции или получение адреса пула.
Uniswap создает контракты, добавляя параметр salt и используя CREATE2, что позволяет предсказать адрес созданного контракта. Логика генерации адреса: новый адрес = hash("0xFF", адрес создателя, salt, initcode).
Умелое использование функций обратного вызова
В некоторых сценариях контракт A вызывает метод контракта B, а B в вызываемом методе вызывает A, такой подход очень практичен.
Например, в Uniswap, при вызове метода swap контракта UniswapV3Pool для совершения сделки, он вызовет swapCallback, передавая рассчитанные токены, необходимые для этой сделки. Вызывающая сторона должна в колбэке перевести необходимые токены в UniswapV3Pool, а не разбивать метод swap на две части для вызова вызывающей стороной. Это обеспечивает безопасность метода swap, гарантируя, что вся логика будет выполнена полностью, без необходимости в сложной записи переменных для обеспечения безопасности.
Использование исключений для передачи информации, реализация оценки транзакций с помощью try catch
В контракте Quoter Uniswap метод swap UniswapV3Pool обернут в блок try catch для выполнения. Это сделано для имитации метода swap, чтобы оценить необходимые токены для сделки. Поскольку при оценке фактический обмен токенов не происходит, возникает ошибка. Uniswap генерирует специальную ошибку в функции обратного вызова транзакции, а затем ловит эту ошибку, извлекая необходимую информацию из сообщения об ошибке.
Этот метод кажется хитрым, но он очень практичен. Не нужно модифицировать метод свопа для оценки торговых потребностей, логика проще.
Использование больших чисел для решения проблемы точности
В коде Uniswap содержится множество вычислительной логики, например, расчёт токенов для обмена на основе текущей цены и ликвидности. Чтобы избежать потери точности при операциях деления, в процессе вычислений часто используется операция "<< FixedPoint96.RESOLUTION", то есть сдвиг влево на 96 бит, что эквивалентно умножению на 2^96. После сдвига выполняется операция деления, что гарантирует точность при нормальных сделках, не приводящих к переполнению.
Расчет дохода с помощью Share
На Uniswap необходимо учитывать комиссионные доходы провайдера ликвидности LP(. Очевидно, что невозможно записывать комиссионные для каждого LP при каждой сделке, это потребует большого количества газа.
Решение Uniswap заключается в том, чтобы записывать feeGrowthInside0LastX128 и feeGrowthInside1LastX128 в структуре Position, что указывает на сумму комиссии, которую каждый ликвидный актив должен получить в момент последнего извлечения комиссии. Нужно просто записать общую сумму комиссии и сумму комиссии, которая должна быть распределена между каждым ликвидным активом; при извлечении LP можно рассчитывать на извлекаемую сумму комиссии на основе удерживаемого ликвидного актива. Это похоже на владение акциями компании, где для извлечения дохода нужно знать историческую прибыль на акцию компании и прибыль на момент последнего извлечения.
![Web3 новичок серия: маленькие советы по разработке контрактов, которые я узнал из кода Uniswap])https://img-cdn.gateio.im/webp-social/moments-45e66af69435e6d4412ae506e77ab893.webp(
Необязательную информацию не нужно получать из цепочки
Онлайн-хранение относительно дорого, и не вся информация должна быть на блокчейне или получена с блокчейна. Например, многие интерфейсы, используемые фронтенд-сайтом Uniswap, являются традиционными интерфейсами Web2.
Список торговых пулов, информация о торговых пулах и т. д. могут храниться в обычной базе данных, часть из них может потребовать периодической синхронизации с блокчейном, но нет необходимости в реальном времени вызывать RPC-интерфейсы цепочки или узлов для получения соответствующих данных.
Конечно, ключевые сделки должны проводиться в цепочке.
Разумное разделение контракта, использование существующих стандартных контрактов
Проект может содержать несколько фактически развернутых контрактов. Даже если фактически развернут только один контракт, код также может быть разделен на несколько контрактов для поддержки с помощью наследования.
Например, контракт NonfungiblePositionManager Uniswap наследует несколько контрактов. При просмотре реализации контракта ERC721Permit обнаруживается, что он напрямую использует контракт @openzeppelin/contracts/token/ERC721/ERC721.sol. Это удобно как для управления позициями с помощью NFT, так и для повышения эффективности разработки с использованием существующих стандартных контрактов.
Итог
Практика — лучший способ обучения. Попробуйте самостоятельно реализовать простую версию децентрализованной биржи, чтобы глубже понять код Uniswap и узнать больше о знаниях, применяемых в реальных проектах.
![Web3 Новичок Серия: Маленькие советы по разработке контрактов, которые я узнал из кода Uniswap])https://img-cdn.gateio.im/webp-social/moments-f95ddc9d89809cf11dbe65b9bafda157.webp(