¿Cómo puedo comprobar si un usuario ha iniciado sesión en Metamask?

Probé un ejemplo muy simple de web3, funciona si inicia sesión en Metamask e intenta enviar algo de ETH.

Sin embargo, si no he iniciado sesión en Metamask, no se muestran errores ni sugerencias.

¿Cómo puedo comprobar si un usuario ya ha iniciado sesión en Metamask?

    <html>
      <head>
         <title>Introduction to Dapps. Simple MetaMask example.</title>
      </head>
      <body>
      <div id="meta-mask-required"></div>
      <fieldset>
        <label> Ether:
          <input type="text" id="amount"></input>
        </label>
        <button onclick="send()">Donate to the Author</button>
        <div id="response"></div>
      </fieldset>

      <script>
        // MetaMask injects the web3 library for us.
        window.onload = function() {
          if (typeof web3 === 'undefined') {
            document.getElementById('meta-mask-required').innerHTML = 'You need <a href="https://metamask.io/">MetaMask</a> browser plugin to run this example'
          }
        }
        function send() {
          web3.eth.sendTransaction({
            from: web3.eth.coinbase,
            to: '0xA7b25444868Cc0e6AcFd81852b3bc3F335933760',
            value: web3.toWei(document.getElementById("amount").value, 'ether')
          }, function(error, result) {
            if (!error) {
              document.getElementById('response').innerHTML = 'Success: <a href="https://testnet.etherscan.io/tx/' + result + '"> View Transaction </a>'
            } else {
              document.getElementById('response').innerHTML = '<pre>' + error + '</pre>'
            }
          })
        }
      </script>
      </body>
    </html>

Respuestas (3)

La forma en que resolví esto es llamandoweb3.eth.getAccounts()

Si devuelve una matriz vacía, significa que el usuario no ha iniciado sesión en MetaMask:

web3.eth.getAccounts(function(err, accounts){
    if (err != null) console.error("An error occurred: "+err);
    else if (accounts.length == 0) console.log("User is not logged in to MetaMask");
    else console.log("User is logged in to MetaMask");
});
Desafortunadamente, hice el mismo error, al menos a partir de hoy, esa técnica no funciona. getAccounts() nunca regresa (es decir, el bloque "entonces" adjunto a la llamada getAccounts() nunca se ejecuta).
¿Qué pasa con firefox? no hay web3 en firefox...
La nota getAccountsestá en desuso en favor de un RPC eth_accounts

MetaMask ya no se inyectará web3, por lo que no es una buena práctica confiar en él.

Usé la ethers.jsbiblioteca. Tuve que incluir eso en mi proyecto usando rollup.js, pero también podrías usar bundler o webpack o lo que sea.

const { ethereum } = window;
if (ethereum) {
    var provider = new ethers.providers.Web3Provider(ethereum);
}

...

const isMetaMaskConnected = async () => {
    const accounts = await provider.listAccounts();
    return accounts.length > 0;
}

await isMetaMaskConnected().then((connected) => {
    if (connected) {
        // metamask is connected
    } else {
        // metamask is not connected
    }
});

Yo creo que puedes usar el Provider y ver cuantas cuentas tienes y a partir de ahí si tienes 0 cuentas puedes pensar que el usuario no ha conectado ninguna cuenta. Toma en cuenta este ejemplo:

function handleAccountsChanged(accounts) {
  if (accounts.length === 0) {
   // MetaMask is locked or the user has not connected any accounts
   console.log('Please connect to MetaMask.');
  } else if (accounts[0] !== currentAccount) {
    currentAccount = accounts[0];
    // Do any other work!
  }
}

Puede ver información más completa como ejemplo aquí: https://docs.metamask.io/guide/ethereum-provider.html#using-the-provider

¡Cuidadoso! Como se indica en la documentación, "conectado" y "desconectado" se refieren a si el proveedor puede realizar solicitudes RPC a la cadena actual, pero no tiene nada que hacer si el usuario ya ha iniciado sesión en Metamask.
ya esta quitado.
@SergiJuanati tienes 100% de razón gracias por el comentario aquí!. ¡Actualizaré esto!