如何使用EIP-7702构建一个ERC-20批量交换dApp

本文介绍了如何使用EIP-7702标准和QuickNode Marketplace插件构建一个去中心化应用(dApp),用于批量交易ERC-20代币,将其合并为单一资产。通过Covalent Token API获取钱包余额,并通过Aerodrome和Velodrome Swap API获取最佳兑换报价,在Base和Optimism网络上执行批量兑换。

概述

跨各种协议管理多个 ERC-20 代币可能会很快变成一件令人头疼的事情。随着时间的推移,钱包会收集“灰尘”(少量、低价值的代币),清理它们通常意味着需要多次批准、交换和支付费用。

EIP-7702 通过允许你授权智能合约在单个原子交易中执行多个操作来简化此过程。

在本指南中,你将构建一个去中心化应用程序 (dApp),它将多个 ERC-20 代币交换批量处理到一个无缝的交易中,并将它们转换为单个资产。你将使用 QuickNode Marketplace 插件 来获取代币余额,获取最佳交换报价,并在 Base 和 Optimism 网络上执行批量交换。

到最后,你将拥有一个功能齐全的 dApp,可以将繁琐的钱包清理变成快速、一键式的操作。

准备好开始了吗?

  • 在 Vercel 上部署此 dApp:查看我们的示例应用程序库 此处
  • 查看实际效果:尝试 在线演示

你将学到什么

  • 如何在 dApp 中实现 EIP-7702 以进行批量交易执行
  • 如何使用 Covalent Token API 插件获取钱包余额
  • 如何使用 Aerodrome 和 Velodrome Swap API 获取优化的交换报价
  • 如何将这些技术结合起来构建一个可用于生产环境的应用程序

你需要什么

  • 一个带有 Base 或 Optimism 端点的 QuickNode 账户
  • Covalent Token API 插件(无免费层级)和 AerodromeVelodrome Swap API 插件(有免费层级
  • 你的机器上安装了 Node.js
  • JavaScript/TypeScript 和 React 的基本知识
  • MetaMask 钱包,其中包含一些 ERC20 代币和 Base Mainnet 或 Optimism Mainnet 上的 ETH

应用程序流程和架构

在深入研究代码之前,让我们从高层次了解应用程序的工作流程。此过程利用多个 API 来创建简单的前端体验。

下面的流程图提供了应用程序阶段的高级概述,展示了用户从连接他们的钱包到最终交易的过程。

Token Sweeper - 应用程序流程

为了获得更详细的技术视图,下面的时序图说明了幕后发生的通信。

Token Sweeper - 时序图

核心技术解释

我们应用程序的强大之处在于 EIP-7702 与专门的 QuickNode Marketplace 插件的结合。让我们分解每个组件。

EIP-7702 如何实现批量交换

EIP-7702 是一种标准,它允许外部账户 (EOA) 在单个交易中临时充当智能合约。这解决了 DeFi 中的一个主要摩擦点:执行多个操作

传统上,交换十种不同的代币至少需要二十个单独的操作:十个 approve 交易和十个 swap 交易,每个都需要签名和 gas 费。

EIP-7702 通过引入一种可以包含 delegation 的新交易类型来简化此过程。此委托授权特定的实现合同代表用户执行一系列调用。这实现了:

  • 批量执行:授权的合约在一个交易中处理所有单个交换。
  • 原子成功:所有操作一起成功或失败,防止部分失败的状态。
  • Gas 效率:将操作合并为单个交易可显着降低总 gas 成本。

从技术上讲,此功能通过 wallet_sendCalls JSON-RPC 方法暴露给 dApp,我们将使用 wagmi 的 useSendCalls hook 轻松访问该方法。

当前的 EIP-7702 格局

EIP-7702 仍然很新,并且钱包支持正在发展。在撰写本文时,MetaMask 已经将 EIP-7702 集成到他们的钱包 UI 中,提供了无缝的用户体验。当你发起 EIP-7702 交易时,MetaMask 将提示你将钱包升级到智能账户。这是一个一次性的、可逆的过程,它将授权委托给 MetaMask 审计的实现合约 EIP7702DeleGator

由于安全问题,主要钱包可能会管理他们自己的委托合约,而不是允许 dApp 指定任意合约。因此,钱包开发是 EIP-7702 采用的主要重点。由于只有少数钱包支持 EIP-7702,我们将建议在本指南中使用 MetaMask。

如何获取代币余额

首先在工作流程级别,你需要知道用户拥有哪些 ERC20 代币。为此,我们将使用 Covalent Token API 插件。此插件提供了一种简单快速的方法来获取代币余额,而不是手动查询每个代币的余额。

在应用程序中的使用

我们将使用 getTokenBalancesForWalletAddress 端点来填充用户的代币列表。

如何在应用程序中获取代币余额

​```typescript
const response = await client.BalanceService.getTokenBalancesForWalletAddress(
    chainName as any,
    address
)
​```
示例 API 响应

当你从 Covalent API 查询 getTokenBalancesForWalletAddress 端点时,你将收到一个详细的 JSON 对象。最重要的部分是 items 数组,其中每个对象代表用户钱包中的单个代币。

来自 Covalent Token API 的部分响应

​```json
{
    "address": "0x0a417ddb75dc491c90f044ea725e8329a1592d00",
    "quote_currency": "USD",
    "chain_id": 8453,
    "items": [\
        {\
            "contract_decimals": 6,\
            "contract_name": "USD Coin",\
            "contract_ticker_symbol": "USDC",\
            "contract_address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",\
            "supports_erc": ["erc20"],\
            "logo_url": "https://logos.covalenthq.com/tokens/8453/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.png",\
            "native_token": false,\
            "is_spam": false,\
            "balance": "2503277",\
            "quote": 2.5007737,\
            "pretty_quote": "$2.50"\
            // ...\
        }\
    ]
}
​```

从这个响应中,我们的应用程序将使用关键字段,如 contract_addressbalancequote(用于其美元价值)和 is_spam 标志来构建代币投资组合列表。

除了获取用户当前的代币之外,我们的应用程序还需要一个他们可以交换的有效代币列表。为此,我们使用 Aerodrome/Velodrome Swap API 的 /v1/tokens 端点。

来自 Aerodrome Swap API 的部分响应

​```json
{
    "tokens": [\
        {\
            "address": "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA",\
            "symbol": "USDbC",\
            "decimals": 6,\
            "listed": true\
        }\
        // ...\
    ]
}
​```

如何获取优化的交换报价

一旦用户选择要交换的代币,你需要找到最佳的交易途径。Aerodrome Swap API(在 Base 上)和 Velodrome Swap API(在 Optimism 上)Swap API 插件可在所有可用的流动性池中找到最佳价格。

示例 API 响应

/v1/quote 端点接受源代币、目标代币和金额,然后返回最佳的汇率。成功的响应将如下所示:

来自 Aerodrome Swap API 的部分响应

​```json
{
    "input": {
        "token": {
            "address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
            "symbol": "AERO",
            "decimals": 18
        },
        "amount": 1,
        "amount_wei": "1000000000000000000",
        "price_usd": 0.8814186513914624,
        "value_usd": 0.8814186513914624
    },
    "output": {
        "token": {
            "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
            "symbol": "USDC",
            "decimals": 6
        },
        "amount": 0.876388,
        "amount_wei": "876388",
        "min_amount": 0.872007,
        "min_amount_wei": "872007",
        "price_usd": 0.999567128249789,
        "value_usd": 0.876008636392576
    },
    "route": {
        "path": [\
            {\
                "pool_address": "0x6cDcb1C4A4D1C3C6d054b27AC5B77e89eAFb971d",\
                "is_stable": false,\
                "is_cl": false,\
                "hop_number": 1\
            }\
        ],
        "hops": 1,
        "type": "direct"
    },
    "execution_price": 0.876388,
    "slippage": 0.005
}
​```

v1/quote 端点接受源代币、目标代币和金额,并返回最佳的汇率。我们将使用它在用户确认交换之前向他们显示预期的输出。

在应用程序中的使用

在我们的前端,我们调用我们自己的 API 路由,该路由又查询此端点。然后,获取的报价数据用于填充确认屏幕。

如何在应用程序中获取交换报价

​```typescript
const tokenBalance = BigInt(token.balance)
// Convert from wei to token units for API call
const tokenAmount = formatUnits(tokenBalance, token.contract_decimals)

const quoteUrl = `/api/swap/quote?chainId=${chainId}&from_token=${tokenAddr}&to_token=${outcomeTokenAddress}&amount=${tokenAmount}&slippage=${APP_CONFIG.SLIPPAGE_TOLERANCE}`

const response = await fetch(quoteUrl)
​```

这使我们能够在用户签署最终交易之前向他们展示预期结果的清晰细分。

Swap Quotes

如何构建交换交易

在获得报价后,v1/swap/build 端点会返回随时可以发送的交易 calldata,这是一个 JSON 对象,其中包含执行交换所需的一切。我们主要需要每个交易的 datato 字段。

示例 API 响应

来自 Aerodrome Swap API 的部分响应

​```json
"transactions": [\
    {\
      "type": "approval",\
      "description": "Approve AERO for swap",\
      "transaction": {\
        "to": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",\
        "data": "0x095ea7b3...", // 为了视觉清晰而截断\
        "value": "0x0",\
        "gas": "0x186a0",\
        "gasPrice": "0x5c7742",\
        "nonce": "0xc",\
        "chainId": "0x2105",\
        "from": "0x1539F7fBe3C26F5611DD4A449236180990F3e80F"\
      }\
    },\
    {\
      "type": "swap",\
      "description": "Swap 1.0 AERO to USDC",\
      "transaction": {\
        "from": "0x1539F7fBe3C26F5611DD4A449236180990F3e80F",\
        "to": "0x6Cb442acF35158D5eDa88fe602221b67B400Be3E",\
        "value": "0x0",\
        "data": "0x24856bc30...", // 为了视觉清晰而截断\
        "nonce": "0xc",\
        "chainId": "0x2105",\
        "gas": "0x493e0",\
        "gasPrice": "0x6af87c"\
      }\
    }\
]
​```
在应用程序中的使用

我们的 use-swap-builder.ts hook 为用户选择的每个代币调用此端点。然后,它处理每个响应以组装最终的调用数组。

如何在应用程序中构建交换交易

​```typescript
const tokenAmount = formatUnits(BigInt(token.balance), token.contract_decimals)

const buildParams: SwapBuildParams = {
    from_token: tokenAddr as Address,
    to_token: outcomeTokenAddress as Address,
    amount: tokenAmount, // Convert to token units, not wei
    wallet_address: userWalletAddress as Address, // User's actual wallet address
    slippage: APP_CONFIG.SLIPPAGE_TOLERANCE,
}

const buildUrl = `/api/swap/build?chainId=${chainId}`

const response = await fetch(buildUrl, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(buildParams),
})
​```

如何执行批量交易

最后一步是一次发送所有准备好的交易。Wagmi 的 useSendCalls hook 使这变得非常简单,并允许你传递一个交易对象数组以批量执行。

calls 参数是一个数组,其中每个对象代表我们想要执行的单个交易。我们将通过映射用户的选定代币并使用来自 /v1/swap/build 端点的数据来构建此数组。

我们还将 experimental_fallback 选项设置为 true,如果钱包不支持 EIP-7702,则允许交易回退到常规交易。

来自应用程序的部分代码片段

​```typescript
{
    // Build transaction calls for batch execution using Swap APIs
    const calls = await buildSwapCalls(
        selectedTokens,
        tokens,
        outcomeToken,
        chainId,
        address
    )

    if (calls.length === 0) {
        throw new Error('No valid swap calls could be built')
    }

    // Execute batch transaction using MetaMask EIP-7702, with fallback for non-supporting wallets
    sendCalls({ calls, experimental_fallback: true })
}
​```

构建批量交换应用程序

现在,让我们设置项目并在你的本地机器上运行该应用程序。

前提条件

在运行应用程序之前,你需要一个 QuickNode 端点和所需的插件,以及 WalletConnect 项目 ID。

设置 QuickNode
  1. 创建端点:登录到你的 QuickNode 帐户,并为你想要支持的每个链创建一个新端点。在本指南中,我们将使用 Base 和 Optimism。

由于这些 API 插件仅在主网上可用,因此你需要使用主网端点设置你的 QuickNode 帐户。

  1. 安装插件

你只需要安装你计划支持的链的插件。免费套餐足以开始使用。

  1. 获取 Covalent API 密钥:单击 Covalent Token API 插件旁边的“登录到仪表板”。这将重定向到 Covalent 仪表板,你可以在其中找到你的 API 密钥。

  2. 获取交换 API URL:单击 Aerodrome 或 Velodrome Swap API 插件旁边的“入门”。这将向你显示你的应用程序中需要使用的基本 API URL。使用 /v1/... 部分之前的 URL,因为我们将在我们的代码中附加特定的端点。它应该看起来像这样:https://YOUR-QUICKNODE-ENDPOINT-URL/addon/YOUR-ADDON-ID

设置 Reown(以前称为 WalletConnect)
  1. 创建一个 Reown(以前称为 WalletConnect)项目:前往 Reown Cloud 并创建一个新项目。你可以随意命名。

  2. 获取项目 ID:创建项目后,你将被重定向到项目仪表板。在这里,你可以找到你的项目 ID,你需要在你的应用程序中使用它。

设置项目

  1. 克隆存储库:将存储库克隆到你的本地机器。
​```bash
git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/sample-dapps/token-sweeper-eip-7702
​```
  1. 安装依赖项: 使用你喜欢的包管理器来安装项目依赖项。
​```bash
npm install
## 或
yarn install
## 或
pnpm install
​```
  1. 设置环境变量: 通过复制 .env.example 文件在项目的根目录中创建一个 .env.local 文件。
​```bash
cp .env.example .env.local
​```

现在,打开 .env.local 并添加相关的环境变量。

​```
## API 密钥(仅服务器端)
COVALENT_API_KEY=your_covalent_api_key_here

## WalletConnect 项目 ID(RainbowKit 所需 - 需要客户端)
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_walletconnect_project_id_here

## RPC URLs
NEXT_PUBLIC_BASE_RPC_URL=your_base_rpc_url_here
NEXT_PUBLIC_OPTIMISM_RPC_URL=your_optimism_rpc_url_here

## Aerodrome/Velodrome API URLs(实际交换功能所需)
## 注意:这些现在仅在服务器端
AERODROME_BASE_API=your_quicknode_aerodrome_base_api_here
VELODROME_OPTIMISM_API=your_quicknode_velodrome_optimism_api_here
​```
  1. 运行应用程序: 启动开发服务器。
​```bash
npm run dev
## 或
yarn dev
## 或
pnpm dev
​```

打开你的浏览器到 http://localhost:3000 以查看应用程序的实际效果。

  1. 测试应用程序: 尝试在你的应用程序中执行以下步骤:
  • 连接钱包:使用 MetaMask 连接到应用程序
  • 切换网络:确保你位于 Base 或 Optimism 主网上
  • 查看代币:应用程序将显示你的 ERC-20 代币余额
  • 选择代币:选择要交换的代币和输出代币
  • 获取报价:查看交换估算和总输出
  • 执行批处理:确认交易(如果需要,MetaMask 将提示你升级智能帐户)

当你准备好部署时,像 Vercel 或 Netlify 这样的平台提供了与 Next.js 应用程序的无缝集成,从而提供了从开发到生产的简单途径。

结论

你已成功构建了一个 Token Sweeper dApp,该 dApp 演示了 EIP-7702 在批量交易中的强大功能。此应用程序展示了 QuickNode 的 Marketplace 插件如何消除对复杂后端基础架构的需求,同时提供企业级功能。

Covalent 全面的代币数据、Aerodrome 和 Velodrome 优化的 DEX 路由以及 EIP-7702 的批量执行相结合,创造了一种无缝的用户体验,使用户能够以最小的摩擦交换代币。

如果你有任何问题,请随时使用我们的 Discord 服务器,或者使用下面的表格提供反馈。请关注我们的 Twitter 和我们的 Telegram 公告频道,及时了解最新信息。

附加资源

我们 ❤️ 反馈!

如果你对新主题有任何反馈或要求,请告诉我们。我们很乐意听取你的意见。

  • 原文链接: quicknode.com/guides/eth...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。