Как я могу обнаружить изменение учетной записи в Metamask?

Когда пользователь переходит на другую учетную запись в метамаске, есть ли способ обнаружить это асинхронно в коде?

сейчас я использую

this.web3.eth.getAccounts((err, accs) => {   
  this.account = accs[0];
});  

но при смене аккаунта все равно подхватывает предыдущий. Обновление страницы — не выход. Может кто сталкивался с этим и есть решение?

К сожалению, большинство людей используют метод опроса изменений с помощью setIntervals. Единственный другой вариант — проверка совпадения учетных записей перед каждым вызовом.

Ответы (6)

Как было предложено в FAQ по Metamask , это может быть вариант:

var account = web3.eth.accounts[0];
var accountInterval = setInterval(function() {
  if (web3.eth.accounts[0] !== account) {
    account = web3.eth.accounts[0];
    updateInterface();
  }
}, 100);

редактировать

В более новой версии метамаска предоставляет событие, которое можно использовать для определения наличия изменения учетной записи в соответствии с новым документом :

window.ethereum.on('accountsChanged', function (accounts) {
  // Time to reload your interface with accounts[0]!
})
К сожалению, на данный момент проверка в цикле является единственным поддерживаемым методом.
Однако будьте осторожны, у меня была проблема, когда я всегда сопоставлял условие if, потому что учетная запись, которую я получаю, всегда была строчной.
Я использую и предлагаю использовать событие onFocus для решения этой проблемы.
Есть ли подобное решение для расширения TronLink (tronWeb)?

Из документов MetaMask :

window.ethereum.on('accountsChanged', function (accounts) {
  // Time to reload your interface with accounts[0]!
})

window.ethereum.on('networkChanged', function (networkId) {
  // Time to reload your interface with the new networkId
})

Как отметил @Sr.PEDRO , ethereum.publicConfigStoreв будущем работать не будет. На самом деле, он будет удален полностью. См. этот комментарий GitHub для деталей.

Вы также можете запретить MetaMask автоматически перезагружать веб-страницу:

window.onbeforeunload = function() {
  return "Prevent reload"
}

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

Есть ли подобное решение для расширения TronLink (tronWeb)?
URL-адрес документов изменился, перейдите по адресу docs.metamask.io/guide/ethereum-provider.html#table-of-contents.

Используя web3 версии 1.0.0, поставщик метамаски предоставляет событие «обновление», которое вы можете прослушать в своем общедоступном хранилище ConfigStore.

web3.currentProvider.publicConfigStore.on('update', callback);

Ваш обратный вызов будет передавать объект с «selectedAddress» и «networkVersion» всякий раз, когда эти атрибуты изменяются.

Привет, Брайан, где я могу найти документацию о событии обновления? Поискал документы web3 1.0. Спасибо.
В новой версии метамаски имя изменилось, теперь вы должны использовать web3.currentProvider._publicConfigStore.on('update', callback);Но это, вероятно, не будет поддерживаться метамаской в ​​будущем, поэтому я бы рекомендовал использовать события window.ethereum medium.com/metamask/…

Вы можете использовать useEffect для listenEvent, как показано ниже:

useEffect(() => {
    async function listenMMAccount() {
      window.ethereum.on("accountsChanged", async function() {
        // Time to reload your interface with accounts[0]!
        accounts = await web3.eth.getAccounts();
        // accounts = await web3.eth.getAccounts();
        console.log(accounts);
      });
    }
    listenMMAccount();
  }, []);

Вы используете chainChangedсобытие, но вы должны учитывать 3 вещи:

  • Вы должны установить слушателя глобально один раз. Либо в навигационной панели, либо при использовании провайдера в провайдере или в next.js в компоненте _app

  • При изменении цепочки необходимо перезагрузить страницу, рекомендованную метамаской:

Мы настоятельно рекомендуем перезагружать страницу при изменении цепочки, если у вас нет веских причин этого не делать.

  • после установки прослушивателя для chainChangedсобытия вы должны удалить прослушиватель

вот пример в реакции/next.js

  useEffect(() => {
   async function initWeb3() {
     try {
      const provider = new ethers.providers.Web3Provider(
        window.ethereum );
      setListener(window.ethereum);
      // then add logic here
    } catch (error: any) {
      // handle error
    }
  }
   initWeb3();
   return () => removeListener(window.ethereum);
  }, []);

  // this has to be set once globally. metamask suggests
  const setListener = (ethereum) => {
     ethereum.on("chainChanged", pageReload);
  };
  const removeListener = (ethereum) => {
    ethereum.removeListener("chainChanged", pageReload);
  };

  function pageReload() {
    window.location.reload();
  }

Обнаружение изменений в учетной записи Metamask

 useEffect(() => {
    if (window.ethereum) {
   
      window.ethereum.on("accountsChanged", () => {
        window.location.reload();
      });
    }
  });