Solidity極簡入門|第二十二講:Call

律动

我最近在重新學 solidity,鞏固一下細節,也寫一個「Solidity 極簡入門」,供小白們使用(程式設計大佬可以另找教程),每周更新 1-3 講。

所有代碼和教程開源在 github: github.com/AmazingAng/WTFSolidity

我們曾在第 17 講:發送 ETH 那一講介紹過利用 call 來發送 ETH,這一講我們將介紹如何利用它調用合約。

Call

call 是 address 類型的低級成員函數,它用來與其他合約交互。 它的返回值為 (bool, data),分別對應 call 是否成功以及目標函數的返回值。

call 是 solidity 官方推薦的通過觸發 fallback 或 receive 函數發送 ETH 的方法。 不推薦用 call 來調用另一個合約,因為當你調用不安全合約的函數時,你就把主動權交給了它。 推薦的方法仍是聲明合約變數后調用函數,見第 19 講:調用其他合約。 當我們不知道對方合約的原始程式碼或 ABI,就沒法生成合約變數;這時,我們仍可以通過 call 調用對方合約的函數。

call 的使用規則

call 的使用規則如下:

其中二進制編碼利用結構化編碼函數 abi.encodeWithSignature 獲得:

函數簽名為「函數名(逗號分隔的參數類型)」。 例如 abi.encodeWithSignature(“f(uint256,address)”, _x, _addr)。

另外 call 在呼叫合約時可以指定交易發送的 ETH 數額和 gas:

看起來有點複雜,下面我們舉個 call 應用的例子。

目標合約

我們先寫一個簡單的目標合約 OtherContract 並部署,代碼與第 19 講中基本相同,只是多了 fallback 函數。

這個合約包含一個狀態變數 x,一個事件 Log 在收到 ETH 時觸發,三個函數:

getBalance(): 返回合約 ETH 餘額。 setX(): external payable 函數,可以設置 x 的值,並向合約發送 ETH。 getX(): 讀取 x 的值。

利用 call 調用目標合約

1. Response 事件

我們寫一個 Call 合約來調用目標合約函數。 首先先寫一個定義 Response 事件,輸出 call 返回的 success 和 data,方便我們觀察返回值。

2. 調用 setX 函數

我們定義 callSetX 函數來調用目標合約的 setX(),轉入 msg.value 數額的 ETH,並釋放 Response 事件輸出 success 和 data:

接下來我們調用 callSetX 把狀態變數_x 改為 5,參數為 OtherContract 位址和 5,由於目標函數 setX() 沒有返回值,因此 Response 事件輸出的 data 為 0x,也就是空。

3. 調用 getX 函數

下面我們調用 getX() 函數,它將返回目標合約_x 的值,類型為 uint256。 我們可以利用 abi.decode 來解碼 call 的返回值 data,並讀出數值。

從 Response 事件的輸出,我們可以看到 data 為 0x0000000000000000000000000000000000000000000000000000000000000005。 而經過 abi.decode,最終返回值為 5。

4. 調用不存在的函數

如果我們給 call 輸入的函數不存在於目標合約,那麼目標合約的 fallback 函數會被觸發。

上面例子中,我們 call 了不存在的 foo 函數。 call 仍能執行成功,並返回 success,但其實調用的目標合約 fallback 函數。

總結

這一講,我們介紹了如何用 call 這一低級函數來調用其他合約。 call 不是調用合約的推薦方法,因為不安全。 但他能讓我們在不知道原始程式碼和 ABI 的情況下調用目標合約,很有用。

免責聲明:本頁面資訊可能來自第三方,不代表 Gate 的觀點或意見。頁面顯示的內容僅供參考,不構成任何財務、投資或法律建議。Gate 對資訊的準確性、完整性不作保證,對因使用本資訊而產生的任何損失不承擔責任。虛擬資產投資屬高風險行為,價格波動劇烈,您可能損失全部投資本金。請充分了解相關風險,並根據自身財務狀況和風險承受能力謹慎決策。具體內容詳見聲明
留言
0/400
暫無留言