1

I'm trying to build a login system using MetaMask. Everything is working thus far except for sending a signed message. The signed message goes through to MetaMask but then it gets stuck resolving the web3.eth.personal.sign promise, it never moves onto the next item in the promise chain.

Here is the full code:

import React, { Component } from 'react';
import Web3 from 'web3';

import './Login.css';

let web3 = null;

class Login extends Component {
    state = {
        loading: false
    };

    handleAuthenticate = ({ publicAddress, signature }) => {
        fetch(`${process.env.REACT_APP_BACKEND_URL}/auth`, {
            body: JSON.stringify({ publicAddress, signature }),
            headers: {
                'Content-Type': 'application/json'
            },
            method: 'POST'
        }).then(response => response.json());
    };

    handleClick = async () => {
        const { onLoggedIn } = this.props;

        
        if (!window.ethereum) {
            window.alert('Please install MetaMask first.');
            return;
        }
        if (!web3) {
            web3 = new Web3(window.ethereum);
        }
        const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
        if (!accounts[0]) {
            window.alert('Please activate MetaMask first.');
            return;
        }
        const publicAddress = accounts[0].toLowerCase();
        this.setState({ loading: true });

        fetch(`${process.env.REACT_APP_BACKEND_URL}/users?publicAddress=${publicAddress}`)
        .then(response => response.json())
        .then(users => (users.length ? users[0] : this.handleSignup(publicAddress)))
        .then(this.handleSignMessage)
        .then(this.handleAuthenticate)
        .then(onLoggedIn)
        .catch(err => {
            window.alert(err);
            this.setState({ loading: false });
        });
        
    };

    handleSignMessage = ({ publicAddress, nonce }) => {
        return new Promise((resolve, reject) =>
            web3.eth.personal.sign(
                web3.utils.utf8ToHex(`I am signing my one-time nonce: ${ nonce }`),
                publicAddress,
                (err, signature) => {
                    if (err) return reject(err);
                    return resolve({ publicAddress, signature });
                })
            );
        console.log("success");
    };

    handleSignup = publicAddress => {
        fetch(`${process.env.REACT_APP_BACKEND_URL}/users`, {
            body: JSON.stringify({ publicAddress }),
            headers: {
                'Content-Type': 'application/json'
            },
            method: 'POST'
        }).then(response => response.json());
    };


    render() {
        const { loading } = this.state;
        return (
            <div>
                <p>
                    Please login with MetaMask.
                </p>
                <button className="Login-button Login-mm" onClick={() => {this.handleClick()}}>
                    {loading ? 'Loading...' : 'Login with MetaMask'}
                </button>
            </div>
        );
    }
}

export default Login;

The problem is with the handleSignMessage function. It never moves on to handleAuthenticate.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.