原文: 《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,例如:
有些惡意合約,會在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:
receive 和fallback 的區別
receive 和fallback 都能夠用於接收ETH,他們觸發的規則如下:
簡單來說,合約接收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