
Привет, Хабр! Что если мы скажем, что сделать форк смарт-контрактов известного протокола не такая сложная задача, как может показаться? В этой статье я расскажу, как мы форкнули смарт-контракты Uniswap v2 и задеплоили их в Polygon zkEVM.
Базовые знания
Есть два основных репозитория:
uniswap-v2-core
Репозиторий uniswap-v2-core содержит ключевые смарт-контракты: UniswapV2ERC20.sol, UniswapV2Factory.sol, UniswapV2Pair.sol, которые реализуют основной функционал протокола Uniswap V2. Эти смарт-контракты обеспечивают децентрализованный обмен токенами.
Необходимо задеплоить:
UniswapV2Factory.solUniswapV2Pair.sol-
UniswapV2ERC20.solПервый контракт отвечает за создание и управление парами обмена (пулов ликвидности). Смарт-контракт фабрики также отслеживает все существующие пары и их адреса. Когда создается новая пара токенов, фабрика разворачивает новый смарт-контракт
UniswapV2Pair.sol, который представляет собой пул ликвидности для этой пары. Смарт-контрактUniswapV2Factory.solв свою очередь импортируетUniswapV2Pair.sol, который наследуется отUniswapV2ERC20.sol.
uniswap-v2-periphery
Репозиторий uniswap-v2-periphery содержит вспомогательные смарт-контракты:
UniswapV2Migrator.solUniswapV2Router02.solUniswapV2Router01.solSafeMath.solUniswapV2Library.solUniswapV2LiquidityMathLibrary.solUniswapV2OracleLibrary.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 = trueoptimizer_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_KEYhttps://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_KEYhttps://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 в нашем телеграм-канале. Присоединяйтесь:)