Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >web3钱包接入之viem

web3钱包接入之viem

作者头像
Maic
发布于 2025-02-12 06:11:37
发布于 2025-02-12 06:11:37
17500
代码可运行
举报
文章被收录于专栏:Web技术学苑Web技术学苑
运行总次数:0
代码可运行

过去一年,接入了很多第三方钱包,有solana,rainbow,web3Modal【现在是reown】了、aptos相关区块链钱包,第三方钱包接入已经相对非常成熟,API通常来讲非常简易,基本不用考虑更底层的API,常用的hook也会更高效,但通常接入钱包过程中,似乎总有种,知其然而不知所以然的感觉,本文是一篇钱包偏底层的接入流程。

本文主要以evm钱包为例子

首先我们要初步了解viem,我们在项目中,你也许会看到大量的wagmi,实际上这是对viem更上层的封装,wagmi是以太坊交互官方封装便捷好用的react库,让你非常快捷方便的与钱包以及以太坊交互,但本质上所有与以太坊交互的hook依赖于viem

在开始本文之前,你的浏览器得提前安装一个metaMask插件钱包

查看区块block

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
// test.js
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
const client = createPublicClient({
  chain: mainnet,
  transport: http(),
});
console.log(client);
const getBlock = async () => {
  const blockNumber = await client.getBlockNumber();
  console.log(blockNumber);
};
getBlock();

当我们运行node test.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
{
  account: undefined,
  batch: undefined,
  cacheTime: 4000,
  ccipRead: undefined,
  chain: {
    formatters: undefined,
    fees: undefined,
    serializers: undefined,
    id: 1,
    name: 'Ethereum',
    nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
    rpcUrls: { default: [Object] },
    blockExplorers: { default: [Object] },
    contracts: {
      ensRegistry: [Object],
      ensUniversalResolver: [Object],
      multicall3: [Object]
    }
  },
  key: 'public',
  name: 'Public Client',
  pollingInterval: 4000,
  request: [AsyncFunction (anonymous)],
  transport: {
    key: 'http',
    name: 'HTTP JSON-RPC',
    request: [AsyncFunction: request],
    retryCount: 3,
    retryDelay: 150,
    timeout: 10000,
    type: 'http',
    fetchOptions: undefined,
    url: 'https://cloudflare-eth.com'
  },
  type: 'publicClient',
  uid: '2523e6fdcf6',
  extend: [Function (anonymous)],
  call: [Function: call],
  createBlockFilter: [Function: createBlockFilter],
  createContractEventFilter: [Function: createContractEventFilter],
  createEventFilter: [Function: createEventFilter],
  createPendingTransactionFilter: [Function: createPendingTransactionFilter],
  estimateContractGas: [Function: estimateContractGas],
  estimateGas: [Function: estimateGas],
  getBalance: [Function: getBalance],
  getBlobBaseFee: [Function: getBlobBaseFee],
  getBlock: [Function: getBlock],
  getBlockNumber: [Function: getBlockNumber],
  getBlockTransactionCount: [Function: getBlockTransactionCount],
  getBytecode: [Function: getBytecode],
  getChainId: [Function: getChainId],
  getCode: [Function: getCode],
  getContractEvents: [Function: getContractEvents],
  getEip712Domain: [Function: getEip712Domain],
  getEnsAddress: [Function: getEnsAddress],
  getEnsAvatar: [Function: getEnsAvatar],
  getEnsName: [Function: getEnsName],
  getEnsResolver: [Function: getEnsResolver],
  getEnsText: [Function: getEnsText],
  getFeeHistory: [Function: getFeeHistory],
  estimateFeesPerGas: [Function: estimateFeesPerGas],
  getFilterChanges: [Function: getFilterChanges],
  getFilterLogs: [Function: getFilterLogs],
  getGasPrice: [Function: getGasPrice],
  getLogs: [Function: getLogs],
  getProof: [Function: getProof],
  estimateMaxPriorityFeePerGas: [Function: estimateMaxPriorityFeePerGas],
  getStorageAt: [Function: getStorageAt],
  getTransaction: [Function: getTransaction],
  getTransactionConfirmations: [Function: getTransactionConfirmations],
  getTransactionCount: [Function: getTransactionCount],
  getTransactionReceipt: [Function: getTransactionReceipt],
  multicall: [Function: multicall],
  prepareTransactionRequest: [Function: prepareTransactionRequest],
  readContract: [Function: readContract],
  sendRawTransaction: [Function: sendRawTransaction],
  simulateContract: [Function: simulateContract],
  verifyMessage: [Function: verifyMessage],
  verifySiweMessage: [Function: verifySiweMessage],
  verifyTypedData: [Function: verifyTypedData],
  uninstallFilter: [Function: uninstallFilter],
  waitForTransactionReceipt: [Function: waitForTransactionReceipt],
  watchBlocks: [Function: watchBlocks],
  watchBlockNumber: [Function: watchBlockNumber],
  watchContractEvent: [Function: watchContractEvent],
  watchEvent: [Function: watchEvent],
  watchPendingTransactions: [Function: watchPendingTransactions]
}

21074983n

我们发现client这个对象返回出了很多与以太坊交互的接口

http()其实会默认选择rpc就是cloudflare-eth.comcontracts也提供了一个默认的address,默认的交易对就是ETH,精度18

连接钱包

我们知道与以太坊交互去中心化,所有的交易账户需要一个账号与链上产生交互,所以需要链接钱包,当我们插件安装了metaMask后,浏览器的window对象就已经绑定了ethereum这个对象,所以基本上所有与钱包交互的接口的前提是你必须在插件商店安装对应的一个钱包才行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
   function App() {
        const handleConnetWallet = async () => {
        const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' });
        console.log(account, '==account')
      }
  
   return (<div>
            <h1 onClick={handleConnetWallet}>Content Wallet</h1>
      </div>);
   }

当前的web端唤起小狐狸钱包或者其他钱包,基本就是依靠这个window.ethereum.request这个接口

我们注意到一个钱包有很多个账号,而且我们默认的就是ETH主网,因为我们的钱包会默认选择一个ETH主网,当你选择确认对应钱包后,此时的account就是我们选择的钱包地址

SignMessage

通常我们在连接钱包后,我们需要做一个签名,这个签名一般由客户端主动发起,当签名成功后,就会获取一个hash,然后这个hash一般会是通过一个后端登录的接口进行验证这个账户

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import  {memo, useRef} from "react";
...
function App() {
     const accountRef = useRef(null);
    const handleSignMessage = async () => {
    const walletClient = createWalletClient({
        account: accountRef.current,
        chain: mainnet,
        transport:custom(window.ethereum),
    });
    const hash = await walletClient.signMessage({
        message: "hello world"
    });
    console.log(hash);
  }
  const handleConnetWallet = async () => {
    const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' });
    accountRef.current = account;
  }
  return (<div>
     <h1 onClick={handleConnetWallet}>Content Wallet</h1>
     <h1 onClick={handleSignMessage}>SignMessage</h1>
  </div>)
}

注意签名的前提必须是你已经链接钱包

返回的hash是这这样的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
0xaeedca0a7745ee7dbbabdf69226dd7c27aa0f17c8bdcf58616ced8f1b9fe7bc60da3fcdb850af23d1379c2a0b57349862db2010ceb50f8a33322aed68119b14b1c

我们会发现签名值的变化与message这个传入的字符串有关,如果这个字符串发生变化,那么签名后的hash就不回一样,反之当message不发生变化时,产生的hash是不会变化的

isAddress

主要是判断这个钱包地址是否是eth地址

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import {isAddress} from "viem";
...
function App() {
       const [address, setIsAddress] = useState("");
      const [isEthAddress, setIsEthAddress] = useState(false);
     const handleVerifyAddress = () => {
            const isEthAddress = isAddress(address);
            setIsEthAddress(isEthAddress);
      }
    return <>
        <div>
            <input type="text" onChange={(e) => setIsAddress(e.target.value)} />
            <button onClick={handleVerifyAddress}>Verify address</button>
            <p>{address} {isEthAddress ? 'is': 'is not'} eth address</p>
        </div>
    <>
}

sendTransaction

可以理解成一个钱包地址向另外一个地址转账,在操作前,必须有SignMessage操作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
  ...
  const handleSendTransaction = async () => {
    const res = await wallect.current.sendTransaction({
        to: "0x5A39756bAE97685917a292B33ddFb2B54DF1e806",
        value: parseEther("0.001"), // 0.001ETH
    });
    console.log(res);
  }
  return (<>
      <h1 onClick={handleSendTransaction}>sendTransaction</h1>
  </>)

你会发现,我发送2.66$,所需要的gas费用就是0.67$,所以实际上你在钱包中发起的一笔转账,大概总计就需要3.33$

如果你把实际转账的参数改成这样

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
  const handleSendTransaction = async () => {
    const res = await wallect.current.sendTransaction({
        to: "0x5A39756bAE97685917a292B33ddFb2B54DF1e806",
        value: parseEther("1"), // 1 ETH
    });
    console.log(res);
  }
  return (<>
       <h1 onClick={handleSendTransaction}>sendTransaction</h1>
  </>)

你会发现gas费用是动态变化的,但是跟你当下交易的笔数的大小无关,gas费每次都会变化,如果多笔转账合并,那么会减少不少的gas费用

获取公共操作

主要是查询用户账户余额、检索当前区块号,或者检索当前的交易信息,查询这些并不需要签名等权限

  • getBalance
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import {createPublicClient, http, createWalletClient, custom, isAddress, parseEther, formatUnits } from "viem"

import { mainnet, bsc } from "viem/chains";

const client = createPublicClient({
    chain: bsc, // bsc链
    transport: http(),
 })
 
 function App() {
      const handleGetBlance = async () => {
          const res = await client.getBalance({
              address: "0x6c85e349A70791e95fD6D9D5e066C6Ec136E0a92"
          });
           console.log(`余额:${formatUnits(res, 18)} BNB`);
      }
     return <div>
         <div onClick={handleGetBlance}>get Blance</div>
     </div>
 }

我们发现对于获取后的余额实际上精度是18位的,最终我们使用viem中的formatUnits帮我们处理成了与钱包余额一样的余额数值

  • getTransactionReceipt 主要是根本交易hash能查询当前的交易状态,比如
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
 ...
 const handleGetTranstion = async () => {
    const res = await client.getTransactionReceipt({
        hash: "0xf6914af778b18ca1be98adead61af6351862fe26faad7e64d631df30fe925cd4"
    });
 console.log(res);
 function App() {
     return <>
             <h1 onClick={handleGetTranstion}>get transition hash</h1>
     </>
 }
  

我们会查询这个这交易hash的在区块链的实际交易状态,实际上你在https://bscscan.com/ 中根据交易hash也可查询看到对应的状态

至此一个从一个连接钱包登录,到签名,再到sendTransition的基础功能就基本结束,viem也提供了如何与以太坊合约交互的接口,这些都会有一个ABI的数据相关联,后续也会写个测试网合约进行调试,更多的详细的与以太坊交互的参考viem 文档

总结

  • 了解学习到使用更低层的viem官方接口唤起钱包,进行钱包连接签名sendTranstion操作
  • viem开放出来的公用区块查询,比如钱包余额,区块,以及交易状态
  • code example
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-10-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Web技术学苑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
青山不遮,毕竟东流,集成Web3.0身份钱包MetaMask以太坊一键登录(Tornado6+Vue.js3)
    上世纪九十年代,海湾战争的时候,一位美军军官担心他们的五角大楼会被敌人的一枚导弹干掉,从而导致在全球的美军基地处于瘫痪状态。这时候,有一位天才的科学家说,最好的中心就是没有中心。是的,这就是最朴素的去中心化思想,于是互联网出现了。一个没有互联网的时代是无法想象的,互联网的核心就是把一个信息分成若干的小件,用不同的途径传播出去,怎么方便怎么走。
用户9127725
2022/08/08
7830
青山不遮,毕竟东流,集成Web3.0身份钱包MetaMask以太坊一键登录(Tornado6+Vue.js3)
如何开发以太坊网页钱包·Express + web3.js 实例
中国广东省深圳市龙华新区民治街道溪山美地 518131 +86 13113668890 <netkiller@msn.com>
netkiller old
2018/05/18
4.3K0
如何开发以太坊网页钱包·Express + web3.js 实例
.netcore如何开发以太坊区块链示例 原
本文描述了在dotNet核心中使用像以太坊这样的区块链平台的过程。目标受众是其他想要从以太坊开始的dotNet开发者。需要了解区块链。在本文中,我们构建了一个完整的示例,允许你与自定义编写的智能合约进行交互。
笔阁
2018/10/26
1.4K0
web3.js之以太坊交互
web3.js是一个与以太坊交互的重要库,在上一篇介绍的文章中viem也是与以太坊交互的一个库,从功能上讲各有千秋,比起viem,总体包体积web3.js更大,性能也没有viem更好,但很多dapp都是直接使用web3.js,所有这些并不影响众多dapp使用它与以太坊生态的交互
Maic
2025/02/12
1420
web3.js之以太坊交互
交易所对接以太坊钱包服务设计与实现
交易所钱包服务是加密货币交易所系统中的重要组成部分,它负责与各种不同的区块链的交互,实现用户地址生成、充值与提现等功能。本文以对接以太坊区块链的钱包服务为例,介绍交易所系统平台中钱包管理服务的设计与实现。
用户1408045
2019/08/09
2.8K0
Web3js 快速入门
注意:使用上面的命令安装web3.js的话,将会安装web3.js的所有的子包。如果你只需要特定的包,那可以安装指定的包(例如,使用npm i web3-eth-contract来安装与交易相关的包)。
孟斯特
2024/04/24
3470
Web3js 快速入门
chainlink 小实战 web3 “捐助我”项目合约及前端交互——关于 《Patrick web3 course Lesson 7-8 》课程代码中文详解
FundMe lesson 的 示例 本质上是一个合约上对 eth 接收和发送的演示,但这个演示增加了前端 ethers 的交互,以及对 chainlink 预言机喂价的使用。
1_bit
2022/10/28
7580
web3js 实战基本操作
这个篇文章的总结是在学习 b站web3.js的一个基础教程课 的课程总结,方便后续在文章中查找API。
六个周
2023/02/16
1.8K0
web3服务端身份验证
DApp 最大的吸引力就是用户拥有自己的数据。然而要做到这一点,需要验证用户的 web3 身份(用户的钱包)。这在客户端是很容易的(因为用户可以用 Metamask 提交自己的信息),但是在服务端就没那么容易了。
Tiny熊
2022/04/11
2.5K0
web3.js:使用eth包
web3-eth包提供了一套强大的功能,可以与以太坊区块链和智能合约进行交互。在本教程中,我们将指导您如何使用web3.js版本4的web3-eth包的基础知识。我们将在整个示例中使用TypeScript。
孟斯特
2024/05/13
2470
web3.js:使用eth包
第十一课 从宠物商店案例看DAPP架构和WEB3.JS交互接口
【本文目标】 了解ETH生态下DAPP去中心化应用程序的框架和交互流程,了解WEB3.JS的作用和接口函数。 【前置条件】 完成了《第六课 技术小白如何开发一个DAPP区块链应用(以宠物商店为例)》的学习实践,对智能合约了解。 【技术收获】 1). DAPP架构 2). ETH节点框架 3).宠物商店的APP.js文件的业务处理流程图和函数介绍 4).web3.js接口
辉哥
2018/08/10
2.7K0
第十一课 从宠物商店案例看DAPP架构和WEB3.JS交互接口
【Web3项目案例】Ethers.js极简入门+实战案例:实现ERC20协议代币查询、交易
在以太坊生态系统中,ERC20 代币是最常见的一种代币标准。ERC20 代币基于智能合约构建,可以在以太坊网络上进行转账和查询余额。
苏泽
2024/07/01
3330
快速学习-web3.js简介与入门
为了帮助 web3 集成到不同标准的所有类型项目中,1.0.0 版本提供了多种方式来处理异步函数。大多数的 web3 对象允许将一个回调函数作为最后一个函数参数传入,同时会返回一个promise 用于链式函数调用。
cwl_java
2020/04/17
7K0
鲜衣怒马散尽千金,Vue3.0+Tornado6前后端分离集成Web3.0之Metamask钱包区块链虚拟货币三方支付功能
    不得不承认,大多数人并不拥有或者曾经拥有加密货币。是的,Web3.0、加密货币、区块链,对于大多数的互联网用户来说,其实是一些过于轻佻的词汇。如果你是为了追求暴利投机而研究区块链和加密货币,那你多半会失望,因为盐在哪里都是咸的;而如果你是为了摆脱知识桎梏而学习区块链,那你几乎一定能满足,因为懵懂决不是编程界的常态。
用户9127725
2022/08/08
7350
鲜衣怒马散尽千金,Vue3.0+Tornado6前后端分离集成Web3.0之Metamask钱包区块链虚拟货币三方支付功能
以太坊介绍和使用
以太坊是一个能够在区块链上实现智能合约、开源的底层系统。换言之,以太坊是可编程的区块链,它并不是给用户一系列预先设定好的操作(例如比特币交易),而是允许用户按照自己的意愿创建复杂的操作。这样一来,以太坊是就可以作为多种类型去中心化区块链应用的平台,这些应用比如包括之前很火的各种代币但并不仅限于此,我们可以做很多除了代币之外的东西,比如你可以输出一行代表自己不是外行身份的hello world,或者在上面做一个简单的计算器,总之你可以在上面实现你想要的任何功能。
fnatic
2022/07/15
37.4K0
一睹更快更强的Ganache 7
Ganache 是以太坊开发领域的先驱,自 2016 年以来帮助 DApp 开发者和爱好者构建、测试和探索区块链。我们很高兴地宣布最新版本的 Ganache 发布了,分叉(fork)性能提高了 30 倍,并与 Infura 整合,允许你免费访问存档数据,重放历史交易。
Tiny熊
2022/02/22
1.3K0
一睹更快更强的Ganache 7
第十三课 如何在DAPP应用实现自带钱包转账功能?
区块链是一个伟大的发明,它改变了生产关系。很多生态,有了区块链技术,可以由全公司员工的"全员合伙人"变成了全平台的”全体合伙人”了,是真正的共享经济模式。
辉哥
2018/08/10
1.8K0
第十三课 如何在DAPP应用实现自带钱包转账功能?
web3j教程:java使用web3j开发以太坊智能合约交易
为了进行这些交易,必须有以太币(以太坊区块链的代币)存在于交易发生的以太坊账户中。这是为了支付gas成本,这是为支付参与交易的以太坊客户端的交易执行成本,支付了这个成本就能将结果提交到以太坊区块链上。获得以太币的说明下文会说到。
笔阁
2018/09/04
7.9K1
web3j教程:java使用web3j开发以太坊智能合约交易
新版以太坊Ethereum库ethersV5.0配合后端Golang1.18实时链接区块链钱包(Metamask/Okc)以及验签操作
    区块链去中心化思想无处不在,比如最近使用个体抗原自检替代大规模的中心化核酸检测,就是去中心化思想的落地实践,避免了大规模聚集导致的交叉感染,提高了检测效率,本次我们使用Ethereum最新的ethersV5.0以上版本链接去中心化区块链钱包,并且通过后端Golang1.18服务进行验签。
用户9127725
2022/12/05
7350
新版以太坊Ethereum库ethersV5.0配合后端Golang1.18实时链接区块链钱包(Metamask/Okc)以及验签操作
搭建以太坊私有链
区块链技术正在逐渐走向成熟,以太坊作为区块链领域的重要代表被广泛应用于智能合约、去中心化应用等领域,然而公有链上的交易需要消耗大量的手续费,且数据的公开性也限制了其在某些场景下的应用。因此搭建以太坊私有链成为了一种更加灵活、高效、安全的解决方案,本文将介绍如何搭建以太坊私有链帮助读者更好地理解和应用区块链技术
Al1ex
2023/09/07
1.6K1
搭建以太坊私有链
推荐阅读
相关推荐
青山不遮,毕竟东流,集成Web3.0身份钱包MetaMask以太坊一键登录(Tornado6+Vue.js3)
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验