You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于PancakeSwap合约实现单次调用同时兑换多个代币

多代币批量兑换实现方案

核心思路是在单次调用内循环执行原有的单代币兑换逻辑,提前预估所需总BNB金额完成校验,兑换完成后统一退还剩余BNB。

核心改动点

  • 新增批量兑换接口,入参为各目标代币的期望兑换数量数组,顺序对应你预先定义的crypto1、crypto2、crypto3
  • 调用路由合约的getAmountsIn接口预计算每个代币兑换所需的BNB总额,校验用户传入的msg.value足够支付所有兑换
  • 循环执行单代币兑换逻辑,每次兑换使用合约当前剩余的BNB支付
  • 所有兑换完成后统一退还剩余BNB给调用者

完整修改后代码

pragma solidity 0.7.1;

import "https://github.com/pancakeswap/pancake-swap-periphery/blob/master/contracts/interfaces/IPancakeRouter02.sol";

contract UniswapExample {
  address internal constant UNISWAP_ROUTER_ADDRESS = 0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3 ; //Pancake测试网路由地址

  IPancakeRouter02 public uniswapRouter;
 
  address private crypto1 = 0x7ef95a0FEE0Dd31b22626fA2e10Ee6A223F8a684;
  address private crypto2 = 0x78867BbEeF44f2326bF8DDd1941a4439382EF2A7;
  address private crypto3 = 0x8a9424745056Eb399FD19a0EC26A14316684e274;

  constructor() {
    uniswapRouter = IPancakeRouter02(UNISWAP_ROUTER_ADDRESS);
  }

  // 原有单代币兑换函数保留
  function convertEthToCrypto(uint cryptoAmount) public payable {
    uint deadline = block.timestamp + 15; 
    uniswapRouter.swapETHForExactTokens{ value: msg.value }(cryptoAmount, getPathForETH(crypto1), address(this), deadline);
    
    (bool success,) = msg.sender.call{ value: address(this).balance }("");
    require(success, "refund failed");
  }

  // 新增批量兑换函数
  function convertEthToMultipleCrypto(uint[] calldata cryptoAmounts) public payable {
    // 数量数组长度需对应3个预设代币
    require(cryptoAmounts.length == 3, "Amount array length must be 3");
    uint deadline = block.timestamp + 15;
    uint totalRequiredBNB = 0;

    // 预计算所有兑换所需的总BNB金额
    for(uint i = 0; i < cryptoAmounts.length; i++) {
        address targetToken = _getTokenByIndex(i);
        uint[] memory amountsIn = uniswapRouter.getAmountsIn(cryptoAmounts[i], getPathForETH(targetToken));
        totalRequiredBNB += amountsIn[0];
    }
    require(msg.value >= totalRequiredBNB, "Insufficient BNB for all swaps");

    // 循环执行每个代币的兑换
    for(uint i = 0; i < cryptoAmounts.length; i++) {
        address targetToken = _getTokenByIndex(i);
        uniswapRouter.swapETHForExactTokens{value: address(this).balance}(
            cryptoAmounts[i], 
            getPathForETH(targetToken), 
            address(this), // 如需直接转到调用者钱包,改为msg.sender即可
            deadline
        );
    }
    
    // 退还剩余BNB
    (bool success,) = msg.sender.call{ value: address(this).balance }("");
    require(success, "refund failed");
  }

  // 辅助方法:按索引取对应代币地址
  function _getTokenByIndex(uint index) internal view returns(address) {
      if(index == 0) return crypto1;
      else if(index == 1) return crypto2;
      else return crypto3;
  }
                 
  function getPathForETH(address crypto) public view returns (address[] memory) {
    address[] memory path = new address[](2);
    path[0] = uniswapRouter.WETH();
    path[1] = crypto;
    
    return path;
  }
  
  
  function getETH() public view returns(address) {
      return uniswapRouter.WETH();
  }
  
  receive() payable external {}
}

注意事项

  • 调用批量兑换接口时,传入的BNB金额需要略高于预计算的总金额,覆盖兑换滑点,避免交易失败
  • 主网部署时建议把deadline参数改为前端传入,不要在合约内写死固定时长,避免区块拥堵时交易过期失败
  • 若需要兑换获得的代币直接打到调用者钱包,可将swapETHForExactTokens的第三个参数从address(this)改为msg.sender
  • 如果需要支持任意数量的自定义代币兑换,可修改批量兑换函数的入参,同时传入代币地址数组和对应数量数组,去掉固定的长度校验即可

内容的提问来源于stack exchange,提问作者holistic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 00:15:07