Привет, Хабр! Что если мы скажем, что сделать форк смарт-контрактов известного протокола не такая сложная задача, как может показаться? В этой статье я расскажу, как мы форкнули смарт-контракты Uniswap v2 и задеплоили их в Polygon zkEVM.
Базовые знания
Есть два основных репозитория:
uniswap-v2-core
Репозиторий uniswap-v2-core содержит ключевые смарт-контракты: UniswapV2ERC20.sol
, UniswapV2Factory.sol
, UniswapV2Pair.sol
, которые реализуют основной функционал протокола Uniswap V2. Эти смарт-контракты обеспечивают децентрализованный обмен токенами.
Необходимо задеплоить:
UniswapV2Factory.sol
UniswapV2Pair.sol
-
UniswapV2ERC20.sol
Первый контракт отвечает за создание и управление парами обмена (пулов ликвидности). Смарт-контракт фабрики также отслеживает все существующие пары и их адреса. Когда создается новая пара токенов, фабрика разворачивает новый смарт-контракт
UniswapV2Pair.sol
, который представляет собой пул ликвидности для этой пары. Смарт-контрактUniswapV2Factory.sol
в свою очередь импортируетUniswapV2Pair.sol
, который наследуется отUniswapV2ERC20.sol
.
uniswap-v2-periphery
Репозиторий uniswap-v2-periphery содержит вспомогательные смарт-контракты:
UniswapV2Migrator.sol
UniswapV2Router02.sol
UniswapV2Router01.sol
SafeMath.sol
UniswapV2Library.sol
UniswapV2LiquidityMathLibrary.sol
UniswapV2OracleLibrary.sol
Они взаимодействуют с основными смарт-контрактами из uniswap-v2-core. Эти смарт-контракты облегчают взаимодействие с протоколом для пользователей и разработчиков.
Необходимо задеплоить:
UniswapV2Router02.sol
. Предоставляет высокоуровневый интерфейс для взаимодействия с парами и пулами Uniswap. Основной функционал включает функции для свопа токенов, добавления и удаления ликвидности. Включает в себя необходимые библиотеки для работы протокола.
Таким образом обращение пользователя к смарт-контракту UniswapV2Router02.sol
можно представить в виде схемы:
А создание нового смарт-контракта пары выглядит так:
Для решение нашей задачи потребуется три основных шага - подготовка кодовой базы, настройка смарт-конрактов и деплой смарт-контрактов.
Подготовка кодовой базы
Убедитесь что Foundry установлен, проверить можно через forge --version
.
На данном этапе мы инициализируем наш проект и клонируем репозитории смарт-контрактов uniswap-v2.
Инициализируем проект:
forge init UNISWAP-V2-FORK-SC && cd ./UNISWAP-V2-FORK-SC
Добавим v2-core и v2-periphery смарт-контракты:
git submodule add https://github.com/Uniswap/v2-core.git contracts/v2-core
иgit submodule add https://github.com/Uniswap/v2-periphery.git contracts/v2-periphery
Добавим библиотеку
uniswap-lib
, которая используется вv2-periphery
смарт-контрактах:git submodule add https://github.com/Uniswap/uniswap-lib lib/uniswap-lib
и необходимую для работы скриптов/тестов foundry библиотекуgit submodule add https://github.com/foundry-rs/forge-std lib/forge-std
-
Поменяем путь к исходному коду в нашем файле
foundry.toml
://foundry.toml
[profile.default]
src = "contracts"
out = "out"
libs = ["lib"]
optimizer = true
optimizer_runs = 999999
-
Добавим файл в корневой каталог:
//remappings.txt
@uniswap/lib/=lib/uniswap-lib/
@uniswap/v2-core/=contracts/v2-core/
@uniswap/v2-periphery/=contracts/v2-periphery/
forge-std/=lib/forge-std/src/
Настройка смарт-контрактов
Uniswap для работы смарт-контракта UniswapV2Router02
использует метод pairFor
на смарт-контракте - библиотеке UniswapV2Library.sol.
С помощью данного метода адрес смарт-контракта пары вычисляется исходя из:
hex'ff'
адреса смарт-контракта
Factory.sol
адреса токенов erc-20 в пуле
init code hash
.
Таким образом uniswap не использует никаких внешних вызовов для получения адреса пары.
Что такое init code hash
и где нам его найти?
init code hash
представляет из себя keccak256 от байткода отвечающего за создание смарт-контракта UniswapV2Pair.sol.
Таким образом мы можем пойти по нескольким вариантам его получения:
-
Через добавление кода в смарт-контракт:
Добавим в смарт-контракт
Factory.sol
строкуbytes32 public constant INIT_CODE_HASH = keccak256(abi.encodePacked(type(UniswapV2Pair).creationCode));
После деплоя смарт-контракта
Factory.sol
мы смогли бы получитьinit code hash
через методINIT_CODE_HASH
. -
Через js скрипт:
const { ethers } = require('ethers'); const fs = require('fs'); const path = require('path'); const jsonFilePath = path.resolve(__dirname, '../out/UniswapV2Pair.sol/UniswapV2Pair.json'); async function computeInitCodeHash() { try { // Чтение ABI JSON файла const contractJson = JSON.parse(fs.readFileSync(jsonFilePath, 'utf8')); // Проверка наличия байткода в ABI JSON файле if (!contractJson.bytecode.object) { throw new Error('Байткод не найден в ABI JSON файле.'); } // Вычисление INIT_CODE_HASH с использованием байткода смарт-контракта const computedInitCodeHash = ethers.keccak256(contractJson.bytecode.object); console.log('INIT_CODE_HASH:', computedInitCodeHash); return computedInitCodeHash; } catch (error) { console.error('Ошибка при вычислении INIT_CODE_HASH:', error); } } computeInitCodeHash();
Чтобы не добавлять код в смарт-контракт и не изменять изначальные смарт-контракты от uniswap, пойдем по пути получения хеша через javascript.
Как вы можете заметить, для расчета используется ethers
библиотека, которую можно установить через npm install --save ethers
Далее, для получения байткода смарт-контракта нам нужно вызывать forge build
И наконец вызывать скрипт расчета node ./script/compute.js
Результат будет выведен в таком виде:
Полученный хеш нужно вставить в файл библиотеки uniswap - UniswapV2Library.sol
без 0x
.
Деплой смарт-контрактов
Переходим к непосредственному деплою смарт-контрактов.
-
Смарт-контракт Factory. Основной функционал - это создание пар токенов.
forge create src/v2-core/UniswapV2Factory.sol:UniswapV2Factory --rpc-url https://polygonzkevm-mainnet.g.alchemy.com/v2/demo --private-key putYourPrivatekeyHere --constructor-args "putFeeToSetterAddressHere" --verify --etherscan-api-key ACCESS_KEY
https://polygonzkevm-mainnet.g.alchemy.com/v2/demo
- RPC сеть куда будем деплоить.putYourPrivatekeyHere
- Приватный ключ с которого будет деплой.putFeeToSetterAddressHere
- Адрес который сможет устанавливать комиссию протокола.ACCESS_KEY
- API key для верификации смарт-контракта. Можно получить тут. Для этого необходимо зарегистрироваться и создать API key.При деплое может появится ошибка если блокчейн не поддерживает EIP-1559. Для этого необходимо добавить флаг
--legacy
.Если у вы Windows пользователь, у вас может быть ошибка - "Failed to create wallet from private key. Private key is invalid hex: Odd number of digits". Для решения этой проблемы нужно удалить \r symbol с private key. Для этого можете вызывать команду
PRIVATE_KEY=$(echo $PRIVATE_KEY | tr -d '\r')
-
Смарт-контракт
UniswapV2Router02
. Отвечает за удаление и добавление ликвидности в пулы, свапы токенов.forge create src/v2-periphery/UniswapV2Router02.sol:UniswapV2Router02 --rpc-url https://polygonzkevm-mainnet.g.alchemy.com/v2/demo --private-key putYourPrivatekeyHere --constructor-args "factoryAddressPutHere" "WETHAddressPutHere" --verify --etherscan-api-key ACCESS_KEY
https://polygonzkevm-mainnet.g.alchemy.com/v2/demo
- RPC сеть куда будем деплоить.putYourPrivatekeyHere
- Приватный ключ с которого будет деплой.factoryAddressPutHere
- Адрес смарт-контракта Factory.WETHAddressPutHere
- Адрес Wrapped Ether (WETH).ACCESS_KEY
- API key для верификации смарт-контракта.Для тестнета, мы задеплоили код оригинального WETH смарт-контракта.
-
Смарт-контракт multicall.
Смарт-контракт предназначен для:
Агрегирования результатов чтения с нескольких смарт-контрактов в один запрос JSON-RPC.
Выполнение нескольких вызовов изменения состояния блокчейна в одной транзакции.
Более детально можно почитать тут.
Хотя данный смарт-контракт не входит в группу смарт-контрактов необходимых для его работы, он все же потребуется для подключения frontend части.
На момент написания гайда, данный смарт-контракт уже задеплоен в сеть Polygon zkEVM testnet. Посмотреть полный перечень перечень сетей куда уже задеплоен смарт-контракт можно тут.
Заключение
Форк и деплой Uniswap V2 смарт-контрактов может показаться сложной задачей, но с правильными инструментами и подходом это становится гораздо более доступным. В этом гайде мы рассмотрели шаги, необходимые для клонирования исходного кода, настройки и деплоя смарт-контрактов, а также рассмотрели способы вычисления init code hash без изменения оригинальных смарт-контрактов.
Использование библиотек и инструментов, таких как Foundry и ethers.js, значительно упрощает процесс разработки и деплоя смарт-контрактов, позволяя сосредоточиться на ключевых аспектах интеграции и кастомизации.
Данный гайд показывает, что с пониманием базовых концепций и доступными инструментами, разработчики могут эффективно форкать и адаптировать популярные протоколы для своих нужд. Эти знания открывают путь к созданию новых проектов и продуктов на основе проверенных временем решений, таких как Uniswap V2.
Ссылки:
Делимся инсайтами и новостями из мира web3 в нашем телеграм-канале. Присоединяйтесь:)