3

I'm using Next.js to implement server-side rendering in my Ethereum app, however I can't fetch my Metamask address to display it in the top-right corner of the navigation bar in my index.js file. Currently, my getInitialProps() function returns an empty array. Can anyone help me get this to work?

  • I'm using web3 v1.0.0-beta.35
  • I'm logged into Metamask (using v 5.3.1)
  • I'm using web3.eth.getAccounts() to fetch the account from Metamask
  • I've granted permission to the app to access Metamask accounts in accordance with their breaking changes.

There have been a couple of instances where the address does pop up upon refresh, but the majority of the time it doesn't work.

Here's the repo for this project: https://github.com/jviray/buidl-box

Below is the code for my index.js file containing the component that's giving me issues. The address should be showing in the top-right corner of the navigation bar where it says { this.props.accounts[0] }.

import React, { Component } from 'react';
import Head from 'next/head';
import { Jumbotron, Button } from 'react-bootstrap/lib';
import web3 from '../ethereum/web3';

class Welcome extends React.Component {
  static async getInitialProps() {
    const accounts = await web3.eth.getAccounts();

    return { accounts };
  }

  render() {
    const jumbostyle = {
      textAlign: 'center',
      marginTop: '30px'
    };

    return (
      <div>
        <Head>
          <title>BUIDL</title>
          <meta
            name="viewport"
            content="initial-scale=1.0, width=device-width"
          />
          {/* -- Latest compiled and minified CSS */}
          <link
            rel="stylesheet"
            href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
            integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
            crossorigin="anonymous"
          />
        </Head>
        {/* NAVBAR */}
        <nav className="navbar navbar-inverse navbar-fixed-top">
          <div className="container">
            <div className="navbar-header">
              <a href="#" className="navbar-brand">
                BUIDL
              </a>
            </div>

            {/* NAVBAR ITEMS */}
            <ul className="nav navbar-nav navbar-right">
              <li className="navbar-brand">{this.props.accounts[0]}</li>
            </ul>
          </div>
        </nav>
        <Jumbotron>
          <div className="container" style={jumbostyle}>
            <h1>Welcome, Ethereum Devs!</h1>
            <p>
              As a community we need to start building new and powerful
              applications that truly add value.
            </p>
            <p>
              <a href="https://www.coindesk.com/dont-hodl-buidl-blockchain-tech-will-add-value-2018">
                <Button bsStyle="primary">Learn more</Button>
              </a>
            </p>
          </div>
        </Jumbotron>;
      </div>
    );
  }
}

export default Welcome;

What's interesting is that if I add component state and use React's "async componentDidMount()" to setState() with the fetched account, I'm able to get it to work consistently without issues after refreshing.

But again the goal is to fetch the account on the server-side with getInitialprops, and I can't get that to work.

Here's the code that works when I use "async componentDidMount()"

import React, { Component } from 'react';
import Head from 'next/head';
import { Jumbotron, Button } from 'react-bootstrap/lib';
import web3 from '../ethereum/web3';

class Welcome extends React.Component {
  state = {
    accountAddress: ''
  };

  async componentDidMount() {
    const accounts = await web3.eth.getAccounts();

    this.setState({
      accountAddress: accounts[0]
    });
  }

  render() {
    const jumbostyle = {
      textAlign: 'center',
      marginTop: '30px'
    };

    return (
      <div>
        <Head>
          <title>BUIDL</title>
          <meta
            name="viewport"
            content="initial-scale=1.0, width=device-width"
          />
          {/* -- Latest compiled and minified CSS */}
          <link
            rel="stylesheet"
            href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
            integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
            crossorigin="anonymous"
          />
        </Head>
        {/* NAVBAR */}
        <nav className="navbar navbar-inverse navbar-fixed-top">
          <div className="container">
            <div className="navbar-header">
              <a href="#" className="navbar-brand">
                BUIDL
              </a>
            </div>

            {/* NAVBAR ITEMS */}
            <ul className="nav navbar-nav navbar-right">
              <li className="navbar-brand">{this.state.accountAddress}</li>
            </ul>
          </div>
        </nav>
        <Jumbotron>
          <div className="container" style={jumbostyle}>
            <h1>Welcome, Ethereum Devs!</h1>
            <p>
              As a community we need to start building new and powerful
              applications that truly add value.
            </p>
            <p>
              <a href="https://www.coindesk.com/dont-hodl-buidl-blockchain-tech-will-add-value-2018">
                <Button bsStyle="primary">Learn more</Button>
              </a>
            </p>
          </div>
        </Jumbotron>;
      </div>
    );
  }
}

export default Welcome;

While it would be awesome if anyone could solve this, I'd also appreciate input on what the possible issue could be (async/await code, Next.js, web3, React, etc.). Thanks!!

3
  • Metamask queries can only be executed in client side code.
    – Ismael
    Jan 30, 2019 at 16:38
  • @Ismael But how does that explain those rare instances where the query works and the address pops up..only to disappear after refreshing. Thanks for insight!
    – jfviray
    Jan 30, 2019 at 17:41
  • From my understanding Next.js executes on the server only the first time, later interactions are in the client side. The web components needs to be aware of that, the so called isomorphic.
    – Ismael
    Jan 30, 2019 at 18:46

1 Answer 1

1

Metamask is a bridge that connects your browser to the specified blockchain via the ethereum provider that injected into window object. However since on server, you have no access to window, you cannot interact with metamask.

The important thing here is you always need a provider to connect to a blockchain. When we are on the server, we use @truffle/hdwallet-provider to connect to a blockchain

 const HDWalletProvider = require("@truffle/hdwallet-provider");
 const provider = new HDWalletProvider({
    mnemonic: {
      // mnemonics of metamask
      phrase: process.env.METAMASK,
    },
    // this is infura node that exists in rinkeby
    providerOrUrl: process.env.RINKEBY_NODE,
  });
  web3 = new Web3(provider);

then you can get the accounts

web3.eth.getAccounts().then(console.log);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.