Мультичейн: несколько сетей в одном dApp

dApp часто работает в нескольких сетях. Как организовать мультичейн: адреса контрактов на сеть, переключение и единый код.

Мультичейн dApp — приложение, работающее в нескольких сетях (Ethereum, Polygon, Arbitrum…). Контракт деплоится в каждую сеть отдельно, и фронт выбирает нужный адрес по текущему chainId.

Газ в Ethereum дорогой, поэтому многие dApp живут на L2 (Arbitrum, Optimism, Base) и сайдчейнах (Polygon). Часто — сразу в нескольких. Фронту нужно аккуратно понимать, «в какой сети мы сейчас» и «какой адрес контракта тут использовать».

Адрес контракта зависит от сети

Один контракт, задеплоенный в разные сети, имеет разные адреса. Хардкодить один адрес — классическая ошибка. Правильно — карта «сеть → адрес»:

const CONTRACTS = {
  1:     "0xAAA...mainnet",
  137:   "0xBBB...polygon",
  42161: "0xCCC...arbitrum",
};

function contractFor(chainId) {
  const addr = CONTRACTS[chainId];
  if (!addr) throw new Error("Сеть не поддерживается: " + chainId);
  return addr;
}

console.log(contractFor(137));   // 0xBBB...polygon
try { contractFor(999); } catch (e) { console.log(e.message); }

Вывод:

0xBBB...polygon
Сеть не поддерживается: 999

Проверка поддерживаемой сети

Если пользователь в неподдерживаемой сети, фронт должен это явно показать и предложить переключиться (через wallet_switchEthereumChain из раздела про кошельки). Молча «ничего не показывать» — плохой UX: пользователь решит, что dApp сломан.

В wagmi мультичейн встроен

wagmi знает текущий chainId (хук useChainId) и переключает сеть (useSwitchChain). Конфиг createConfig уже содержит список сетей и транспортов на каждую — поэтому правильный RPC выбирается автоматически:

import { useChainId, useSwitchChain } from "wagmi";

const chainId = useChainId();
const { switchChain } = useSwitchChain();
// switchChain({ chainId: 137 }) — переключить на Polygon

Как работает под капотом

Сети независимы: у каждой свой набор узлов, свой газовый токен, своя история. «Один контракт в двух сетях» — это две отдельные программы с одинаковым кодом, но разными адресами и состоянием. Поэтому фронт обязан выбирать и адрес, и RPC по текущей сети. L2 вроде Arbitrum исполняют те же EVM-вызовы, но дешевле; для фронта разница почти только в chainId, адресах и цене газа — код ethers/wagmi тот же.

Частые ошибки

  • Хардкод одного адреса контракта. В другой сети по нему ничего нет; держите карту сеть→адрес.
  • Не реагировать на неподдерживаемую сеть. Покажите баннер и кнопку переключения.
  • Использовать один RPC на все сети. У каждой сети свой RPC-эндпоинт; настройте транспорт на каждую.

Итоги

  • В разных сетях у контракта разные адреса — храните карту сеть→адрес.
  • Проверяйте поддержку сети и предлагайте переключение.
  • wagmi даёт useChainId/useSwitchChain и RPC на каждую сеть из конфига.
Проверьте себя
1. Почему нельзя хардкодить один адрес контракта для всех сетей?
AАдреса секретны
BВ разных сетях контракт имеет разные адреса
CТак требует ESLint
DАдрес меняется каждый блок
2. Что должен сделать фронт, если пользователь в неподдерживаемой сети?
AМолча ничего не показывать
BПоказать баннер и предложить переключить сеть
CОтправить транзакцию наугад
DУдалить кошелёк
3. Какой хук wagmi сообщает текущую сеть?
AuseAccount
BuseChainId
CuseReadContract
DuseBalance