Ropsten测试网使用Metamask与Remix向合约转DAI异常求解
Ropsten测试网DAI代币向合约转账异常修复
原有代码问题根因
- 方法1逻辑完全不符合ERC20调用规范:使用
abi.encodePacked直接拼接函数字符串无法生成正确的4字节函数选择器,实际没有触发DAI合约的转账逻辑,异常转出的无名代币是错误调用触发fallback逻辑产生的无效通证。 - 方法2权限逻辑错误:在合约内调用
token.approve(address(this), amount * 2)是合约自身给自己授权,不具备任何实际效力。transferFrom执行的前提是用户本人通过DAI合约给当前存款合约开放对应额度的授权,没有用户授权的情况下节点模拟执行会直接抛出allowance不足的回滚错误,导致Remix gas估算失败。 - 额外隐藏问题:导入的
@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol是适配旧版本Solidity的可升级合约包,和0.8+版本内置溢出检查的语法不兼容;且代码中amount = 10没有考虑ERC20精度,DAI为18位小数,10个完整DAI对应的最小单位值为10 * 10^18,直接写10实际仅转账0.00000000000000001 DAI,金额远小于预期。
修正后可运行代码
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Ropsten测试网DAI合约地址:0xaD6D458402F60fD3Bd25163575031ACDce07538D import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; contract DAI_txn { using SafeERC20 for IERC20; IERC20 public immutable token; // 10个完整DAI,按18位精度换算为最小单位 uint256 public constant depositAmount = 10 * 10**18; constructor(address _token) { token = IERC20(_token); } /** * @dev 标准授权转账方式:用户提前给本合约授权对应额度后调用 */ function deposit_DAI() external returns (bool) { // safeTransferFrom 会自动校验转账返回值,失败直接回滚 token.safeTransferFrom(msg.sender, address(this), depositAmount); return true; } /** * @dev 签名免授权转账方式(适配支持EIP-2612的ERC20代币,含Ropsten DAI) * @param deadline 签名有效期区块时间戳 * @param v/r/s 用户离线生成的授权签名参数 */ function deposit_DAI_With_Permit(uint256 deadline, uint8 v, bytes32 r, bytes32 s) external returns (bool) { // 通过链下签名完成授权,不需要用户提前发送approve交易 IERC20Permit(address(token)).permit( msg.sender, address(this), depositAmount, deadline, v, r, s ); token.safeTransferFrom(msg.sender, address(this), depositAmount); return true; } /** * @dev 查询合约持有的DAI余额 */ function balance() external view returns (uint256) { return token.balanceOf(address(this)); } }
操作说明
- 使用标准
deposit_DAI方法前,必须先由用户本人调用DAI合约的approve方法,参数为当前部署的DAI_txn合约地址、授权额度不小于depositAmount,等授权交易链上确认后再调用存款方法,即可正常完成转账,不会出现gas估算错误。 - 禁止使用低阶call拼接字符串的方式调用ERC20合约方法,如需生成调用数据应使用
abi.encodeWithSignature传入正确的函数签名和参数,否则会出现调用逻辑异常。 - ERC20的approve权限仅属于代币持有者本人,合约无法代替用户完成授权操作,这是ERC20标准的基础权限约束。
内容的提问来源于stack exchange,提问作者shush
相关产品推荐
相关产品推荐

