React Native DApp 开发全栈实战·从 0 到 1 系列(钱包相关)

  • 木西
  • 发布于 10小时前
  • 阅读 58

前言本文主要用Ethers.jsv5在一篇文章里讲透「钱包全链路」:连接→授权→转账→检测→交易记录→账号列表。所有代码片段可直接拷进项目跑通。补充:使用ganache作为测试账号,通过创建自定义网络的导入账号;以web端为主准备工作注册个Ganache账号用来

前言

本文主要用 Ethers.js v5 在一篇文章里讲透「钱包全链路」:连接 → 授权 → 转账 → 检测 → 交易记录 → 账号列表。所有代码片段可直接拷进项目跑通。补充:使用ganache作为测试账号,通过创建自定义网络的导入账号;以web端为主

准备工作

  • 注册个Ganache账号用来测试,安装ganache-cli运行节点或者下载个客户端

<!---->

启动终端指令 cmd
ganache//返回链id rpc链接 和10个账号的公钥和私钥 助记词等
  • ganache返回值汇总

    字段
    网络名称 Ganache Local
    RPC URL <http://127.0.0.1:8545>
    链 ID 1337
    货币符号 ETH
    区块浏览器 URL (可不填)
  • 安装个metamask浏览器插件,用来导入测试账号和dapp交互使用

<!---->

# 插件安装完毕,已经注册了metamask账号
# 点击设置选择网络
# 点击 添加自定义网络
# 弹出面板,分别填写 网络名称、RPCURL、链ID、货币符号、区块浏览器url(可填、可部填),这些信息获取可以通过ganache返回值中获取 .

项目配置

  • 安装 ethers + RN 适配包

<!---->

# 包安装
npx expo install ethers
npx expo install @ethersproject/shims
npx expo install react-native-get-random-values
  • 在项目入口文件(_layout.tsx)顶部 第一行 引入 shims

<!---->

import '@ethersproject/shims';
import 'react-native-get-random-values';
  • 组件中使用ethers

<!---->

import { ethers } from 'ethers';

链接、断开钱包

# 链接钱包
const onConnectWalletFunction=async ()=>{
   // 1. 判断 MetaMask
  if (!window.ethereum) {
    alert('请先安装 MetaMask');
    return null;
  }

  // 2. 创建 Provider
  const provider = new ethers.providers.Web3Provider(window.ethereum);

  // 3. 唤起授权
  await provider.send('eth_requestAccounts', []);
   let addressList=await provider.listAccounts()
   console.log(addressList);

  // 4. 获取签名器 & 地址
  const signer = await provider.getSigner();
  const address = await signer.getAddress();

  // 5. 查余额(wei → ETH)
  const balanceWei = await provider.getBalance(address);
  const balanceEth = ethers.utils.formatEther(balanceWei);
  //使用zustand 存储钱包的信息:例如 地址 余额交易信息等等
  setAddress(address);//zustand 定义的方法
  setBalance(balanceEth);//zustand 定义的方法
  setAddressBookList([...addressList]);//联系人 钱包列表
  }
 # 断开钱包
 # 断开钱包需要手动断开,组件知识清除存储的信息
 const disconnectFn=()=>{
    setBalance("")
    setWellatAddress("")
    useWallet.persist.clearStorage();//zustand清空数据
}

获取指定账号的交易记录

说明:主要自定义网络只能通过扫描log日志来实现交易记录整理,(不是最优解),如果是测试链(mainnet)可以通过(new ethers.providers.EtherscanProvider)来实现更加优雅

  • 以太主网交易记录

<!---->

const provider = new ethers.providers.EtherscanProvider('mainnet', YOUR_KEY);
const history = await provider.getHistory(address, 0, 'latest');
console.log(history.slice(-100));
  • 自定义网络交易记录

<!---->

# 说明通过扫描日志log来获取信息,整理交易信息
 const hostlistFn= async ()=>{
        const TARGET_ADDR = address.toLowerCase();
        const provider = new ethers.providers.JsonRpcProvider('http://localhost:8545');//ganache rpcurl
        const latest = await provider.getBlockNumber();//获取区块
        const list: any[] = [];
        console.log(`开始扫描 0 → ${latest} 区块...`);
        for (let i = 0; i &lt;= latest; i++) {
            const block = await provider.getBlockWithTransactions(i);
            console.log(block)
            for (const tx of block.transactions) {
            if (
                tx.from.toLowerCase() === TARGET_ADDR ||
                (tx.to && tx.to.toLowerCase() === TARGET_ADDR)
            ) {
                list.push({
                hash:      tx.hash,
                from:      tx.from,
                to:        tx.to,
                value:     ethers.utils.formatEther(tx.value),
                block:     tx.blockNumber,
                timestamp: new Date(block.timestamp * 1000).toLocaleString(),
                });
            }
            }
        }
        return list;
    }
    hostlistFn()
  .then(txs => {
    console.log(`共 ${txs.length} 笔转账`);
    console.table(txs);
  })
  .catch(console.error);

监听钱包事件

# 核心代码
  window.ethereum.on('accountsChanged',async (accounts: string[]) => {

  if (accounts.length === 0) {
    // 用户断开所有账户
    setAddress(null);
  } else {
    //可以进行后续的操作
  }
})

转账

 const onSend=async()=>{
      // 1. 拿到浏览器注入的 provider
const provider = new ethers.providers.Web3Provider(window.ethereum);

// 2. 让用户授权并拿到 signer
await provider.send("eth_requestAccounts", []);
const signer = await provider.getSigner();

// 3. 构造交易
const tx = await signer.sendTransaction({
  to:    Recipient, // 接收地址
  value: ethers.utils.parseEther(Amount), // 0.01 ETH → wei
  // gasLimit、maxFeePerGas 可省略,MetaMask 会自动估算
});

// 4. 等待确认
const receipt = await tx.wait();
console.log("交易已确认,哈希:", receipt); // 成功
if(receipt.status==1){
//成功后进行后续操作
}else{
  alert("交易失败");
}
  }

获取账号列表

# 创建 Provider
  const provider = new ethers.providers.Web3Provider(window.ethereum);
# 授权 
  await provider.send('eth_requestAccounts', []);
# 获取账号列表 
  let addressList=await provider.listAccounts()

效果图

<div style="display:flex; gap:8px;flex-wrap:wrap;"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/cf834dbf6d0b476386d94b71be6a0fb2~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&#x26;rk3s=e9ecf3d6&#x26;x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&#x26;x-orig-expires=1756125869&#x26;x-orig-sign=dvROBVnziTu6UUa%2FFD8Pf4mDYIk%3D" alt="图1" width="200"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/9232714519244a7fad0ebcd8f65815e0~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756125913&x-orig-sign=EE7TLQn4RN9s3hVeMYA0cPLLJUI%3D" alt="图1转存失败,建议直接上传图片文件" width="200"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/6eee1733f3af4adda8e200c0d3647021~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756126192&x-orig-sign=%2FP6R6vFEbKH2gQXT74Z%2FI2BwRZY%3D" alt="图1转存失败,建议直接上传图片文件" width="200"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/c195ab0a6a2d44ad9c3c128f9ca884d8~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756126234&x-orig-sign=xVwBudV9x6xXzJtFDG0LZ3s7NxU%3D" alt="图1转存失败,建议直接上传图片文件" width="200">
<img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/389c4f830a5d4769a48046ff6e58aa9a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756126273&x-orig-sign=VqUqCvxyDXLvJdIGC0%2F2S9rj9LQ%3D" alt="图1转存失败,建议直接上传图片文件" width="200">
<img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/7110b79ce73748bea7635680ba0faf40~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756126082&x-orig-sign=hI79yzHKqn6apmkPkHvFNbze10Y%3D" alt="图1转存失败,建议直接上传图片文件" width="200">
</div>

总结

至此,「钱包全链路」完整闭环:
连接 → 授权 → 转账 → 余额 → 交易记录 → 账号列表 → 监听 → 断开。
所有代码可直接落地项目;如需支持移动端 React-Native,把 window.ethereum 换成 WalletConnect 即可

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
木西
木西
0x5D5C...2dD7
江湖只有他的大名,没有他的介绍。