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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 22:48:21