Besseres Muster zum Erkennen des web3-Standardkontos bei Verwendung von Metamask

Kontext: Ich möchte Blockies verwenden, um ein Identicon auf der Seite zu rendern, ich bekomme den defaultAccount von web3, dazu muss der Benutzer mit einer ausgewählten Adresse aus seinem Wallet bei Metamask angemeldet sein.

Das Problem: Die Web-App scheint das web3-Objekt beim Ladeereignis der Seite nicht zu erkennen, was der empfohlene Ort ist, um es zu erkennen.

Der folgende Code ist inspiriert von Empfehlungen unter:

https://github.com/MetaMask/metamask-plugin/issues/1158

https://github.com/MetaMask/faq/blob/master/DEVELOPERS.md#partly_sunny-web3---ethereum-browser-environment-check

Ich habe ständig intermittierendes Verhalten, manchmal ist web3 da und manchmal nicht, die einzige Lösung, die mir einfällt, ist, einen Timer zu haben, aber das scheint mir etwas zu einfach zu sein, ich würde etwas Eleganteres bevorzugen.

Frage: Gibt es eine bessere Lösung, um das defaultAccount von web3 zu erkennen, wenn die Seite geladen wird?

 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"));
}

Antworten (6)

Die eine Methode, die zuverlässiger ist als das In-Page- accountsArray, ist web3.eth.getAccounts(accounts => console.log(accounts[0])).

Dadurch wird das Konten-Array asynchron angefordert und zurückgerufen, wenn es verfügbar ist.

Vielen Dank, DanF, tatsächlich gibt die Verwendung dieser Methode immer den gewünschten Zustand zurück.
Alternative: web3.eth.getAccounts().then(...).
Da ich diese Arbeit nicht bekommen konnte, entdecke ich, dass die getAccountsMethode zwei (2) Argumente zurückgibt und accountsdas zweite ist. Mit anderen Worten: web3.eth.getAccounts((error, accounts) => console.log(accounts[0])).
Besteht die Gefahr, dass der Anbieter überschwemmt wird, wenn er diese Informationen alle 100 Sekunden anfordert?
Dies ist kein schwerwiegendes Risiko, da der Kontoanbieter lokal ist, sodass dies kein Netzwerkanruf ist, sondern nur eine Wertprüfung auf demselben Computer.
Die Chrome-Konsole zeigt den Wert "undefiniert" an

Folgendes verwende ich in meinem Dapp. Es scheint ziemlich gut zu funktionieren.

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);
  }
}

So verwendet:

function startApp(web3) {
  // ...
}

window.addEventListener('load', function() {
  getWeb3(startApp);
});

Der Hauptunterschied besteht darin, dass ich die defaultAccountvon der ursprünglichen window.web3Instanz kopiere. Sie werden feststellen, dass kein MetaMask-spezifischer Code web3.eth.defaultAccountTeil der Javascript-API ist. MetaMask scheint sich zu füllen, defaultAccountsobald Sie Ihre Brieftasche entsperren.

danke @0xcaff, aber wie DeviateFish erwähnt hat, haben Sie immer noch das gleiche Problem mit den defaultAccounts, trotzdem denke ich, dass Sie keinen Code haben, der sich auf Metamask bezieht, und sich nur auf die Standard-Web3-Aufrufe verlassen.

Die Überprüfung web3.eth.accounts[0]alle 100 Millisekunden ist in einigen Fällen viel schneller als 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);
  }
}());

Bei Verwendung eines Proxys Option 2war es bei mir bis zu 35 Sekunden (!) schneller als Option 1.


In Bezug auf web3.eth.defaultAccountsagt die MetaMask-Dokumentation , dass sie nicht verwendet werden sollte, um zu erkennen, welches Konto derzeit vom Benutzer ausgewählt ist.


Übrigens, laut MetaMask-Dokumentation müssen Sie setTimeout/ trotzdem verwenden, um auf ausgewähltesetInterval Kontoänderungen zu hören :

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

Ein paar Dinge, die mir bei der Verwendung von MetaMask aufgefallen sind.

  1. defaultAccountist nicht immer besetzt. Es ist sicherer, es web3.eth.accounts[0]als Überprüfung zu verwenden, um festzustellen, ob ein Konto ausgewählt ist oder nicht. Sie müssen diesen Wert regelmäßig abrufen, wenn Sie wissen möchten, ob sich das ausgewählte Konto ebenfalls ändert.

  2. Das loadEreignis scheint auch in einigen meiner Erfahrungen nicht immer zuverlässig zu sein. Ich habe das schließlich gelöst, aber ich habe meinen Code nicht zur Hand, um zu demonstrieren, wie. Ich werde diesen Beitrag später damit aktualisieren, wenn das accounts[0]Stück nicht ausreicht.

danke @DeviateFish, ich konnte zwar nicht sicherstellen, dass das defaultAccount jedes Mal ausgefüllt wurde, aber DanF empfahl, getAccounts mit einer Callback-Funktion zu verwenden. Auch für den Kontowechsel wäre es schön, einen Rückruf zu haben, wenn sich das Konto ändert, oder?
Es wäre in der Tat schön, aber so etwas gibt es derzeit nicht in web3 (oder über den RPC, soweit ich das beurteilen kann). Die Verwendung der asynchronen Methoden ist im Allgemeinen vorzuziehen, also bin ich froh, dass das für Sie funktioniert!

Wenn Sie React verwenden und auf dieses Problem stoßen, müssen Sie nur Folgendes tun:

1. web3 installieren:

npm install web3 --save

2. Überprüfen Sie, ob MetaMask vorhanden ist:

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 :(');
  }
}
Meine Eigenschaft currentProvider gibt an dieser Stelle null zurück. Gibt es einen Rückruf oder etwas, das ich verwenden kann, wenn es abgeschlossen ist?
@ user339946 kehrt zurück, nullwenn Sie Metamask entsperrt haben?
Ja, die Metamaske ist freigeschaltet. Es scheint, dass das web3-Objekt zu diesem Zeitpunkt noch nicht für die Komponente bereit ist. Irgendwelche Ideen?
Wie suchen Sie nach mobilen Wallets wie Trust oder Status? Metamask kann ich einfach fangen, aber keines der mobilen Wallets.
Ich weiß nicht @JamboDev :(

Kein schamloser Stecker.

Kürzlich angefangen zu verwenden: https://www.blocknative.com/

Sie bieten gute Onboarding-Muster mit MetaMask.