8

Vue.js对接WalletConnect教程

 1 year ago
source link: http://blog.hubwiz.com/2022/08/14/vue-walletconnect-integration/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Vue.js对接WalletConnect教程

2022-08-14

| 区块链

区块链开发课程精选

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

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

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

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

cover.avif

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

1、Vue.js 应用程序开发

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

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

npm install -g @vue / cli

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

vue create vue-wallet-connect

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

Vue WalletConnect整合

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

cd vue-wallet-connect

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

npm i ethers

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

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

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

npm i node-polyfill-webpack-plugin

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

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

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",
},
},
},
});

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

npm run serve

2、构建用户界面

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

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

<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组件,如下所示:

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

Vue WalletConnect整合

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

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

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

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

VUE_APP_INFURA_ID={{INFURA__ID}}

4、创建Composables

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

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

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

import { reactive, watch } from "vue";

const defaultState = {
address: "",
chainId: "",
status: false,
};

const state = defaultState

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

const STATE_NAME = "userState";

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

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

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

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

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

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

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

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

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

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文件等:

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导出:

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中的逻辑连接到接口。像往常一样,导入文件并对其进行解构以获取动作和状态:

<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以便在模板中使用:

<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功能的断开连接按钮。

Vue WalletConnect整合

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

Vue WalletConnect整合

7、结束语

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


原文链接:Integrating WalletConnect into Vue.js DApps

汇智网翻译整理,转载请标明出处


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK