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 認可其觀點表述,也不得被視為財務或專業建議。詳見聲明
  • 讚賞
  • 留言
  • 轉發
  • 分享
留言
0/400
暫無留言
交易,隨時隨地
qrCode
掃碼下載 Gate App
社群列表
繁體中文
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)