首页 > 解决方案 > 通过合约发送代币时出现 SafeMath 错误

问题描述

在尝试通过合约发送代币时,我遇到了错误消息:“SafeMath:减法溢出。”

最初我只使用了传输功能。但是,正如我认为 msg.sender 只需将其令牌发送给其他用户(通过松露控制台,这没有问题)。然而,阅读 [this] 我得到的印象实际上是合约地址成为了 TokenContract 中的 msg.sender。因此,(仅作为账户而不是合约本身)我认为我必须先向合约发送代币,然后批准合约允许代表 msg.sender 发送代币,然后再转账。但是,我一直遇到 SafeMath 错误。

TokenContract(不是下面的接口)实现了我的代码最简单的版本如下:

contract ContractA {

    function pay () public returns (bool) {

        TokenContract tk = TokenContract("tokenContractAddress");
        tk.transferFrom(msg.sender, address(this), 5);
        tk.approve(address(this), 5);
        tk.transfer("someAccount", 5);

        return true;
    }
}

interface TokenContract {
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transfer(address recipient, uint256 amount) external returns (bool);   
}

contract TokenContract is ERC20, ERC20Detailed {
    constructor() ERC20Detailed("Token", "TKN", 18) public {
        _mint(msg.sender, 1000);
    }
}

显然,我不希望出现 safeMath 错误。当我转帐并批准时。我只是期望与使用松露控制台时相同的行为。

标签: tokenethereumsolidity

解决方案


我假设地址调用ContractA没有为合同设置津贴。

要求:
* 调用者必须sender至少有 ' 的代币amounthttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0/contracts/token/ERC20/ERC20.sol

    /**
     * @dev See `IERC20.transferFrom`.
     *
     * Emits an `Approval` event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of `ERC20`;
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `value`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
        return true;
    }
  1. 合约 Aapprove的调用者作为代币的津贴
  2. Caller of Contract A 调用pay函数,transferFrom在先前设置的允许范围内将调用从用户转移到接收者。

如果您正在创建 ERC20 代币,您可能需要查看 OpenZeppelin Contracts 实现,看看这是否满足您的需求。有关详细信息,请参阅文档:https ://docs.openzeppelin.com/contracts/2.x/tokens#ERC20

如果您要转移各种 ERC20 代币,您可能需要考虑使用 SafeERC20 包装器进行这些调用:https ://docs.openzeppelin.com/contracts/2.x/api/token/erc20#SafeERC20

如果您需要 ERC20 的接口,您可能希望使用 IERC20:https ://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20

作为 ERC20 的替代方案,您可以考虑创建 ERC777 代币(无需在两个单独的交易中进行批准和 transferFrom)。有关详细信息,请参阅文档:https ://docs.openzeppelin.com/contracts/2.x/tokens#ERC777

如果您对使用 OpenZeppelin 有任何疑问,可以在社区论坛中提问:https ://forum.openzeppelin.com/

披露:我是 OpenZeppelin 的社区经理


推荐阅读