原文: 《Solidity 極簡入門: 19. 接收ETH receive 和fallback》

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

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

回調函數

Solidity 支持兩種特殊的回調函數,receive() 和fallback(),他們主要在兩種情況下被使用:

- 接收ETH

- 處理合約中不存在的函數調用(代理合約proxy contract)

我們這一講主要介紹接收ETH 的情況。

接收ETH 函數receive

receive() 只用於處理接收ETH。一個合約最多有一個receive() 函數,聲明方式與一般函數不一樣,不需要function 關鍵字:receive() external payable { ... }

receive() 函數不能有任何的參數,不能返回任何值,必須包含external 和payable。

當合約接收ETH 的時候,receive() 會被觸發。 receive() 最好不要執行太多的邏輯因為如果別人用send 和transfer 方法發送ETH 的話,gas 會限制在2300,receive() 太複雜可能會觸發Out of Gas 報錯;如果用call 就可以自定義gas執行更複雜的邏輯(這三種發送ETH 的方法我們之後會講到)。

我們可以在receive() 裡發送一個event,例如:

WTF Solidity極簡入門第十九講: 接收ETH receive和fallback

有些惡意合約,會在receive() 函數嵌入惡意消耗gas 的內容,使得一些退款合約不能正常工作:Akutar NFT項目因此被永久鎖定了11539 ETH,接近2 億元!因此寫包含退款等邏輯的合約時候,一定要注意這種情況。

回退函數fallback

fallback() 函數會在調用合約不存在的函數時被觸發。可用於接收ETH,也可以用於代理合約proxy contract。 fallback() 聲明時不需要function 關鍵字,必須由external 修飾,一般也會用payable 修飾,用於接收ETH:fallback() external payable { ... }。

我們定義一個fallback() 函數,被觸發時候會釋放fallbackCalled 事件,並輸出msg.sender,msg.value 和msg.data:

WTF Solidity極簡入門第十九講: 接收ETH receive和fallback

receive 和fallback 的區別

receive 和fallback 都能夠用於接收ETH,他們觸發的規則如下:

WTF Solidity極簡入門第十九講: 接收ETH receive和fallback

簡單來說,合約接收ETH 時,msg.data 為空且存在receive() 時,會觸發receive();msg.data 不為空或不存在receive() 時,會觸發fallback(),此時fallback () 必須為payable。

receive() 和payable fallback() 均不存在的時候,向合約發送ETH 將會報錯。

總結

這一講,我介紹了Solidity 中的兩種特殊函數,receive() 和fallback(),他們主要在兩種情況下被使用,他們主要用於處理接收ETH 和代理合約proxy contract。

推特: @0xAA_Science

社區: Discord微信群官網wtf.academy

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