React Native DApp 开发全栈实战·从 0 到 1 系列(收益聚合器-前端部分)

88 阅读3分钟

前言

基于《 React Native DApp 开发全栈实战·从 0 到 1 系列(收益聚合器-合约部分)》,本文进入“前端交互”环节,把已经部署在 Hardhat Local 上的 多授权代币 + 收益聚合器 搬到浏览器里:用 MetaMask 点火,用 ethers.js 操纵,完成 存、取、份额、喂价、权限 五大核心场景的实时调用。

前期准备

  • hardhat启动网络节点:npx hardhat node
  • 合约编译:npx hardhat compile 生成对应的xxx.json用获取abi等相关信息
  • 合约部署:npx hardhat deploy --tags token3,token4,MockV3Aggregator,YieldAggregator 获取合约地址(资产代币、奖励代币、喂价和收益聚合器合约地址)
  • 节点的私钥导入钱包:用来与合约交互时支付对应的gas费

核心代码

  • 公共代码
import { abi as MockV3AggregatorABI } from '@/abi/MockV3Aggregator.json';
import { abi as MyTokenABI1 } from '@/abi/MyToken1.json';
import { abi as MyTokenABI3 } from '@/abi/MyToken3.json';
import { abi as YieldAggregatorABI } from '@/abi/YieldAggregator.json';
import * as ethers from 'ethers';
  • 场景1(首次存入正确铸造份额=》二次存入按比例铸造份额 =》提取后份额与资产减少)
  const aggregatorFn=async ()=>{
        const provider = new ethers.providers.Web3Provider(window.ethereum);
        await provider.send('eth_requestAccounts', []); // 唤起钱包
        const signer = await provider.getSigner();
        const userAddr = await signer.getAddress();//当前用户地址
        const YieldAggregatorAddress="0x0E801D84Fa97b50751Dbf25036d067dCf18858bF"//聚合器地址
        const MockV3AggregatorAddress="0x998abeb3E57409262aE5b751f60747921B33613E"//MockV3Aggregator地址
        const MyAssetAddress="0x4826533B4897376654Bb4d4AD88B7faFD0C98528" //资产
        const MyAwardAddress="0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf"//奖励
        const YieldAggregatorContract = new ethers.Contract(YieldAggregatorAddress, YieldAggregatorABI, signer);
        const MockV3AggregatorContract = new ethers.Contract(MockV3AggregatorAddress, MockV3AggregatorABI, signer);
        const MyAssetContract = new ethers.Contract(MyAssetAddress, MyTokenABI1, signer);//资产
        const MyAwardContract = new ethers.Contract(MyAwardAddress, MyTokenABI3, signer);//奖励
        
        console.log(YieldAggregatorContract,MockV3AggregatorContract,MyAssetContract,MyAwardContract)

        const DEPOSIT_AMOUNT = ethers.utils.parseUnits("100", 18); // 100 个 token(18 位)
        const WITHDRAW_SHARES = ethers.utils.parseUnits("30", 18); // 100 个 token(18 位)

        /* ---------- 1. mint + approve ---------- */
  // 如果 asset 是 ERC20 且用户余额不足,我们先给他 mint(测试 token 才有)
  const mintTx = await MyAssetContract.mint(userAddr, DEPOSIT_AMOUNT);
  await mintTx.wait();

  const approveTx = await MyAssetContract.approve(YieldAggregatorAddress, DEPOSIT_AMOUNT);
  await approveTx.wait();

  /* ---------- 2. 首次 deposit ---------- */
  const depositTx = await YieldAggregatorContract.deposit(DEPOSIT_AMOUNT);
  await depositTx.wait();

  /* ---------- 3. 打印结果 ---------- */
  const userShares = await YieldAggregatorContract.shares(userAddr);
  const totalShares= await YieldAggregatorContract.totalShares();
  const totalAssets= await YieldAggregatorContract.totalAssetsDeposited();
  console.log("首次存入后用户份额 :", ethers.utils.formatUnits(userShares, 18));
  console.log("首次存入后份额总量 :", ethers.utils.formatUnits(totalShares, 18));
  console.log("首次存入后资产总量 :", ethers.utils.formatUnits(totalAssets, 18));  
  
  //提取资产
  const withdrawTx = await YieldAggregatorContract.withdraw(WITHDRAW_SHARES);
  await withdrawTx.wait();
//验证
  const userSharesAfter = await YieldAggregatorContract.shares(userAddr);
  const totalSharesAfter= await YieldAggregatorContract.totalShares();
  const totalAssetsAfter= await YieldAggregatorContract.totalAssetsDeposited();
  console.log("提取资产后用户份额 :", ethers.utils.formatUnits(userSharesAfter, 18));
  console.log("提取资产后份额总量 :", ethers.utils.formatUnits(totalSharesAfter, 18));
  console.log("提取资产后资产总量 :", ethers.utils.formatUnits(totalAssetsAfter, 18));
    }
  • 场景2(无法提取超过自身份额、 rescue 只能 owner 调用 、getUserAssetValue 计算正确)
  • 场景3 获取喂价
const ethPrice=await YieldAggregatorContract.getETHPrice()
console.log("ethPrice:",ethers.utils.formatUnits(ethPrice,8))

效果图

图1转存失败,建议直接上传图片文件 图1转存失败,建议直接上传图片文件

总结

  1. 一条命令跑通全流程
    npx hardhat nodecompiledeploy --tags → 私钥导入钱包,30 秒完成链端准备。

  2. 三大场景一次封装

    • 首次存入 1:1 铸造份额
    • 二次存入按比例增发
    • 提取后份额 & 资产同步减少
      外加 超额提取 revert、owner rescue、实时 ETH 价格 等边界校验,全部在前端用 Contract.method + wait() 实现,与单元测试断言一一对应。
  3. 直接可迁移到生产
    代码已抽离公共 signer/contract 初始化逻辑,只需把地址、ABI 换成正式网络,即可无缝接入 React / React Native 项目;UI 层只需包裹按钮与 Loading,即可完成「链上收益聚合器」的完整交互闭环。

至此,合约端 + 前端双端闭环全部打通,恭喜你拥有了一套可扩展、可复用、可上架的 DeFi 迷你收益聚合器 DApp!