能否在一笔交易中同时发送1155/731 NFT与ERC-20代币?求示例
单笔交易同时转账NFT(ERC-721/ERC-1155)与ERC-20代币的可行性及实现
可行性说明
完全可行。区块链交易的本质是向链上发送包含一系列指令的数据包,只要这些指令符合合约调用规则,就能在同一笔交易内依次执行多个操作——比如完成ERC-20代币转账后,再执行ERC-721/ERC-1155 NFT的转账,核心是通过合约批量调用或聚合合约来实现。
实现方式及示例
方式1:自定义聚合合约(推荐)
编写一个简单的智能合约,在合约内封装ERC-20和NFT的转账逻辑,用户只需调用聚合合约的一个方法,就能在单笔交易中完成所有操作。
Solidity合约示例
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC20 { function transfer(address to, uint256 amount) external returns (bool); } interface IERC721 { function transferFrom(address from, address to, uint256 tokenId) external; } interface IERC1155 { function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; } contract BatchTransfer { // 同时转账ERC-20和ERC-721 function transferERC20And721( address erc20Addr, address erc721Addr, address recipient, uint256 erc20Amount, uint256 nftTokenId ) external { require(IERC20(erc20Addr).transfer(recipient, erc20Amount), "ERC20转账失败"); IERC721(erc721Addr).transferFrom(msg.sender, recipient, nftTokenId); } // 同时转账ERC-20和ERC-1155 function transferERC20And1155( address erc20Addr, address erc1155Addr, address recipient, uint256 erc20Amount, uint256 nftId, uint256 nftAmount, bytes calldata data ) external { require(IERC20(erc20Addr).transfer(recipient, erc20Amount), "ERC20转账失败"); IERC1155(erc1155Addr).safeTransferFrom(msg.sender, recipient, nftId, nftAmount, data); } }
调用聚合合约的Ethers.js示例
const { ethers } = require("ethers"); const provider = new ethers.providers.JsonRpcProvider("你的RPC节点地址"); const signer = new ethers.Wallet("你的私钥", provider); // 部署后的聚合合约地址 const batchTransferAddr = "0x..."; const batchTransferAbi = [ "function transferERC20And721(address erc20Addr, address erc721Addr, address recipient, uint256 erc20Amount, uint256 nftTokenId)" ]; const batchContract = new ethers.Contract(batchTransferAddr, batchTransferAbi, signer); // 转账参数 const erc20Addr = "0x..."; const erc721Addr = "0x..."; const recipient = "0x..."; const erc20Amount = ethers.utils.parseUnits("100", 18); // 假设ERC-20是18位小数 const nftTokenId = 123; async function executeBatchTransfer() { const tx = await batchContract.transferERC20And721( erc20Addr, erc721Addr, recipient, erc20Amount, nftTokenId ); await tx.wait(); console.log("批量转账完成,交易哈希:", tx.hash); } executeBatchTransfer();
方式2:使用通用多调用合约
借助链上通用的多调用合约(如以太坊主网的Multicall),在单笔交易中执行多个独立的合约调用。
Ethers.js调用Multicall示例
const { ethers } = require("ethers"); const provider = new ethers.providers.JsonRpcProvider("你的RPC节点地址"); const signer = new ethers.Wallet("你的私钥", provider); // 以太坊主网Multicall合约地址 const multicallAddr = "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696"; const multicallAbi = [ "function aggregate(tuple(address target, bytes callData)[] calls) returns (uint256 blockNumber, bytes[] returnData)" ]; const multicallContract = new ethers.Contract(multicallAddr, multicallAbi, signer); // 构建调用数据 const erc20Addr = "0x..."; const erc721Addr = "0x..."; const recipient = "0x..."; const erc20Amount = ethers.utils.parseUnits("100", 18); const nftTokenId = 123; // ERC-20 transfer调用数据 const erc20TransferData = new ethers.utils.Interface(["function transfer(address,uint256)"]) .encodeFunctionData("transfer", [recipient, erc20Amount]); // ERC-721 transferFrom调用数据 const erc721TransferData = new ethers.utils.Interface(["function transferFrom(address,address,uint256)"]) .encodeFunctionData("transferFrom", [signer.address, recipient, nftTokenId]); // 多调用数组 const calls = [ { target: erc20Addr, callData: erc20TransferData }, { target: erc721Addr, callData: erc721TransferData } ]; async function executeMulticall() { const tx = await multicallContract.aggregate(calls); await tx.wait(); console.log("多调用完成,交易哈希:", tx.hash); } executeMulticall();
注意事项
- NFT转账前,调用者需拥有NFT所有权,或已通过
approve/setApprovalForAll获得转账授权。 - ERC-20转账需确保调用者余额充足,且合约无转账限制。
- 单笔交易总Gas消耗不能超过区块Gas上限,否则交易会失败。
内容的提问来源于stack exchange,提问作者NoVa
相关产品推荐
相关产品推荐

