Контекст: я хочу использовать блоки для отображения идентификатора на странице, я получаю учетную запись по умолчанию из web3, для этого пользователь должен войти в метамаску с выбранным адресом из своего кошелька.
Проблема: веб-приложение, похоже, не обнаруживает объект web3 в событии загрузки страницы, что является рекомендуемым местом для его обнаружения.
Код: ниже вдохновлен рекомендациями по адресу:
https://github.com/MetaMask/metamask-plugin/issues/1158
У меня постоянно прерывистое поведение, иногда web3 есть, а иногда нет, единственное решение, которое я могу придумать, это иметь таймер, но мне это кажется слишком упрощенным, я бы предпочел что-то более элегантное.
Вопрос: есть ли лучшее решение для обнаружения defaultAccount из web3 при загрузке страницы?
function startApp() {
GenerateIdenticon();
}
window.addEventListener('load', function () {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
if (web3.currentProvider.isMetaMask === true) {
if (typeof web3.eth.defaultAccount === 'undefined') {
document.body.innerHTML = '<body><h1>Oops! Your browser does not support Ethereum Ðapps.</h1></body>';
}
else {
startApp();
}
}
else {
alert('No web3? Please use google chrome and metamask plugin to enter this Dapp!', null, null);
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
Единственный метод, который более надежен, чем accounts
массив на странице, — это web3.eth.getAccounts(accounts => console.log(accounts[0]))
.
Это асинхронно запросит массив учетных записей и перезвонит, когда он будет доступен.
Вот что я использую в своем Dapp. Кажется, это работает очень хорошо.
function getWeb3(callback) {
if (typeof window.web3 === 'undefined') {
// no web3, use fallback
console.error("Please use a web3 browser");
} else {
// window.web3 == web3 most of the time. Don't override the provided,
// web3, just wrap it in your Web3.
var myWeb3 = new Web3(window.web3.currentProvider);
// the default account doesn't seem to be persisted, copy it to our
// new instance
myWeb3.eth.defaultAccount = window.web3.eth.defaultAccount;
callback(myWeb3);
}
}
Используется так:
function startApp(web3) {
// ...
}
window.addEventListener('load', function() {
getWeb3(startApp);
});
Ключевое отличие состоит в том, что я копирую defaultAccount
из исходного window.web3
экземпляра. Вы заметите, что web3.eth.defaultAccount
в Javascript API нет кода, специфичного для MetaMask. MetaMask, кажется, заполняется, defaultAccount
как только вы разблокируете свой кошелек.
Проверка web3.eth.accounts[0]
каждые 100 миллисекунд в некоторых случаях намного быстрее, чем web3.eth.getAccounts()
:
// Option 1:
web3.eth.getAccounts(console.log);
// Option 2:
(function loop() {
if (web3.eth.accounts[0]) {
console.log(web3.eth.accounts[0]);
} else {
setTimeout(loop, 100);
}
}());
При использовании прокси Option 2
для меня это было на 35 секунд (!) быстрее, чем Option 1
.
Что касается web3.eth.defaultAccount
, в документации MetaMask говорится, что его не следует использовать для определения того, какая учетная запись выбрана пользователем в данный момент.
Кстати, согласно документации MetaMask, вам нужно будет использовать setTimeout
/ setInterval
в любом случае для прослушивания выбранных изменений учетной записи :
var account = web3.eth.accounts[0];
setInterval(function () {
if (web3.eth.accounts[0] !== account) {
account = web3.eth.accounts[0];
updateInterface();
}
}, 100);
Пара вещей, которые я заметил при использовании MetaMask.
defaultAccount
не всегда заселен. Безопаснее использовать web3.eth.accounts[0]
в качестве проверки, выбрана ли учетная запись. Вам нужно будет периодически опрашивать это значение, если вы хотите знать, изменяется ли выбранная учетная запись.
Это load
событие также не всегда кажется надежным в некоторых моих опытах. В конце концов я решил это, но у меня нет кода, чтобы продемонстрировать, как это сделать. Я обновлю этот пост позже, если этого accounts[0]
фрагмента недостаточно.
Если вы используете React и столкнулись с этой проблемой, вам нужно сделать только это:
1. Установите веб3:
npm install web3 --save
2. Проверяем, есть ли MetaMask:
import 'Web3' from 'web3';
// ...
componentDidMount() {
// Check if Web3 has been injected by the browser (MetaMask).
// (since 'web3' is global, we need to use 'window')
if (window.web3 && window.web3.currentProvider.isMetaMask) {
window.web3.eth.getAccounts((error, accounts) => {
// Do whatever you need to.
this.setState({wallet: accounts[0]});
});
} else {
console.log('MetaMask account not detected :(');
}
}
null
когда вы разблокировали Metamask?Не бессовестный штекер.
Недавно начал использовать: https://www.blocknative.com/
Они предлагают хорошие шаблоны адаптации с MetaMask.
Хорхе Альварадо
Даниал Айтекин
web3.eth.getAccounts().then(...)
.Джобсамуэль
getAccounts
метод возвращает два (2) аргументаaccounts
, а второй. Другими словами:web3.eth.getAccounts((error, accounts) => console.log(accounts[0]))
.Эдуардо Перейра
DanF
Вячеслав Герчиков