Solidity

呼叫和僅使用函式有什麼區別?

  • January 3, 2022

假設我有一個名為 的契約contractA

它具有以下功能:

function bla(address test) {
   // way 1. test.call(abi.encodeWithSignature("first4bytes", arg1, arg2))
   // way 2. testAddrInterface(test).functName()
}

如您所見,在方式 2 的範例中,我只是使用了介面,以便可以functName直接呼叫它,而不是使用方式 1。

我見過很多人們使用方式 1 的地方。為什麼?方式2有什麼問題?如果您告訴我方式 2 包含更多程式碼並且成本更高,我會問:介面是否仍包含在最終程式碼中,這是方式 1 更好的唯一原因嗎?

更重要的區別是,如果funcName恢復,那麼案例 2bla也將恢復。

對於案例 2,呼叫返回一個布爾值,指示呼叫是否失敗,並且可以忽略失敗。

使用原始呼叫是低級的,不鼓勵使用,因為它很容易出錯。從 solc 0.6 開始,您可以使用try/catch

   try myContract.funcName(param1, param2, ..) returns (uint retValue) {
       /* Do something with retValue */
   } catch Error(string memory err) {
       /* Do something with the error message and revert */
   }

案例 1 是唯一選擇的另一個地方是在進行任意呼叫時,因為在編譯時您不知道函式名稱或參數,例如代理合約、多重簽名錢包等。

實際上,沒有區別。

使用介面提供了對使用的參數的編譯時安全檢查。並以同樣的方式簡化了返回值的使用。

這是一個快速、簡單的範例,但基本上這些程式碼行是等價的。

<Type> returnTuple = address.call( <payload as byyes> );

<Type> returnTuple = address.call( abi.encodeWithSelector( <Function Selector>, <Arguments . . .>);

<Type> returnTuple = address.call( abi.encodeWithSignature( <Function Selector string>, <Arguments . . .>);

<Type> returnTuple = address.f( <arguments> );

如果返回元組不合適,所有都將恢復。使用 call 時,您通常會接受原始字節。然後從那裡開始使用它。例如返回、轉發或解析。

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