网络知识 娱乐 Vue.js对接WalletConnect教程「Web3.0」

Vue.js对接WalletConnect教程「Web3.0」

在本文中,我们将使用 WalletConnect 将钱包应用链接到我们使用Vue.js开发的去中心化应用。

去中心化应用程序 (DApps) 的主要功能之一是能够连接钱包,这反过来又允许用户与 DApp 上的交易进行交互。它抽象了诸如交换网络、 提供签名者和其他为用户提供身份验证形式的功能等功能。连接钱包还充当网关,允许用户通过 DApp 使用他们的钱包地址作为授权身份在 区块链上进行和读取操作。

WalletConnect是一个免费的开源协议,可以将我们的 DApp 连接到多个钱包,包括MetaMask、Trust Wallet、Rainbow 等。 该协议通过在 DApp 和钱包之间建立连接来抽象这个过程,使它们在整个会话期间保持同步。

你可以在此处下载本教程的源代码,应用程序的演示请访问这里。



用熟悉的语言学习 Web3.0开发 : Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1、Vue.js 应用程序开发

首先,让我们使用 Vue CLI 启动项目。如果你的系统上已经安装了 Vue CLI,可以继续直接创建 Vue 项目。

可以使用以下命令全局安装它:

1

npm install -g @vue / cli

我们现在可以使用 Vue CLI 来创建我们的项目。使用以下命令创建一个新项目:

1

vue create vue-wallet-connect

你将需要选择一个预设。选择,然后选择如下所示的选项:Manually select features



创建项目后,导航到新的项目文件夹:

1

cd vue-wallet-connect

我们将在Vue 应用程序中使用Ethers.js在连接钱包时直接与区块链交互:

1

npm i ethers

在这里,我们将 WalletConnect 库安装到项目中:

1

npm install --save web3 @walletconnect/web3-provider

接下来,要直接在 Vue 3 中使用 WalletConnect 库,我们需要安装node-polyfill-webpack-plugin:

1

npm i node-polyfill-webpack-plugin

我们安装这个插件是因为项目使用 webpack v5,其中删除了 polyfill Node 核心模块。因此,需要安装它以访问项目中的这些模块。

现在,打开vue.config.js文件并将其替换为以下代码块:

12345678910111213

const { defineConfig } = require("@vue/cli-service");const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");module.exports = defineConfig({ transpileDependencies: true, configureWebpack: { plugins: [new NodePolyfillPlugin()], optimization: { splitChunks: { chunks: "all", }, }, },});

完成后,现在可以启动服务器:

1

npm run serve

2、构建用户界面

让我们进入 components 文件夹并创建一个名为StatusContainer.vue的文件, 该组件包含我们的主页。

这个文件包含了欢迎信息、帮助我们连接的Connect Wallet按钮以及用于断开我们与钱包的连接的Disconnect按钮。最后,当我们成功连接到钱包时, 会显示Connected按钮:

12345678910111213141516

<template> <div class="hello"> <h1>Welcome to Your Vue.js Dapp</h1> <div > <button class="button">Connected</button> <button class="disconnect__button">Disconnect</button> </div> <button class="button"> Connect Wallet</button> </div></template><script>export default { name: 'StatusContainer'}</script>

完成后,打开App.vue文件并导入StatusContainer组件,如下所示:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748

<template> <status-container/></template><script>import StatusContainer from './components/StatusContainer.vue'export default { name: 'App', components: { StatusContainer }}</script><style>@import url('https://fonts.googleapis.com/css2?family=Sora:wght@100&display=swap');#app { font-family: 'Sora', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px;}.button { background-color: #1c82ff; border: none; color: #ffffff; font-family: "Sora"; border-radius: 3rem; padding: 2rem 3rem; font-weight: 600; font-size: 2rem; margin: 1rem 1rem 1rem auto; width: 40%;}.disconnect__button { background-color: red; border: none; color: #ffffff; font-family: "Sora"; border-radius: 3rem; padding: 1rem 1.3rem; font-weight: 600; font-size: 1rem; margin: 8rem 1rem 1rem auto; width: 20%;}</style>

在样式标签中,现在为之前创建的按钮添加样式:.button.disconnect。 此外,我们从 Google Fonts 导入 Sora Custom Font 并在.__buttonfont-family样式中使用该字体。

3、实例化 WalletConnect

我们将需要一个 RPC 提供程序来实例化 WalletConnect 库。对于此示例,我们将使用Infura。 打开 Infura,创建一个新项目,然后获取项目 ID。



现在,在 src/walletConnect 文件夹下创建一个新文件夹walletConnect, 在这个文件夹中,让我们创建一个文件provider.js。在这里,我们导入WalletConnect 库,并使用 我们的 Infura ID 对其进行实例化,然后将其导出以用于其他文件。

src/walletConnect/provider.js看起来像这样:

1234

import WalletConnectProvider from "@walletconnect/web3-provider";export const provider = new WalletConnectProvider({ infuraId: process.env.VUE_APP_INFURA_ID,});

Infura ID 应当设置为环境变量。因此,将以下内容添加到你的.env文件中:

1

VUE_APP_INFURA_ID={{INFURA__ID}}

4、创建Composables

在创建接口并成功实例化我们的库之后,下一步是实现功能。为此,我们将使用 Vue composables,因为它允许我们在应用程序的任何组件中使用 我们的状态和操作,类似于Pinia和 Vuex。

在src文件夹内,添加src/composables/connect,在connect文件夹中,让我们创建一个index.js文件。

在这里,我们导入reactivewatch,我们将在这个文件中使用它。让我们创建状态对象defaultState

123456789

import { reactive, watch } from "vue";const defaultState = { address: "", chainId: "", status: false,};const state = defaultState

为了保持状态一致,我们将状态与本地存储中的项目同步。让我们命名这个条目为userState并将其分配给一个名为STATE_NAME 的变量。 这样做是为了避免userState在多个地方重复时出错:

1

const STATE_NAME = "userState";

我们使用watch来监听状态的任何变化,以便及时更新本地存储:

1234567

watch( () => state, () => { localStorage.setItem(STATE_NAME, JSON.stringify(state)); }, { deep: true });

接下来,我们创建一个getDefaultState函数来检查本地存储中的STATE_NAME项是否存在,并将本地存储项赋给状态。如果本地存储项不存在, 它会将defaultState赋给state

现在,我们可以删除const state = defaultState并使用reactive来赋值:

1234567

const getDefaultState = () => { if (localStorage.getItem(STATE_NAME) !== null) { return JSON.parse(localStorage.getItem(STATE_NAME)); } return defaultState;};const state = reactive(getDefaultState());

最后,我们导出状态。我们还添加了一条if语句来检查本地存储项是否不存在。如果没有,它会创建项目并分配state给本地存储:

12345678

export default () => { if (localStorage.getItem(STATE_NAME) === null) { localStorage.setItem(STATE_NAME, JSON.stringify(state)); } return { state, };};

现在,我们的状态总是与本地存储同步,确保一致性。

让我们看看src/composables/connect/index.js

1234567891011121314151617181920212223242526272829303132

import { reactive, watch } from "vue";const defaultState = { address: "", chainId: "", status: false,};const STATE_NAME = "userState";const getDefaultState = () => { if (localStorage.getItem(STATE_NAME) !== null) { return JSON.parse(localStorage.getItem(STATE_NAME)); } return defaultState;};const state = reactive(getDefaultState());watch( () => state, () => { localStorage.setItem(STATE_NAME, JSON.stringify(state)); }, { deep: true });export default () => { if (localStorage.getItem(STATE_NAME) === null) { localStorage.setItem(STATE_NAME, JSON.stringify(state)); } return { state, };};

5、创建Actions

Actions由将在程序中使用的功能组成。我们将创建三个函数:

  • connectWalletConnect,这会触发 WalletConnect 与钱包连接
  • autoConnect,它在 DApp 连接后处理我们 WalletConnect 会话中的一致性,因此当 DApp 连接并且刷新页面后,用户的会话仍然处于活动状态
  • disconnectWallet,这会断开 DApp 与钱包的连接并结束用户的会话

让我们直接进入代码!

仍在我们的src/composables/connect文件夹中,创建connectWalletConnect文件。首先,我们导入index文件等:

1234567891011121314151617181920212223242526272829303132333435363738

import { providers } from "ethers";import connect from "./index";import { provider } from "../../walletConnect/provider";const connectWalletConnect = async () => { try { const { state } = connect(); // Enable session (triggers QR Code modal) await provider.enable(); const web3Provider = new providers.Web3Provider(provider); const signer = await web3Provider.getSigner(); const address = await signer.getAddress(); state.status = true; state.address = address; state.chainId = await provider.request({ method: "eth_chainId" }); provider.on("disconnect", (code, reason) => { console.log(code, reason); console.log("disconnected"); state.status = false; state.address = ""; localStorage.removeItem("userState"); }); provider.on("accountsChanged", (accounts) => { if (accounts.length > 0) { state.address = accounts[0]; } }); provider.on("chainChanged", (chainId) => { state.chainId = chainId }); } catch (error) { console.log(error); }};export default connectWalletConnect;

然后我们用provider监听三个事件: disconnect、accountsChanged和chainChainged。

  • disconnect:一旦用户直接从他们的钱包断开连接就会触发
  • accountsChanged:如果用户在其钱包中切换帐户,则会触发。如果account数组的长度大于零,我们将state.address设置为数组第一个地址,也就是当前地址
  • chainChainged:如果用户切换其链/网络,则会触发。例如,如果从以太坊主网切换到 rinkeby 测试网,我们的应用程序会将state.chainId从1更改为4。

然后,我们的catch语句只是将任何错误记录到控制台。

返回到connect文件夹中的index.js文件并导入connectWalletConnect动作。在这里,我们创建一个actions对象并使用state导出:

1234567891011121314151617181920212223242526272829303132333435

import { reactive, watch } from "vue";import connectWalletConnect from "./connectWalletConnect";const STATE_NAME = "userState";const defaultState = { address: "", chainId: "", status: false,};const getDefaultState = () => { if (localStorage.getItem(STATE_NAME) !== null) { return JSON.parse(localStorage.getItem(STATE_NAME)); } return defaultState;};const state = reactive(getDefaultState());const actions = { connectWalletConnect,};watch( () => state, () => { localStorage.setItem(STATE_NAME, JSON.stringify(state)); }, { deep: true });export default () => { if (localStorage.getItem(STATE_NAME) === null) { localStorage.setItem(STATE_NAME, JSON.stringify(state)); } return { state, ...actions, };};

6、实现组件逻辑

让我们打开StatusContainer组件并将composables中的逻辑连接到接口。像往常一样,导入文件并对其进行解构以获取动作和状态:

123456789101112131415161718192021

<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>

然后返回函数 ( disconnectUser, connectUserWallet) 和state以便在模板中使用:

12345678910111213

<template> <div class="hello"> <h1>Welcome to Your Vue.js Dapp</h1> <div v-if="state.status"> <button @click="connectUserWallet" class="button">Connected</button> <h3>Address: {{state.address}}</h3> <h3>ChainId: {{state.chainId}}</h3> <button @click="disconnectUser" class="disconnect__button">Disconnect</button> </div> <button v-else @click="connectUserWallet" class="button"> Connect Wallet</button> </div></template>

首先,我们用v-if来有条件地显示事物,使用state.status。 如果已连接并且state.status为真, 我们将显示Connected按钮、用户addresschainId。此外,我们将显示一个触发disconnectUser功能的断开连接按钮。



如果用户没有连接并且state.statusfalse,我们只显示触发connectUserWallet功能的连接钱包按钮。



7、结束语

在本文中,我们介绍了在 Vue DApp 中集成 WalletConnect 的详细步骤。内容涵盖项目配置、界面构建、逻辑编写、状态同步 等环节,以确保我们的应用程序始终与钱包同步。


原文链接:http://blog.hubwiz.com/2022/08/14/vue-walletconnect-integration/