Contexto: quiero usar bloques para representar un identicon en la página, obtengo la cuenta predeterminada de web3, para esto, el usuario debe iniciar sesión en metamask con una dirección seleccionada de su billetera.
El problema: la aplicación web parece no detectar el objeto web3 en el evento de carga de la página, que es el lugar recomendado para detectarlo.
El código: a continuación está inspirado en las recomendaciones de:
https://github.com/MetaMask/metamask-plugin/issues/1158
Sigo teniendo un comportamiento intermitente, a veces web3 está ahí ya veces no, la única solución que se me ocurre es tener un temporizador, pero eso me parece un poco simplista, preferiría algo más elegante.
Pregunta: ¿Existe una solución mejor para detectar la cuenta predeterminada de web3 cuando se carga la página?
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"));
}
El único método que es más confiable que la accounts
matriz en la página es web3.eth.getAccounts(accounts => console.log(accounts[0]))
.
Esto solicitará de forma asincrónica la matriz de cuentas y devolverá la llamada cuando esté disponible.
Esto es lo que uso en mi Dapp. Parece funcionar bastante bien.
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);
}
}
Usado así:
function startApp(web3) {
// ...
}
window.addEventListener('load', function() {
getWeb3(startApp);
});
La diferencia clave es que copio el de la instancia defaultAccount
original . window.web3
Notarás que no hay un código específico de MetaMask que web3.eth.defaultAccount
sea parte de la API de Javascript. MetaMask parece llenarse defaultAccount
una vez que desbloqueas tu billetera.
Verificar web3.eth.accounts[0]
cada 100 milisegundos es mucho más rápido en algunos casos que 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);
}
}());
Al usar un proxy, Option 2
fue hasta 35 segundos (!) Más rápido para mí que Option 1
.
Con respecto a web3.eth.defaultAccount
, la documentación de MetaMask dice que no debe usarse para detectar qué cuenta está seleccionada actualmente por el usuario.
Por cierto, de acuerdo con la documentación de MetaMask, deberá usar setTimeout
/ setInterval
de todos modos para escuchar los cambios de cuenta seleccionados :
var account = web3.eth.accounts[0];
setInterval(function () {
if (web3.eth.accounts[0] !== account) {
account = web3.eth.accounts[0];
updateInterface();
}
}, 100);
Un par de cosas que he notado al usar MetaMask.
defaultAccount
no siempre está poblado. Es más seguro usarlo web3.eth.accounts[0]
como verificación para ver si una cuenta está seleccionada o no. Deberá sondear este valor periódicamente si desea saber si la cuenta seleccionada también cambia.
El load
evento tampoco siempre parece confiable en algunas de mis experiencias. Eventualmente resolví esto, pero no tengo mi código a mano para demostrar cómo. Actualizaré esta publicación más tarde, si la accounts[0]
pieza no es suficiente.
Si está utilizando React y enfrenta este problema, solo necesita hacer esto:
1. Instalar web3:
npm install web3 --save
2. Compruebe si MetaMask está allí:
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
cuando desbloqueaste Metamask?No es un enchufe desvergonzado.
Recientemente comencé a usar: https://www.blocknative.com/
Ofrecen buenos patrones de incorporación con MetaMask.
Jorge Alvarado
danyal aytekin
web3.eth.getAccounts().then(...)
.Jobsamuel
getAccounts
método devuelve dos (2) argumentos yaccounts
es el segundo. En otras palabras:web3.eth.getAccounts((error, accounts) => console.log(accounts[0]))
.eduardo pereira
DanF
Vyachaslav Gerchicov