Перейти к содержанию

Смена сети в Web3-кошельке: устаревший контекст

Оглавление курса «Web3-интерфейс: реестр в браузере» · Урок 13 из 30.

Публичный RPC и выбранный кошелёк могут смотреть на разные сети. Карточка показывает локальный курс 17, а расширение в этот момент подключено к другой цепочке. В этом уроке обработаем смену сети и защитим подготовленный запрос от устаревшего контекста. Результат — интерфейс не предлагает отправку в неопределённое окружение.

Предполагаются выбор провайдера, подключение аккаунта и поколение его состояния. Чтение продолжает использовать закреплённую сеть 31337 через HTTP-клиент. Код не запускался, запрос переключения кошелька не выполнялся. Номера чужих сетей в примерах обозначают различие окружений, а не настройку production-развёртывания.

Сеть принадлежит контексту операции

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

Событие chainChanged передаёт идентификатор сети шестнадцатеричной строкой. Его обработка похожа на смену аккаунта: увеличиваем поколение контекста и удаляем подготовленную симуляцию. Публичную карточку можно оставить, но ясно сообщить, что кошелёк сейчас смотрит в другую сеть. Иначе посетитель может ошибочно принять видимую карточку за данные выбранного расширения.

Не нужно автоматически менять публичный клиент вслед за каждым событием кошелька. Наше приложение посвящено определённому экземпляру учебного реестра. Автоматическое следование расширению могло бы превратить сайт в интерфейс произвольной сети с неподготовленной конфигурацией. Если продукт поддерживает несколько сетей, для каждой выбирается известная запись развёртывания.

Модуль сетевого контекста

Ниже самостоятельный сетевой слой поверх выбранного провайдера. Он не переключает сеть самостоятельно и не сохраняет старое поколение после изменения.

export function chainContext(provider, onChange) {
  let chainId = null;
  let revision = 0;
  function changed(hex) {
    chainId = typeof hex === 'string' ? BigInt(hex) : null;
    revision++;
    onChange({ chainId, revision, allowed: chainId === 31337n });
  }
  provider.on('chainChanged', changed);
  return {
    async readInitial() {
      changed(await provider.request({ method: 'eth_chainId' }));
    },
    snapshot() { return { chainId, revision }; },
    dispose() { provider.removeListener('chainChanged', changed); },
  };
}

Реальный адаптер также обрабатывает некорректную строку, если провайдер вернул неподходящие данные: ошибка преобразования не должна оборвать все подписки интерфейса. В минимальном учебном модуле предполагается корректный ответ совместимого провайдера. На границе доверия проверка формы ответа остаётся отдельным улучшением, а не скрытым свойством BigInt.

При начальном чтении возможна гонка с событием изменения. Если событие пришло раньше ответа старого запроса, поздний ответ может вернуть прежний номер. Для строгого контроллера перед запросом сохраняют поколение и применяют результат только при его совпадении. Этот приём уже знаком по загрузке карточки; внешний кошелёк тоже является асинхронным источником.

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

Кнопка «Выбрать локальную сеть» может запросить wallet_switchEthereumChain с chainId: '0x7a69'. Поддержка и согласие зависят от кошелька. Вызов не является приказом браузеру и может быть отклонён. После успешного ответа всё равно читаем актуальный контекст и обрабатываем соответствующее событие.

Добавление неизвестной сети — другой маршрут с параметрами RPC и названием. Для локальной лаборатории endpoint относится к устройству пользователя. В production нельзя автоматически подставлять адрес из случайного URL страницы и выдавать его за доверенную сеть. Пользователь должен понимать, какую конфигурацию добавляет в кошелёк.

Если запрос переключения отклонён, карточка остаётся читаемой, а запись недоступной. Не нужно закрывать весь сайт или автоматически повторять окно. Нормальное поведение человека включает отказ от изменения окружения; приложение предоставляет возможность вернуться позже.

Непосредственно перед подписью

Предварительная проверка при подключении не удерживает сеть неизменной. Перед writeContract ещё раз сверяем eth_chainId и доступный аккаунт с намерением. Если они отличаются, возвращаем пользователя к подготовке. Это сокращает обычные ошибки, однако не является атомарной блокировкой внешнего расширения на всё время подтверждения.

Сам Wallet Client также создаётся с явным объектом chain. Не следует использовать неопределённый клиент без сети и полагаться только на надпись в интерфейсе. Настройки клиента помогают библиотеке сопоставить контекст, а приложение сохраняет понятные пользователю параметры операции.

После получения хеша историю связывают с той сетью, в которую отправлялась транзакция. Если пользователь затем переключился, наблюдение продолжает прежний Public Client. Перенаправление наблюдения на новую сеть часто даёт ложное «транзакция исчезла», потому что хеш просто ищется в другом месте.

Возврат в прежнюю сеть

Сценарий A → B → A увеличивает поколение дважды. Старое подготовленное действие не становится автоматически свежим, потому что за это время могли измениться аккаунт, выпуск и данные реестра. Новое моделирование строится заново. Введённый пользователем отпечаток можно сохранить, но состояние «готово к отправке» сбрасывается.

Сохранённые локальные операции группируются по сети и экземпляру. Если журнал смешивает их в общий список, каждая строка содержит понятное обозначение происхождения. Сокращённый хеш без сети недостаточен для ссылки на explorer и восстановления. В локальной лаборатории explorer может вообще отсутствовать; это не означает отсутствия самой транзакции.

Для упражнения рассмотрите переключение во время чтения, во время симуляции и после получения хеша. В первых двух случаях устаревает подготовка, в последнем сохраняется независимое наблюдение отправленной операции. Ожидаемый итог — сетевой контекст является частью намерения, а не декоративной подписью. Стандарты описаны в EIP-1193 и EIP-3326.

Неподдерживаемая сеть

Если кошелёк сообщает сеть, которой нет в конфигурации приложения, интерфейс не создаёт для неё новый адрес реестра из прежней строки. Он показывает, что запись поддерживается только в выбранном окружении, и предоставляет понятный путь возвращения. Публичная карточка local при этом остаётся доступной, если её RPC отвечает.

Проверка формы шестнадцатеричной строки выполняется до BigInt. Например, неожиданное пустое значение должно превратиться в категорию ошибки провайдера, а не оборвать весь обработчик события. После такой ошибки подготовка остаётся недоступной до нового корректного контекста. Приложение не может безопасно «угадать сеть» по предыдущему значению.

Для общего контроллера удобно хранить сеть как целое и отображать имя через известную таблицу. Название из произвольного внешнего объекта не заменяет числовую проверку. На экране подтверждения человек видит и понятное обозначение, и доступные технические детали, связывающие действие с конкретным экземпляром.

Оглавление серии