簡體   English   中英

動態調用 solidity function,基於它的 bytes4 function 選擇器

[英]Call solidity function dynamically, based on its bytes4 function selector

在智能合約中,假設我有一個 function,它想根據一些內部邏輯動態調用另一個 function。 在這里它獲得 function 選擇器作為bytes4變量。

之后可以使用分支邏輯來調用目標函數之一。 見:(一)

但是,是否可以避免這種情況並直接調用 function 選擇器? 參見: (B)

function myDynamicFunc(uint256 someParam) public {
    bytes4 selector = /* ... some internal logic ... */

    if (selector == this.myFuncA.selector) {
      myFuncA(someParam);
    } else if (selector == this.myFuncB.selector) {
      myFuncB(someParam);
    }
    // (A) instead of something like this ^ branching logic (which works)

    selector.invoke(someParam);
    // (B) can something like this ^ instead by calling the selector directly instead (does not work)
}


細節

  • myDynamicFuncpublic的, myFuncA + myFuncB也是public的。
  • 所有 3 個功能都在同一個智能合約中實現。

筆記

我寫了一個答案,擴展了@kj-crypto在評論中的建議。 如果有另一種方法可以在使用address(this).call(...)的情況下完成上述操作,我洗耳恭聽!

關於B選項:

  • 使用call將返回一個字節 object,然后您應該將其轉換為適當的類型,在本例中為 integer。(額外的 gas 使用)
  • 要使用call ,您需要打包選擇器和參數(額外的 gas 使用)

只要你在同一個合約中使用 function,就沒有必要使用它的 abi 規范,因為你現在已經知道 function 在哪里,它是如何定義的,你可以毫不費力地調用它。

擴展@kj-crypto上面的評論

你的意思是像address(this).call(abi.encodePacked(selector, <func-args>))嗎?

...並創建了這個實現:

  function myDynamicFunc(uint256 someParam)
    public
    // pure // --> (1)
    returns (bytes memory result) // --> (2)
  {
    bytes4 selector =
      /* ... some internal logic ... */
      this.myFuncA.selector;

    (bool success, bytes memory resultBytes) =
      address(this).call(abi.encodePacked(selector, someParam));

    require(success, "failed to call selector"); // --> 3
    result = resultBytes;
  }

總而言之,答案是:“是的,這是可能的,但不,這不是一個好主意。”

原因:

(1) - 如果您需要 function 是pure的,不幸的是,它不能是純的,因為address(this).call(...)可能會修改 state。

(2) - 返回類型將默認為bytes memory ,因為這是address(this).call(...)的返回類型。 您可以轉換它,但這會增加代碼的復雜性,這與最初的動機背道而馳。

(3) - 要正確處理address(this).call(...) ,需要對元組中返回的bool做一些事情。 例如使用require() 這也違背了最初的動機,因為它只是將分支邏輯從一種形式轉移到另一種形式( if... elserequire() ),並且在那個時候更昂貴。

(4) - 總的來說,原始 function 的 gas 成本似乎低於建議的形式,因此更有優勢。 請注意,這尚未通過實驗驗證,如果有人想給它一個 go,這里是( 完整的 solidity 文件)。

selector是 bytes4 類型,沒有方法調用 function 或調用 function。

bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));

或者它是返回數據值:

  nonPayableAddress.call(abi.encodeWithSignature("transfer(address,uint256)", 0xaddress, amount))

唯一可以使用selector調用另一個合約的 function 的是

(bool success, bytes memory data) = contractAddress.call(
        abi.encodeWithSelector(SELECTOR, to, value)
    );

call, delegateCall, callcode方法可用於地址類型, transfersend方法可用於支付地址類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM