使用 React+ethers.js 开发简单加密钱包(一)

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 使用 React+ethers.js 开发简单加密钱包

最近在开发一个 NFT 二创平台,其中包含了很多概念和技术。我会更新一个系列的文章来总结和沉淀在这个过程中的一些知识与思考。

本文是对 ethers.js 进行一个全方位介绍,非常适合 web3 入门学习。


什么是 ethers.js?


Web3 中的各类 DApp,都需要与智能合约进行交互。如果用原生 JS 来做这些事会很麻烦。这时就需要使用专属的 SDK。

目前 JS 环境中有两个主流的库可以用来和智能合约进行交互,一个是 web3.js,另一个是 ethers.js。


ethers.js VS web3.js


web3.js 比 ethers.js 出现的更早。但是目前 ethers.js 更受欢迎。

主要原因有如下两点:

  1. 体积:ethers.js 体积仅有 116.5kb,web3.js 有 590.6kb。相差 5 倍左右。
  2. 设计理念:由于设计理念不同。web3.js 认为用户会在本地部署以太坊节点,私钥和网络连接状态由这个节点管理。但实际上大部分人都不会在本地部署以太坊节点。ethers.js 充分考虑了这一点,它是用 Provider 管理网络连接状态,用 Wallet 管理密钥,更加安全和灵活。而且原生支持 ENS。

ethers.js 基本使用介绍


节点即服务


由于在本地部署一个区块链节点的成本并不低,很少会有人真的部署一个节点,而是选择使用节点即服务。

这类服务有很多,比如老牌的 Alchemy、Infura、Moralis 以及今年估值 102 亿美金的新秀 Tenderly。

在这里我们选择 Alchemy,目前它的市场占有率是最高的。

alchemy 的网址在这:dashboard.alchemy.com/。具体的注册登陆就不讲了。

登陆之后我们创建一个 App。

image.png

Chain 选择 Ethereum,Network 选择 Goerli。

image.png

这样就成功创建了一个 App,点击后面的 view key,就可以查看 key。

image.png

我们把它复制下来,后面会用到。

image.png


构造合约


在对合约进行读取或交互之前,我们首先需要构造一个合约对象。

合约对象有三个构造参数,第一个是合约地址,是一个字符串。第二个是合约的 abi,可以是一个 JSON,第三个参数是 provider 对象,它用于管理网络连接状态。

下面的例子中就是使用 alchemy 提供的 JSON RPC 接口作为网络连接。


const rpc = `https://eth-goerli.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_API_KEY}`;
const provider = new ethers.providers.JsonRpcProvider(rpc);
const contract = new ethers.Contract(contractAddress, abi, provider)

除了 JsonRpcProvider 以外,ethers 还有 IpcProvider、InfuraProvider、AlchemyProvider、Web3Provider 等多种 Provider。


读取合约信息


abi 中的方法会直接挂载到 contract 对象上,我们可以直接调用。

不过需要注意,所有的操作都是异步的。


(async () => {
  const owner = await contract.owner();
  console.log(owner);
})();


连接钱包


由于和合约交互需要支付 gas 费用,所以必须有一个数字钱包。

钱包有很多种,比如 MetaMask、Rainbow、Coinbase Wallet 等。其中 MetaMask 是最常用的一种数字钱包。

这里主要介绍如何连接到 MetaMask。

MetaMask 有一个浏览器插件,如果用户安装了该插件,在 window 对象下会有一个 ethereum 对象。我们可以调用 ethereum.request 方法发起请求,参数是一个对象,对象的 method 描述该次请求的操作。

ethereum.request 方法是异步的,会返回一个数组,该数组是所有登陆钱包的账户地址字符串,第一个账户就是当前激活的账户。如果返回的数组长度为 0,则意味着没有登陆任何账户。


(async ()=> {
  const accounts = await ethereum.request({ method: 'eth_requestAccounts' })
  if(accounts.length === 0) {
    throw Error('未登录任何账户')
  }
  const activeAccount = accounts[0]
  console.log(activeAccount)
})()

我们还可以通过 ethereum.request 方法获取当前的网络状态。


(async ()=> {
  const chainId = await ethereum.request({ method: 'eth_chainId' })
  console.log(chainId)
})()

它会返回一个字符串。0x1 表示以太网主网;0x5 表示 Goerli 测试网,更多网络的 chainId 可以在这个网站查看:chainlist.org/

下面是使用 ethers.js 来连接 MetaMask 的代码。


(async ()=> {
  const provider = new ethers.providers.Web3Provider(window.ethereum)
  const accounts = await provider.send("eth_requestAccounts", [])
  const activeAccount = accounts[0]
})()

如果使用 MetaMask 作为 provider,那么就不需要再使用 alchemy 了。


钱包


在转账交易之前,我们需要创建一个 Wallet 实例,它的作用是对交易和消息进行签名。

创建 Wallet 对象的方法有三种。

通过 Wallet.createRandom 创建随机钱包

这种方式创建的是一个单机钱包,需要连接网络。


const wallet = ethers.Wallet.createRandom()
wallet.connect(provider)

通过助记词创建


const wallet = new ethers.Wallet.fromMnemonic(mnenonic.phrase)

通过私钥和 provider 创建


const wallet = new ethers.Wallet(privateKey, provider)


钱包信息


我们可以在创建好的钱包上面获取很多有用的信息,比如钱包地址、助记词、私钥、交易次数等。


console.log(wallet.address)
console.log(await wallet.getAddress())
console.log(wallet.mnemonic)
console.log(wallet.privateKey)
console.log(wallet.getTransactionCount())


转账


一旦又了钱包,我们就可以向其他人发起转账交易。

创建一个 tx 对象,它最少需要两个属性,to 和 value,分别表示接受钱包地址和转账额度。

然后使用 wallet.sendTransaction 方法发送转账,它会返回一个 receipt 对象。这个对象有一个异步的 wait 方法,当交易上链后会返回。


const tx = {
  to: address,
  value: ethers.utils.parseEther("0.1"),
}
console.log('开始转账')
const receipt = await wallet.sendTransaction(tx)
await receipt.wait()
console.log('完成转账')


通过合约转账交易


交易需要使用 Wallet 对象。再通过 wallet 作为合约的第三个构造参数创建 Contract 对象。

调用合约的 transfer 方法,进行转账交易。该方法需要两个参数,转入的钱包地址字符串和转入的数量。

transfer 会返回一个 tx 对象,该对象有一个异步的 wait 方法,会在交易完成后执行。


const wallet = new ethers.Wallet(privateKey, provider)
const contract = new ethers.Contract(contractAddress, abi, wallet)
(async ()=> {
  const tx = await contract.transfer(toAddress, ethers.utils.parseEther("1"))
  await tx.wait()
})()


通过 signer 进行转账


通常我们无法直接拿到 privateKey,但是可以通过 signer 对象间接使用 privateKey。只需要进行签名就可以进行交易。这也是最常用的交易方式。


const signer = walletProvider.getSigner();
const tx = {
  to,
  value,
};
const receipt = await signer.sendTransaction(tx);
await receipt.wait();


使用 React 和 ethers.js 开发加密钱包


接下来我们开发一个最简单的加密钱包,具备最基础的转账功能和查询余额功能。


创建项目


我们首先创建一个 Next.js 项目。


npx create-next-app

需要选择 TypeScript。


安装依赖


安装 ethers.js


npm i ethers


安装 tailwindcss


npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

修改 tailwind.cinfig.js。


/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

修改 styles/globals.css。


@tailwind base;
@tailwind components;
@tailwind utilities;


安装 headless-ui


npm install @headlessui/react

相关文章
|
19天前
|
Web App开发 JavaScript 前端开发
Node.js开发
Node.js开发
33 13
|
25天前
|
存储 JavaScript 前端开发
深入浅出Node.js后端开发
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将以Node.js为例,深入探讨其背后的哲学思想、核心特性以及在实际项目中的应用,旨在为读者揭示Node.js如何优雅地处理高并发请求,并通过实践案例加深理解。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和思考。
|
22天前
|
Web App开发 开发框架 JavaScript
深入浅出Node.js后端开发
本文将带你领略Node.js的魅力,从基础概念到实践应用,一步步深入理解并掌握Node.js在后端开发中的运用。我们将通过实例学习如何搭建一个基本的Web服务,探讨Node.js的事件驱动和非阻塞I/O模型,以及如何利用其强大的生态系统进行高效的后端开发。无论你是前端开发者还是后端新手,这篇文章都会为你打开一扇通往全栈开发的大门。
|
25天前
|
Web App开发 开发框架 JavaScript
深入浅出Node.js后端开发
在这篇文章中,我们将一起探索Node.js的奇妙世界。无论你是刚接触后端开发的新手,还是希望深化理解的老手,这篇文章都适合你。我们将从基础概念开始,逐步深入到实际应用,最后通过一个代码示例来巩固所学知识。让我们一起开启这段旅程吧!
|
21天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
本文将带领读者从零基础开始,一步步深入到Node.js后端开发的精髓。我们将通过通俗易懂的语言和实际代码示例,探索Node.js的强大功能及其在现代Web开发中的应用。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的见解和技巧,让你的后端开发技能更上一层楼。
|
25天前
|
JavaScript 前端开发 API
深入理解Node.js事件循环及其在后端开发中的应用
本文旨在揭示Node.js的核心特性之一——事件循环,并探讨其对后端开发实践的深远影响。通过剖析事件循环的工作原理和关键组件,我们不仅能够更好地理解Node.js的非阻塞I/O模型,还能学会如何优化我们的后端应用以提高性能和响应能力。文章将结合实例分析事件循环在处理大量并发请求时的优势,以及如何避免常见的编程陷阱,从而为读者提供从理论到实践的全面指导。
|
26天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
本文将带你走进Node.js的世界,从基础到进阶,逐步解析Node.js在后端开发中的应用。我们将通过实例来理解Node.js的异步特性、事件驱动模型以及如何利用它处理高并发请求。此外,文章还会介绍如何搭建一个基本的Node.js服务器,并探讨如何利用现代前端框架与Node.js进行交互,实现全栈式开发。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
19 4
|
1月前
|
前端开发 JavaScript 开发者
颠覆传统:React框架如何引领前端开发的革命性变革
【10月更文挑战第32天】本文以问答形式探讨了React框架的特性和应用。React是一款由Facebook推出的JavaScript库,以其虚拟DOM机制和组件化设计,成为构建高性能单页面应用的理想选择。文章介绍了如何开始一个React项目、组件化思想的体现、性能优化方法、表单处理及路由实现等内容,帮助开发者更好地理解和使用React。
77 9
|
2月前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
|
27天前
|
监控 前端开发 数据可视化
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
@icraft/player-react 是 iCraft Editor 推出的 React 组件库,旨在简化3D数字孪生场景的前端集成。它支持零配置快速接入、自定义插件、丰富的事件和方法、动画控制及实时数据接入,帮助开发者轻松实现3D场景与React项目的无缝融合。
101 8
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生