Integrating a wallet connection is a core feature of any decentralized application (DApp). It allows users to interact with blockchain transactions, switch networks, and use their wallet address as a form of authentication. This connection acts as a gateway, enabling users to perform actions like sending transactions or reading data from the blockchain directly through your DApp.
WalletConnect is an open-source protocol that simplifies connecting DApps to various crypto wallets, including MetaMask, Trust Wallet, and Rainbow. It establishes a secure connection between your application and the user's wallet, keeping them synchronized throughout the session.
In this guide, you’ll learn how to integrate WalletConnect into a Vue.js DApp. You’ll set up the project, build the user interface, and implement essential functionalities like connecting, auto-reconnecting, and disconnecting wallets.
Prerequisites and Setup
Before you begin, ensure you have Node.js and npm installed on your system. You’ll also need a basic understanding of Vue.js and Ethereum development concepts.
Start by installing the Vue CLI globally if you haven’t already:
npm install -g @vue/cliCreate a new Vue project using the following command:
vue create vue-wallet-connectSelect Manually select features and choose options suitable for a Vue 3 project (like Babel and Vuex if needed). Once the project is created, navigate into the directory:
cd vue-wallet-connectInstall the required dependencies:
npm i ethers web3 @walletconnect/web3-provider node-polyfill-webpack-pluginEthers.js will help interact with the blockchain, while the WalletConnect provider enables wallet connectivity. The polyfill plugin ensures compatibility with webpack 5.
Update vue.config.js to include the polyfill plugin:
const { defineConfig } = require("@vue/cli/service");
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
plugins: [new NodePolyfillPlugin()],
},
});Now, start the development server:
npm run serveBuilding the User Interface
Create a new component StatusContainer.vue in the components folder. This component will display connection status and action buttons:
<template>
<div>
<h1>Welcome to Your Vue.js Dapp</h1>
<div v-if="state.status">
<button class="connected">Connected</button>
<p>Address: {{ state.address }}</p>
<p>ChainId: {{ state.chainId }}</p>
<button class="disconnect__button" @click="disconnectUser">
Disconnect
</button>
</div>
<button v-else class="button" @click="connectUserWallet">
Connect Wallet
</button>
</div>
</template>
<script>
import connect from '../composables/connect/index';
export default {
name: 'StatusContainer',
setup() {
const { connectWalletConnect, disconnectWallet, state } = connect();
const connectUserWallet = async () => {
await connectWalletConnect();
};
const disconnectUser = async () => {
await disconnectWallet();
};
return {
connectUserWallet,
disconnectUser,
state
};
}
}
</script>In App.vue, import and use this component:
<template>
<div id="app">
<StatusContainer />
</div>
</template>
<script>
import StatusContainer from './components/StatusContainer.vue';
import connect from './composables/connect/index';
import { onMounted } from 'vue';
export default {
name: 'App',
components: {
StatusContainer
},
setup() {
const { autoConnect } = connect();
onMounted(async () => {
await autoConnect();
});
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Sora:wght@100&display=swap');
#app {
font-family: 'Sora', sans-serif;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.button {
background-color: #1c82ff;
color: #ffffff;
border-radius: 3rem;
padding: 2rem 3rem;
font-weight: 600;
font-size: 2rem;
width: 40%;
border: none;
}
.disconnect__button {
background-color: red;
color: #ffffff;
border-radius: 3rem;
padding: 1rem 1.3rem;
font-weight: 600;
font-size: 1rem;
width: 20%;
border: none;
}
</style>The UI includes conditional rendering to show connection details or a connect button based on the wallet state.
Configuring WalletConnect
To use WalletConnect, you need an RPC provider. Infura is a popular choice. Sign up for an account, create a new project, and note the Project ID.
Create a walletConnect folder under src, and inside it, a provider.js file:
import WalletConnectProvider from "@walletconnect/web3-provider";
export const provider = new WalletConnectProvider({
infuraId: process.env.VUE_APP_INFURA_ID,
});Add your Infura ID to a .env file:
VUE_APP_INFURA_ID=your_infura_project_idManaging State with Composables
Composables help manage state and actions across components. Create a composables/connect folder and an index.js file:
import { reactive, watch } from "vue";
import connectWalletConnect from "./connectWalletConnect";
import autoConnect from "./autoConnect";
import disconnectWallet from "./disconnectWallet";
const STATE_NAME = "userState";
const defaultState = {
address: "",
chainId: "",
status: false,
};
const getDefaultState = () => {
const storedState = localStorage.getItem(STATE_NAME);
return storedState ? JSON.parse(storedState) : defaultState;
};
const state = reactive(getDefaultState());
watch(
() => state,
(newState) => {
localStorage.setItem(STATE_NAME, JSON.stringify(newState));
},
{ deep: true }
);
const actions = {
connectWalletConnect,
autoConnect,
disconnectWallet
};
export default () => {
if (!localStorage.getItem(STATE_NAME)) {
localStorage.setItem(STATE_NAME, JSON.stringify(state));
}
return {
state,
...actions
};
};This composable manages the user’s wallet state and synchronizes it with local storage.
Implementing Connection Actions
connectWalletConnect
Create connectWalletConnect.js:
import { providers } from "ethers";
import { provider } from "../../walletConnect/provider";
import connect from "./index";
const connectWalletConnect = async () => {
try {
const { state } = connect();
await provider.enable();
const web3Provider = new providers.Web3Provider(provider);
const signer = web3Provider.getSigner();
const address = await signer.getAddress();
state.status = true;
state.address = address;
state.chainId = await provider.request({ method: "eth_chainId" });
provider.on("disconnect", () => {
state.status = false;
state.address = "";
localStorage.removeItem("userState");
});
provider.on("accountsChanged", (accounts) => {
if (accounts.length) {
state.address = accounts[0];
}
});
provider.on("chainChanged", (chainId) => {
state.chainId = chainId;
});
} catch (error) {
console.error("Connection error:", error);
}
};
export default connectWalletConnect;This function triggers the WalletConnect modal, handles the connection, and sets up event listeners for changes.
autoConnect
Create autoConnect.js:
import connect from "./index";
const autoConnect = () => {
const { state, connectWalletConnect } = connect();
if (state.status) {
if (!localStorage.getItem("walletconnect")) {
state.status = false;
state.address = "";
localStorage.removeItem("userState");
} else {
connectWalletConnect();
}
}
};
export default autoConnect;This action checks for an existing session and reconnects automatically if possible.
disconnectWallet
Create disconnectWallet.js:
import { provider } from "../../walletConnect/provider";
import connect from "./index";
const disconnectWallet = async () => {
const { state } = connect();
await provider.disconnect();
state.status = false;
state.address = "";
localStorage.removeItem("userState");
};
export default disconnectWallet;This function disconnects the wallet and clears the state.
Enhancing User Experience
To make your DApp more robust, consider handling network changes gracefully and providing user feedback during transactions. Use toast notifications or loading indicators to improve interactivity.
👉 Explore more strategies for DApp development
Frequently Asked Questions
What is WalletConnect?
WalletConnect is an open-source protocol that enables secure connections between DApps and mobile crypto wallets. It supports multiple wallets and chains, providing a streamlined user experience without compromising security.
Why use composables in Vue for state management?
Composables offer a flexible way to reuse state and logic across components. They are lightweight and integrate well with Vue 3’s reactivity system, making them ideal for managing DApp state and wallet connections.
How does auto-reconnect work?
Auto-reconnect checks for existing WalletConnect sessions in local storage. If a session is found, it automatically re-establishes the connection, ensuring users remain logged in even after refreshing the page.
Can I use WalletConnect with other frameworks?
Yes, WalletConnect is framework-agnostic. You can integrate it with React, Angular, or any other JavaScript framework following similar patterns.
What RPC providers can I use?
Besides Infura, you can use Alchemy, QuickNode, or your own Ethereum node. Ensure the provider supports the networks your DApp targets.
How do I handle errors during connection?
Implement try-catch blocks around connection logic and provide user-friendly error messages. Common issues include network mismatches or user rejection of connection requests.
Conclusion
Integrating WalletConnect into your Vue.js DApp enhances usability by allowing users to connect their preferred wallets securely. By following this guide, you’ve learned how to set up the project, build a dynamic UI, manage state with composables, and implement essential wallet functions.
Remember to test your DApp thoroughly across different wallets and networks. Keep your dependencies updated and follow best practices for security and user experience.
👉 Get advanced methods for blockchain development
Happy building!