Подключение в проекте на ES6

Для работы с Universal Router в среде JavaScript (ES6) требуется установка официальных пакетов экосистемы Uniswap. Базовый набор включает:

  • @uniswap/universal-router
  • ethers или viem (в зависимости от выбранного стека)
  • вспомогательные ABI и утилиты

Установка через пакетный менеджер:

npm install @uniswap/universal-router ethers

или

yarn add @uniswap/universal-router ethers

Структура ES6-модуля

Современные JavaScript-проекты используют модульную систему ES6 (import/export). Для корректной работы необходимо:

  • указать "type": "module" в package.json
  • либо использовать расширение .mjs

Пример package.json:

{
  "type": "module"
}

Импорт библиотек

Universal Router не предоставляет «высокоуровневого клиента», а работает через ABI и вызовы смарт-контракта. Основные элементы импортируются следующим образом:

import { ethers } from 'ethers'
import { UNIVERSAL_ROUTER_ADDRESS } from '@uniswap/universal-router'
import UniversalRouterABI from '@uniswap/universal-router/artifacts/contracts/UniversalRouter.sol/UniversalRouter.json' assert { type: 'json' }

Ключевые моменты:

  • ethers используется для взаимодействия с блокчейном
  • UNIVERSAL_ROUTER_ADDRESS — адрес контракта (может отличаться в зависимости от сети)
  • ABI необходим для создания экземпляра контракта

Инициализация провайдера

Провайдер — это точка входа для взаимодействия с сетью Ethereum.

const provider = new ethers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_API_KEY')

Возможные альтернативы:

  • Alchemy
  • локальный узел (Hardhat / Anvil)
  • публичные RPC

Подключение кошелька

Для подписания транзакций используется Signer:

const wallet = new ethers.Wallet(PRIVATE_KEY, provider)

Важно:

  • приватный ключ должен храниться безопасно (например, в .env)
  • в production-среде используется менеджер секретов

Создание экземпляра Universal Router

После инициализации провайдера и кошелька создаётся контракт:

const router = new ethers.Contract(
  UNIVERSAL_ROUTER_ADDRESS,
  UniversalRouterABI.abi,
  wallet
)

Объект router становится основным интерфейсом для взаимодействия с Universal Router.


Конфигурация сети

Universal Router развёрнут в нескольких сетях. Наиболее используемые:

Сеть Адрес
Ethereum Mainnet фиксированный
Arbitrum отдельный адрес
Optimism отдельный адрес

Пример переключения сети:

const provider = new ethers.JsonRpcProvider('https://arb1.arbitrum.io/rpc')

Адрес роутера должен соответствовать выбранной сети.


Работа с переменными окружения

Для ES6-проектов рекомендуется использовать dotenv:

npm install dotenv

Подключение:

import dotenv from 'dotenv'
dotenv.config()

const PRIVATE_KEY = process.env.PRIVATE_KEY
const RPC_URL = process.env.RPC_URL

Файл .env:

PRIVATE_KEY=your_private_key
RPC_URL=https://mainnet.infura.io/v3/your_key

Проверка подключения

Базовая проверка корректности инициализации:

async function checkConnection() {
  const balance = await provider.getBalance(wallet.address)
  console.log(`Balance: ${ethers.formatEther(balance)} ETH`)
}

checkConnection()

Если баланс успешно получен:

  • провайдер работает
  • кошелёк подключён
  • сеть доступна

Подготовка к выполнению команд

Universal Router использует концепцию команд (commands) и входных данных (inputs).

Перед использованием требуется:

  1. Подготовить массив команд (bytes)
  2. Закодировать параметры (ABI encoding)

Импорт вспомогательных инструментов:

import { AbiCoder } from 'ethers'

Создание кодировщика:

const abiCoder = new AbiCoder()

Базовая структура вызова

Все операции выполняются через функцию execute:

await router.execute(commands, inputs, deadline)

Где:

  • commands — байтовая последовательность инструкций
  • inputs — массив закодированных параметров
  • deadline — timestamp, ограничивающий выполнение

Обработка ошибок подключения

Типичные проблемы:

1. Неверный RPC URL

Error: could not detect network

2. Неверный приватный ключ

Error: invalid private key

3. Несоответствие сети и адреса контракта

execution reverted

Рекомендуется добавлять обработку:

try {
  // операции
} catch (error) {
  console.error('Connection error:', error)
}

Асинхронная структура ES6

Все взаимодействия с блокчейном — асинхронные. Используется async/await:

async function init() {
  const network = await provider.getNetwork()
  console.log(network)
}

init()

Разделение логики по модулям

Типичная структура проекта:

/src
  /config
    provider.js
  /contracts
    router.js
  /utils
    encoding.js
  index.js

Пример provider.js:

import { ethers } from 'ethers'
import dotenv from 'dotenv'

dotenv.config()

export const provider = new ethers.JsonRpcProvider(process.env.RPC_URL)

Пример router.js:

import { ethers } from 'ethers'
import { provider } from '../config/provider.js'
import UniversalRouterABI from '@uniswap/universal-router/artifacts/contracts/UniversalRouter.sol/UniversalRouter.json' assert { type: 'json' }

const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider)

export const router = new ethers.Contract(
  'UNIVERSAL_ROUTER_ADDRESS',
  UniversalRouterABI.abi,
  wallet
)

Оптимизация инициализации

Для уменьшения количества подключений:

  • использовать singleton-провайдер
  • избегать повторного создания Contract
  • кешировать объекты

Пример:

let routerInstance = null

export function getRouter() {
  if (!routerInstance) {
    routerInstance = new ethers.Contract(
      UNIVERSAL_ROUTER_ADDRESS,
      UniversalRouterABI.abi,
      wallet
    )
  }
  return routerInstance
}

Совместимость с фронтендом

При использовании в браузере:

  • применяется ethers.BrowserProvider
  • подключение через MetaMask
const provider = new ethers.BrowserProvider(window.ethereum)
const signer = await provider.getSigner()

Проверка доступности Universal Router

Проверка существования контракта:

const code = await provider.getCode(UNIVERSAL_ROUTER_ADDRESS)

if (code === '0x') {
  throw new Error('Contract not deployed')
}

Работа с BigInt

ES6-версия ethers использует BigInt:

const amount = 1000000000000000000n

или:

const amount = ethers.parseEther('1')

Логирование и отладка

Для отслеживания выполнения:

console.log({
  address: wallet.address,
  network: await provider.getNetwork(),
})

Дополнительно:

  • использовать debug логирование
  • подключать Hardhat для локальной отладки

Подготовка к дальнейшей работе

После выполнения всех шагов:

  • создан провайдер
  • подключён кошелёк
  • инициализирован Universal Router
  • настроена структура ES6-модулей

Среда готова для выполнения сложных сценариев:

  • мульти-свопы
  • взаимодействие с NFT
  • агрегированные транзакции через Universal Router