Skip to content

Instantly share code, notes, and snippets.

@duartefdias
Created December 24, 2021 12:30
Show Gist options
  • Save duartefdias/b2d1557a35a0bec6329d3f54e1771f5e to your computer and use it in GitHub Desktop.
Save duartefdias/b2d1557a35a0bec6329d3f54e1771f5e to your computer and use it in GitHub Desktop.
<script>
import Web3 from 'web3'
export default ({
data() {
return {
buttonDisabled: false,
buttonInstallText: "Click here to install Metamask",
}
},
methods: {
performAction() {
if (this.isMetaMaskInstalled()) {
this.connectToMetamask()
} else {
// Redirect to metamask install page
if(process.client){ window.open('https://metamask.io/'); }
}
},
//Check if MetaMask extension is installed
isMetaMaskInstalled() {
//Have to check the ethereum binding on the window object to see if it's installed
if(process.client){
return Boolean(this.$store.getters['metamask/ethereum'] && this.$store.getters['metamask/ethereum'].isMetaMask);
}
return false
},
async checkIfUserRegistered(address) {
const response = await this.$axios.$get('/users/' + address)
// Handle response
if (response === address) {
return true
} else {
return this.registerUser(address)
}
},
async registerUser(address) {
const response = await this.$axios.post('/users/register', {
address: address,
})
console.log('Register user response: ' + response)
},
handleSignMessage(publicAddress, nonce) {
// Define instance of web3
var web3 = new Web3(window.ethereum)
return new Promise((resolve, reject) =>
web3.eth.personal.sign(
web3.utils.fromUtf8(`Nonce: ${nonce}`),
publicAddress,
(err, signature) => {
if (err) return reject(err);
return resolve({ publicAddress, signature });
}
)
);
},
async connectToMetamask() {
try {
// Connect to metamask and get user accounts
const accounts = await this.$store.getters['metamask/ethereum'].request({ method: 'eth_requestAccounts' });
// Update vuex store
this.$store.commit('metamask/setMetamaskConnected', true)
this.$store.commit('metamask/setAccounts', accounts)
// Check if user is registered, if not, register them
const isRegistered = await this.checkIfUserRegistered(accounts[0])
// Request nonce from backend
const responseNonce = await this.$axios.get('/users/' + accounts[0] + '/nonce')
const nonce = responseNonce.data
// Sign message
const signedMessage = await this.handleSignMessage(accounts[0], nonce)
// Send signature to backend
const responseSign = await this.$axios.post('/users/' + accounts[0] + '/signature', signedMessage)
// Set token in store
this.$store.commit('metamask/setToken', responseSign.data.token)
// If successful, redirect to home
if (responseSign.status === 200) {
this.$router.push('/')
}
} catch (error) {
console.log(error)
}
}
}
})
</script>
@ChristianOConnor
Copy link

ChristianOConnor commented Mar 12, 2022

When I run this code I get the exact same error as described here: web3/web3.js#4659. They developed a workaround in this thread involving react-app-rewired. I'm assuming this doesn't work for vue. The problem centers around web3. Do you have a fix for this particular vue app?

UPDATE
I fixed it. I had to add this to the vue.config.js file in the root directory:

const { defineConfig } = require("@vue/cli-service");
const webpack = require("webpack");
const path = require("path");

module.exports = defineConfig({
  transpileDependencies: true,
  configureWebpack: {
    plugins: [
      new webpack.ProvidePlugin({
        Buffer: ["buffer", "Buffer"],
        process: "process/browser",
      }),
    ],
    resolve: {
      alias: {
        "@contracts": path.resolve(__dirname, "build", "contracts"),
      },
      fallback: {
        http: require.resolve("stream-http"),
        https: require.resolve("https-browserify"),
        crypto: require.resolve("crypto-browserify"),
        stream: require.resolve("stream-browserify"),
        os: require.resolve("os-browserify/browser"),
        url: require.resolve("url"),
        assert: require.resolve("assert"),
      },
    },
  },
});

@ChristianOConnor
Copy link

I have another problem. The site compiles now but the button doesn't work. This is what my webpage looks like:
https://imgur.com/a/ndF3xzr

This is my components/MetamaskConnectWidget.vue file:

<template>
  <div>
    <v-btn
      color="primary"
      large
      :disabled="buttonDisabled"
      @click="performAction()"
    >
      <img src="../assets/metamaskloginbutton.png" class="metamask-logo" />
      <span v-if="isMetaMaskInstalled()">Login with Metamask</span>
      <span v-if="!isMetaMaskInstalled()">{{ buttonInstallText }}</span>
    </v-btn>
  </div>
</template>

<script>
import Web3 from "web3";
export default {
  data() {
    return {
      buttonDisabled: false,
      buttonInstallText: "Click here to install Metamask",
    };
  },
  methods: {
    performAction() {
      if (this.isMetaMaskInstalled()) {
        this.connectToMetamask();
      } else {
        // Redirect to metamask install page
        if (process.client) {
          window.open("https://metamask.io/");
        }
      }
    },
    //Check if MetaMask extension is installed
    isMetaMaskInstalled() {
      //Have to check the ethereum binding on the window object to see if it's installed
      if (process.client) {
        return Boolean(
          this.$store.getters["metamask/ethereum"] &&
            this.$store.getters["metamask/ethereum"].isMetaMask
        );
      }
      return false;
    },
    async checkIfUserRegistered(address) {
      const response = await this.$axios.$get("/users/" + address);
      // Handle response
      if (response === address) {
        return true;
      } else {
        return this.registerUser(address);
      }
    },
    async registerUser(address) {
      const response = await this.$axios.post("/users/register", {
        address: address,
      });
      console.log("Register user response: " + response);
    },
    handleSignMessage(publicAddress, nonce) {
      // Define instance of web3
      var web3 = new Web3(window.ethereum);
      return new Promise((resolve, reject) =>
        web3.eth.personal.sign(
          web3.utils.fromUtf8(`Nonce: ${nonce}`),
          publicAddress,
          (err, signature) => {
            if (err) return reject(err);
            return resolve({ publicAddress, signature });
          }
        )
      );
    },
    async connectToMetamask() {
      try {
        // Connect to metamask and get user accounts
        const accounts = await this.$store.getters["metamask/ethereum"].request(
          { method: "eth_requestAccounts" }
        );

        // Update vuex store
        this.$store.commit("metamask/setMetamaskConnected", true);
        this.$store.commit("metamask/setAccounts", accounts);
        // Check if user is registered, if not, register them
        //const isRegistered = await this.checkIfUserRegistered(accounts[0]);
        // Request nonce from backend
        const responseNonce = await this.$axios.get(
          "/users/" + accounts[0] + "/nonce"
        );
        const nonce = responseNonce.data;
        // Sign message
        const signedMessage = await this.handleSignMessage(accounts[0], nonce);
        // Send signature to backend
        const responseSign = await this.$axios.post(
          "/users/" + accounts[0] + "/signature",
          signedMessage
        );
        // Set token in store
        this.$store.commit("metamask/setToken", responseSign.data.token);
        // If successful, redirect to home
        if (responseSign.status === 200) {
          this.$router.push("/");
        }
      } catch (error) {
        console.log(error);
      }
    },
  },
};
</script>

And this is my views/HomeView.vue file (which is the view displayed in the screenshot):

<template>
  <div class="home">
    <MetamaskConnectWidget />
  </div>
</template>

<script>
// @ is an alias to /src
import MetamaskConnectWidget from "@/components/MetamaskConnectWidget.vue";

export default {
  name: "HomeView",
  components: {
    MetamaskConnectWidget,
  },
};
</script>

Why wont the button work?

@duartefdias
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment