web3实战课01:链接你的钱包

📖阅读本文,你将

  1. 获取一个 demo 仓库。
  2. 从思路上理清 【链接钱包】 这件事的思路。
  3. 认识 EIP-1193 协议。
  4. 认识 EIP-6963 协议。
  5. 认识 WalletConnect 相关平台和能力。
  6. 学会 wagmi 的基本使用。

01、web3世界里,钱包(Wallet)是最重要的

在web3的领域,钱包就是身份证 + 账号密码 + 验证码等一切。

web3的钱包记录着你的以下几个关键内容:

  • 你的私钥 private-key.
  • 你的钱包地址 wallet-address.

你可通过使用钱包,对任何请求进行签名和响应授权、交易等行为,以此证明"你就是你"。

可以说,web3的钱包不仅仅是你的身份证,更是你的通行证和令牌。

因此,在 web3 中链接钱包,就像 web2 中"使用账号密码登录"一样常见,作为"实战开发"的第一课,恰如其份。

首先,你需要准备一个 web3 钱包,这属于入门基础,你可以先去任何别的文章先了解一二,至少能拥有一个 web3 钱包,可以是浏览器插件,也可以是手机上的钱包APP。

为了和主流技术不脱节,本文将采用 web3 圈最主流的技术进行实现。

  • 前端框架:react + next.js
  • 前端请求状态库:react-query
  • React Hooks库 :wagmi
  • 手机钱包链接平台:cloud.walletconnect.com

02、基本架构和生态位

当我们学东西时,最初的疑问可能并不是"这个工具怎么用",而是:这是个什么库?我为什么要用它?它在工具链里处于什么位置?有哪些平替?

我大概按自己的理解,给目前 web3 主流库划分了一个分层。(当然,保不齐可能有错的,欢迎指正,我也是初学者)。

  • connector:钱包链接库,主要提供钱包链接相关能力。
  • 能力抽象和封装:对常见 web3 能力进行了封装抽象,让大家能更轻易地进行常规web3 操作。
  • React 封装:对常见能力,进行针对 React 的更一步封装,状态化、Hook化。
  • UI 库:这一层在 web3 领域被推荐的几乎只有 React
  • React 集成框架: 这一层几乎只有 next.js

可能有人会问,为什么 UI 层没有 vue,我只能说按我目前的观察,在 web3 领域,React + Next.js 几乎是唯一的选择。当然你可以说 "React能做到的,Vue都能做到。",话虽如此,但生态就是这样,没有什么好争论的。

03、先理清思路,如何链接浏览器拓展?

假设一下,如果你现在是一个架构师,你需要负责设计一个网站,外加一个 Chrome 浏览器拓展。当你在页面上点击一个按钮之后,拓展就会被唤醒,然后当用户进行一系列操作之后,拓展会返回一些信息给页面。

你会怎么设计?

常规思路,无外乎:

  1. 找到常规的 HTML 页面和 Chrome 浏览器拓展通信的方式,约定好通信协议,啥时候算唤起,啥时候算关闭,啥时候返回什么内容算结束。
  2. 编写拓展,按照协议进行通信。

问题来了,如果此时,有很多其他网站的开发者,也希望接入你的拓展。那么他们就得按你设计的协议来进行通信。

然后,有另外的开发商开发了和你同样能力的拓展,也希望无成本地给所有网站接入。他们也得遵从你的协议来。

对,这里的 HTML 就是所有需要链接钱包的 DAPP,这里的 Chrome 浏览器拓展就是所有安装在浏览器上的 web3 钱包。

为了应对茫茫多的钱包和页面复用的问题,大家都需要一个标准。

于是,有了 EIP-1193 标准。

3.1 什么是 EIP-1193

如果你想让你的浏览器拓展和页面进行通信,那么你需要遵循 EIP-1193 协议。

EIP-1193 协议,是 Ethereum 社区提出的浏览器拓展和页面通信协议,它是 web3 生态中最基础的协议。

3.2 EIP-1193 提供了哪些标准?

EIP(Ethereum Improvement Proposal) 的简称。1193 是 EIP-1193 的编号。

EIP-1193 最大的特点是,它希望钱包可以将其 provider 对象暴露给页面,然后页面就可以通过这个 provider 对象进行交互。

而暴露给provider的方式,就是将其注入到 window.ethereum 对象中。

因此,只要你的电脑装了任何一个号称支持 EIP-1193web3 钱包,那么你就能在任何一个页面的控制台里,发现这个 window.ethereum 对象。

看到了上面的对象了吗?其中属于 EIP-1193 协议标准的只有 request 函数。其他都是各种钱包携带的私货。

那么 EIP-1193 标准协议,究竟应该如何连接钱包呢?

尝试在任何网页,打开控制台,输入以下代码:

javascript 复制代码
await window.ethereum.request({
  method: 'eth_requestAccounts',
})

只要你的浏览器里有任何支持 EIP-1193web3 钱包,你就能看到以下结果:

ok, 这就是 EIP-1193 标准协议的连接方式。

但是等等,你有没有发现 EIP-1193 缺失了一些重要的内容?

比如:

  • 我不能知道控制我要调用的 provider 具体指向哪个钱包,这完全依赖于浏览器拓展的加载顺序。
  • 我更无法清晰了解到我有哪几个钱包可用,以及它们的基本信息。

为了应对这个问题,EIP-6963 协议应运而生。

3.3 EIP-6963 解决了什么问题?

EIP-6963 正是为了解决 EIP-1193 协议的缺陷而提出的。

它定义了一组 window event,让钱包可以和页面进行双向通信。

比如,当钱包监听到页面的 eip6963:requestProvider 事件后,就可以将自己的 provider 和元信息返回给页面。

这样一来,页面就可以知道有哪些钱包可用,以及它们的基本信息。

理解到这里就够了,目前使用浏览器拓展的 web3 钱包,基本都是基于 EIP-6963 标准或者 EIP-1193 标准。

04、如何链接手机钱包?

Web 端登录,却希望手机客户端来验证授权,最常见的方式是什么?

扫码登录。

思考一下,你会怎么设计?

ok,现在你需要一个额外的服务用来生成二维码,并且提供可供用户手机访问的链接,完成认证后再通知你的 web 浏览器,从而完成交互。

WalletConnect 云服务,就是这样的一个中心化网站,它提供便捷的 web3 钱包链接 Saas 服务。

有了它,你可以省下一台自己的服务器,并且省去写那些繁琐的代码。

访问:cloud.walletconnect.com/ 注册一个账号。

不用担心,注册非常简单。你甚至可以用你刚刚生成的钱包地址就能完成注册。

然后去创建一个 Project

其他信息随便写写就行,关键是要获取这个 ProjectId。它会在你的 DApp 中用到。

记住你的 ProjectId

05、基于 Next.js 搭建项目

使用以下命令,就可以快速创建一个 Next.js 项目:

shell 复制代码
npx create-next-app@latest

然后 cd 到你的项目目录,执行以下命令:

shell 复制代码
# npm yarn 都一样
pnpm install @tanstack/react-query@latest antd@5.x viem@2.x wagmi@2.x

至于 demo 具体的代码,我放在了这个仓库里:

github.com/zhangshichu...

并且通过 vercel 部署了一个可以直接线上访问的 demo

wagmi-demos.vercel.app/01-wallet-c...

(当然,可能需要一些科学和魔法)

下面,我会对本节涉及到的 demo 难点进行逐一讲解。

05、Next.js 中提供 Provider

众所周知,Next.js 默认的页面配置是 SSR 的。初学者如果不熟悉的话,在给 wagmi 配置 Provider 时,可能会遇到一些问题。

例如: 我们按照 wagmi 的教程,一开始就需要配置如下一套 React Provider 供后续的 Hooks 消费:

jsx 复制代码
<WagmiProvider config={config}>
  <QueryClientProvider client={queryClient}>
    {children}
  </QueryClientProvider>
</WagmiProvider>

但是最新版本 Next.jsapp/layout.jsx 文件默认是 use Server 的,而 Provider 等能力因为是运行在 client 端,所以需要 use Client

app/layout.jsx 中,我们往往要编写一些不适合 client 端运行的代码,比如配置 meta 等。

这就产生了一个矛盾:如何在 app/layout.jsx 中,同时使用 ServerClient 呢?

Next.js 官方给出了解决方案:你可以另外创建一个 app/wallet-provider.jsx 文件,专门用来提供 Provider。在这个文件中你可以大胆地使用 use client

并在 app/layout.jsx 中,import 进来,然后使用即可。

jsx 复制代码
import WalletProvider from "./wallet-provider";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <WalletProvider>{children}</WalletProvider>
      </body>
    </html>
  );
}

以上代码建议参考这三个文件:

@/configs/wallet.ts

@/app/layout.tsx

@/app/wallet-provider.tsx

06、如何从 connectors 中区分不同的方式?

wagmi 提供了 useConnect 这个 Hook,可以用来获取当前可用的 connectors

但你仍然需要从中分辨出这些 connector 本来的面目:

主要有三类:

  • 第一类,connector.id === "walletConnect" 的,这一类是 @walletconnect/ethereum-provider 库提供的,通过它,你可以便捷地使用手机扫码登录钱包。
  • 第二类,connector.id === "injected" 的,这一类是 EIP-1193 协议提供的,在你的多个插件争夺 window.ethereum 对象中,获得胜利的那个钱包提供的能力。
  • 第三类,其他的,这一类是 EIP-6963 协议提供的,你可以获取到具体的拓展名称和 icon,链接到具体的钱包。

关于我

我是春哥,一个前端工程师。

目前正在学习 web3 领域。

如果你有任何问题,欢迎留言。

相关推荐
学习使我快乐0120 分钟前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio199521 分钟前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈1 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水2 小时前
简洁之道 - React Hook Form
前端
正小安4 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch6 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光6 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   6 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   6 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web6 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery