ERC20代币转账异常技术求助:调用createTransaction函数时代币转入合约地址而非指定钱包地址
解决ERC20代币错转入合约地址的问题
嘿,我仔细看了你的代码和问题描述,马上就找到了导致代币没到目标地址反而流入合约的核心问题,咱们一步步拆解修复:
问题根源分析
1. 转账逻辑完全搞反了,还缺目标地址
你的Transaction结构体里根本没定义代币要转到的目标地址,而且当前代码里的transactionDetails.token.transfer(...)是让合约自己作为发起方转代币,转到的还是wallet_address(也就是调用initializeProfile的那个地址)。但你的需求明明是让用户调用createTransaction时,把自己的代币转到指定目标——这相当于你写了个让合约“自导自演”转代币的逻辑,自然会出现代币先流入合约的情况(如果用户给合约授权了额度的话)。
2. 没用到安全的ERC20操作方法
你导入了OpenZeppelin的SafeERC20库但没用上,普通的transfer/transferFrom在遇到非标准ERC20代币时可能静默失败,排查问题会特别头疼。
修复后的完整代码
我给你调整了逻辑,加了必要的字段,还用了安全方法:
pragma solidity ^0.8.10; // SPDX-License-Identifier: MIT import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract TransactionContract { using SafeERC20 for IERC20; // 让IERC20对象可以直接调用SafeERC20的安全方法 enum TransactionType { payment, donation } struct Transaction { string description; TransactionType transaction_type; IERC20 token; uint256 exchange_rate; uint256 amount; uint256 converted_amount; string remarks; address recipient; // 新增:代币要转到的目标地址 } string public display_name; address public wallet_address; string[] public transaction_list; mapping(string => Transaction) public transactions; function initializeProfile(string memory displayName) public { display_name = displayName; wallet_address = msg.sender; } function createTransaction(string memory transactionID, Transaction memory transactionDetails) payable public { // 验证ETH转账金额(如果你的业务逻辑需要的话) require(msg.value >= transactionDetails.converted_amount, "ETH amount not enough"); // 关键修复:用safeTransferFrom从调用者账户转代币到目标地址 transactionDetails.token.safeTransferFrom( msg.sender, transactionDetails.recipient, transactionDetails.converted_amount ); transactions[transactionID] = transactionDetails; transaction_list.push(transactionID); } }
关键修复点说明
- 新增
recipient字段:现在你可以在transactionDetails里指定代币要转到的目标钱包地址了,这是之前缺失的核心信息。 - 切换到
safeTransferFrom:这个方法会直接从调用createTransaction的用户(msg.sender)账户里扣代币,转到目标地址。注意:用户在调用这个函数之前,必须先给合约授权对应额度的ERC20代币——也就是先调用代币合约的approve方法,授权你的TransactionContract可以操作自己的代币。 - 启用
SafeERC20库:通过using SafeERC20 for IERC20让代币对象直接调用安全方法,避免非标准代币带来的静默失败问题。
必做前置操作
用户在调用createTransaction之前,必须先执行授权:
// 用户端需要执行的授权示例(用web3/ethers.js都可以) await tokenContract.approve(addressOfYourTransactionContract, amountToTransfer);
这样调整后,代币就会从用户钱包直接转到你指定的目标地址,再也不会流入合约啦!
内容的提问来源于stack exchange,提问作者Raven Dorado
相关产品推荐
相关产品推荐

