Erc-20

為什麼 SafeERC20 會假設代幣的 transfer 和 transferFrom 返回值是可選的?

  • October 7, 2022

在 openZeppelin 的 SafeERC20 中,函式safeTransfersafeTransferFrom呼叫一個內部函式,它對令牌和函式_callOptionalReturn進行低級呼叫,並檢查返回值是否為真,如果有返回值transfer``transferFrom

這是程式碼

/**
* @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不是總是transfer有一個布爾返回值transferFrom嗎?這是ERC20 標準中定義的內容,也是本契約引用的IERC20 介面中定義的內容。

快速回答:並不總是有返回值。

長答案:

雖然它不完全符合 ERC20,但有很多 ERC20 代幣不會返回任何東西。相反,它們只是像BadERC20Token以下範例中那樣建構:

contract FullCompliantERC20Token {
 function transfer() returns (bool) { return true; }
}

contract BadERC20Token {
 function transfer() {}
}

假設您transfer在 DEX 中對 -function 執行外部函式呼叫,並且您希望該函式返回一個布爾值,那麼如果此函式在該呼叫之前已存在於記憶體中,則此返回值中可能存在一些垃圾沒有顯式返回值。這是可能的,因為函式的返回值不是實際函式選擇器的一部分!因此,transfer()沒有返回值的函式和函式transfer() returns(bool)具有相同的函式選擇器,儘管它們仍然不同。它們將以相同的方式執行,但在非返回值版本中,返回值將包含隨機垃圾並導致錯誤。

實際上這是自 2017 年拜占庭硬分叉以來的一個大問題。在此之前,返回值是來自函式呼叫本身的常量值,但自從拜占庭以來,返回值有點隨機,會導致錯誤甚至安全問題。

為了真正檢查傳遞函式是否真的有意返回布爾值,唯一的機會是檢查 RETURNDATASIZE,它是由 Byzantinum fork 發明的 EVM 操作碼。

這發生在SafeERC20:它只是檢查布爾返回值是否存在。僅當返回值存在時,它才會評估該值並恢復或不恢復。通過這種方式,它為呼叫合約提供了更高的可靠性和安全性。

好吧,如您所見,該函式被呼叫_callOptionalReturn。儘管標準規定需要返回值,但某些合約可能會認為 ERC20 代幣就像叢林,你可以做任何你想做的事情,並且:不要在其傳輸函式中返回 bool 值。

因此,如果您希望 bool 返回但該函式不返回任何內容,則可能會發生不好的事情,例如訪問您不打算訪問的記憶體。

如需進一步閱讀,您可以查看此處: https ://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca

引用自:https://ethereum.stackexchange.com/questions/137049