китаев.tech

Смена сети — addChain и switchChain

Как переключить MetaMask на нужную сеть через wallet_switchEthereumChain и добавить сеть через wallet_addEthereumChain, если её ещё нет в кошельке.

Зачем dApp переключает сеть

dApp работает только в той сети, где задеплоены её контракты.

Если контракт находится в Base, а пользователь открыл сайт с выбранным Ethereum Mainnet в MetaMask, транзакция уйдёт не туда или вообще не соберётся. Поэтому приложение должно проверить сеть и попросить кошелёк переключиться.


Переключаем MetaMask на Base

typescript
import { BrowserProvider } from "ethers";

type EthereumProvider = {
  request(args: {
    method: string;
    params?: unknown[] | Record<string, unknown>;
  }): Promise<unknown>;
};

declare global {
  interface Window {
    ethereum?: EthereumProvider;
  }
}

const baseMainnet = {
  chainId: "0x2105",
  chainName: "Base",
  nativeCurrency: {
    name: "Ether",
    symbol: "ETH",
    decimals: 18,
  },
  rpcUrls: ["https://mainnet.base.org"],
  blockExplorerUrls: ["https://basescan.org"],
};

const app = document.createElement("main");
app.innerHTML = `
  <button id="switch-network">Переключиться на Base</button>
  <pre id="network-info">Сеть не проверена</pre>
`;
document.body.appendChild(app);

const button = document.querySelector<HTMLButtonElement>("#switch-network");
const output = document.querySelector<HTMLPreElement>("#network-info");

if (!button || !output) {
  throw new Error("Не удалось найти элементы интерфейса");
}

function getErrorCode(error: unknown): number | undefined {
  if (typeof error === "object" && error !== null && "code" in error) {
    const code = (error as { code: unknown }).code;
    return typeof code === "number" ? code : undefined;
  }

  return undefined;
}

async function switchToBase() {
  if (!window.ethereum) {
    output.textContent = "MetaMask не найден. Установите расширение браузера.";
    return;
  }

  try {
    await window.ethereum.request({
      method: "wallet_switchEthereumChain",
      params: [{ chainId: baseMainnet.chainId }],
    });
  } catch (error: unknown) {
    if (getErrorCode(error) !== 4902) {
      throw error;
    }

    await window.ethereum.request({
      method: "wallet_addEthereumChain",
      params: [baseMainnet],
    });

    await window.ethereum.request({
      method: "wallet_switchEthereumChain",
      params: [{ chainId: baseMainnet.chainId }],
    });
  }

  const provider = new BrowserProvider(window.ethereum);
  const network = await provider.getNetwork();

  output.textContent = `Текущая сеть: ${network.name} (${network.chainId})`;
}

button.addEventListener("click", () => {
  switchToBase().catch((error: unknown) => {
    const message = error instanceof Error ? error.message : "Неизвестная ошибка";
    output.textContent = `Ошибка смены сети: ${message}`;
  });
});

Этот код должен выполняться в браузере. MetaMask показывает пользователю подтверждение перед сменой или добавлением сети.


Как это работает

chainId: "0x2105" — идентификатор Base Mainnet в шестнадцатеричном формате. MetaMask требует именно 0x-строку, а не число 8453.

wallet_switchEthereumChain — просит кошелёк переключиться на сеть с указанным chainId.

4902 — код ошибки MetaMask: такой сети ещё нет в кошельке пользователя.

wallet_addEthereumChain — просит добавить новую сеть. Для этого нужны chainName, rpcUrls, nativeCurrency и желательно blockExplorerUrls.

new BrowserProvider(window.ethereum) — после переключения читает активную сеть через ethers.js.


addChain не заменяет switchChain

wallet_addEthereumChain добавляет сеть в кошелёк, но приложение всё равно должно убедиться, что она стала активной.

Поэтому надёжный порядок такой:

text
1. Пробуем wallet_switchEthereumChain
2. Если получили 4902 — вызываем wallet_addEthereumChain
3. После добавления снова вызываем wallet_switchEthereumChain
4. Читаем provider.getNetwork() и проверяем результат

Так приложение не зависит от того, переключил ли кошелёк сеть автоматически после добавления.


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

Передавать chainId как число → используйте строку в hex-формате: "0x2105", "0x1", "0x89".

Добавлять сеть без проверки ошибки 4902 → сначала пробуйте wallet_switchEthereumChain. Если сеть уже есть, добавлять её заново не нужно.

Использовать непроверенный RPC URL → пользователь доверяет сети, которую предлагает dApp. Указывайте официальный RPC или надёжного провайдера.


Что дальше

Материалы китаev.tech публикуются в образовательных целях и не являются инвестиционной рекомендацией. Примеры кода и описания протоколов — для обучения; использование в продакшне на ваш собственный риск. Дисклеймер и политика конфиденциальности.