Как мы форкнули Uniwap v2: гайд, как сделать это быстро и просто

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