首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么SafeERC20假定令牌的传输和transferFrom返回值是可选的?

为什么SafeERC20假定令牌的传输和transferFrom返回值是可选的?
EN

Ethereum用户
提问于 2022-10-07 16:03:58
回答 2查看 744关注 0票数 3

在openZeppelin的SafeERC20中,函数safeTransfersafeTransferFrom调用一个名为_callOptionalReturn的内部函数,该函数对令牌的transfertransferFrom函数进行低级调用,并检查返回值是否为真。

这是代码

代码语言:javascript
复制
/**
 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
 * on the return value: the return value is optional (but if data is returned, it must not be false).
 * @param token The token targeted by the call.
 * @param data The call data (encoded using abi.encode or one of its variants).
 */
function _callOptionalReturn(IERC20 token, bytes memory data) private {
    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
    // the target address contains contract code and also asserts for success in the low-level call.

    bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
    if (returndata.length > 0) {
        // Return data is optional
        require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }
}

为什么要检查返回值?对于ERC20、transfertransferFrom,不是总是有一个布尔返回值吗?

这是在ERC20 20标准中定义的,也是在这个契约引用的IERC20 20接口中定义的。

EN

回答 2

Ethereum用户

发布于 2022-10-07 19:24:38

快速回答:并不总是有一个返回值。

长答案:

虽然它并不完全符合are 20,但是有很多are 20标记不返回任何东西。相反,在下面的示例中,它们只是像BadERC20Token一样构建:

代码语言:javascript
复制
contract FullCompliantERC20Token {
  function transfer() returns (bool) { return true; }
}

contract BadERC20Token {
  function transfer() {}
}

假设您在DEX中执行对transfer-function的外部函数调用,并且您希望该函数返回一个布尔值,那么如果该函数没有显式返回值,则该返回值中可能有一些垃圾存在于该调用之前的内存中。这是可能的,因为函数的返回值不是实际函数选择器的一部分!因此,没有返回值的函数transfer()和函数transfer() returns(bool)具有相同的函数选择器,尽管它们仍然不同。它们将以同样的方式执行,但在不返回值的版本中,返回值将包含随机垃圾并导致错误。

实际上,这是一个大问题,因为拜占庭硬叉子在2017年。在此之前,返回值是函数调用本身的一个常量值,但由于Byzantinum返回值是随机的,因此会导致错误,甚至安全问题。

为了真正检查传递函数是否真的有意返回布尔值,唯一的机会是检查RETURNDATASIZE,这是一种EVM操作码,它是用Byzantinum叉发明的。

这是在SafeERC20中发生的:它只是检查,是否存在布尔返回值。只有当返回值存在时,它才会计算这个值,或者恢复或不恢复。这样可以使呼叫合同更可靠、更安全。

票数 6
EN

Ethereum用户

发布于 2022-10-07 19:21:40

如您所见,这个函数名为_callOptionalReturn。尽管标准指定需要返回值,但一些契约可能认为ERC20令牌就像丛林一样,您可以随心所欲地做任何事情,并且:不要在它们的传递函数中返回bool值。

因此,如果您期望一个bool返回,但是该函数没有返回任何内容,那么可能会发生一些糟糕的事情,比如访问您不打算访问的内存。

要进一步阅读,您可以在这里查看:https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca

票数 1
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/137049

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档