Вводный курс DeFi для всех. Работа с dAPPs через смарт-контракты. Uniswap. Часть I
Итак, продолжаем наш бесплатный курс по DeFi:
В этом видео поговорим про протокол децентрализованной биржи Uniswap.
Uniswap - децентрализованный протокол обмена ассетами в EVM сетях. Он имеет несколько версий. Сейчас уже запущен протокол версии 4. Но мы в данном видео будем работать с протоколом версии 3, которые пользователи также используют, чтобы производить обмен активов или становиться провайдерами ликвидности.
Работать с протоколом будем также без его нативного веб интерфейса, используя только эксплорер контрактов. Опять же делая это на случай, если Uniswap по какой-то причине заблокирует адрес нашего кошелька или наш IP адрес на уровне интерфейсов.
Для демонстрации мы также будем использовать сеть арбитрум и arbiscan.io.
Первая операция, которую будем осуществлять - обмен ассетов.
Будем менять стейблкоины USDT на USDC. Для начала нам нужно понять, сколько можем получить токенов usdc за один usdt и можем ли мы их обменять в протоколе - есть ли такая торговая пара.
Находим в документации контракт UniswapV3Factory для сети Арбитрум. Выбираем метод чтения getPool.
Указываем ему адрес токена USDT, токена USDС. Указываем комиссии торговой пары. Она может быть разной - в Uniswap предусмотрены несколько уровней комиссии: 0,01%, 0.05%, 0.30%, 1%.
Такое многообразие позволяет создавать пулы с разной комиссией для одних и тех же пар токенов.
Методу getPool передаётся значение комиссии не 0,01, например, а 100. В документации есть описание значений комиссии и чему оно соответствует. Поэтому 100 всё равно что 0,01. Такое большое значение деноминатора используется для повышения точности вычислений. Итак, проверим, есть ли пул для нашей пары с комиссией 0,01%.
Теперь проверим для уровня комиссии 0,05%. Есть пул. И для комиссии 0,3%, и для 1% есть пулы. Сами разработчики в документации отмечают, что чем более рискованные активы обмениваются, тем выше % комиссии могут устанавливать провайдеры ликвидностей для пулов торговых пар.
Итого: мы поняли, что для нашей торговой пары есть пул ликвидности с минимальной комиссией за обмен 0,01%.
Понять, сколько мы получим токена Б при обмене токена А через эксплорер не удастся.
В протоколе есть контракт Quoter с его методом quoteExactInputSingle, который можно вызвать и он вернёт рассчитанное значение токена Б.
Но эксплорер не умеет в транзакции (quoteExactInputSingle - метод записи) показать значение, которое возвращает метод. Можно писать скрипты используя различные фреймворки, например, Foundry, Brownie и в них делать вызов этого метода. Но это требует квалификации программирования. Поэтому мы будем сразу производить обмен.
Для обмена нам будет необходимо выдать разрешение контракту SwapRouter02 протокола Uniswap использовать в нужном количестве наши USDt
Находим в эксплорере по адресу контракт USDT. В методах записи находим метод approve.
Указываем адрес распорядителя - адрес контакта SwapRouter02 протокола, который также можно найти для нашей сети в документации Uniswap.
Указываем сумму - 1 USDt - 1 000 000 с учетом количества знаков после запятой (значение в публичной переменной decimals у контракта USDT).
Далее на контракте SwapRouter02 находим метод exactInputSingle.
Указываем значения параметров:
- payableAmount - количество передаваемого Эфира в транзакции 0 - мы не будем менять Эфир на то-то сейчас.
- tokenIn - адрес токена USDT - мы его будем менять на USDC.
- tokenOut - адрес токена USDC - то, что хотим получить.
- fee - указываем 10000 - мы хотим обменять на пуле именно с такой комиссией - 0,01%.
- recipient - получатель usdc - копируем адрес, которым будем подписывать транзакцию. Но можно указать и другой адрес
- deadline - до какого момента транзакцию можно будет выполнить - бывает, что транзакция не сразу подтверждается, подвисает и мы должны указать, до какого времени она еще актуальна для нас. Время указывается в формате unixtime, мы здесь укажем сколько угодно большое число.
- amountIn - указываем количество ассета, который меняем - меняем 1 usdt - 1000000 с учетом дробной части после запятой.
- amountOutMinimum - минимальное количество токенов usdc, которое мы хотим получить. Поставим значение 10 - с учётом количества знаков после запятой.
- sqrtPriceLimitX96 - лимит цены (обычно 0, если мы не хотим ограничивать цену).
Подписываем транзакцию. Проверяем транзакцию. Видим, что протокол забрал 1 USDT и зачислил нам некоторое количество токенов USDC - чуть меньше 1 доллара.