特殊函數

Yan Ru Su

receive() and fallback()

合約裡的特殊函數,用來應對一些特殊情況,宣告的時候不用加 function。

receive()

專門用來接收 ETH ,只處理有值沒有 data 的情況,宣告不用加 function 但ㄧ定要有 external 跟 payable,不能有引數,不能有回傳值。

1
receive() external payable{}

fallback()

處理當data function selector 對不上 contract 內 function 的情況,一定要加 external ,要收款要記得加 payable , solidity > 0.8.1 可以有引數跟回傳值。

1
fallback() external {}

fallback其中一個用途是代理合約 proxy contract。

代理合約

代理合約是固定一個地址不動,不過所有的呼叫會進到 fallback, fallback 會指向另一個合約再去用其他 contract 的邏輯,不過最終的 data 是存在 proxy contract,這樣可以做到主要一個地址不換,如果要 upgrade contract 只要重新指向一個新 address 即可。

觸發特殊函數的邏輯

有 value → 看有沒有data
有 data → fallback()
沒有 data → 看有沒有 receive
有 receive → receive()
沒 receive→ fallback()

如果 input data & value 都有,合約也 fallback & receive 都有,最終是會跑哪一個?

有 data, function selector 對不上直接進 fallback()。

transfer and send

transfer() 和 send() 是 Solidity 中用來發送 ETH 的內建方法
會傳送一筆只有 value 但沒有 data 的 Tx,邏輯上會優先進到 receive(),但如果沒有 receive(),會到 payable fallback()。

1
2
Address.transfer(amount);
Address.send(amount);

兩個的差別是 transfer 會直接 revert , send 只會回傳 bool。如果轉帳 function 裡有其他邏輯 bool 會需要額外處理,避免自行設計的紀錄已經減少但轉帳失敗。

transfer and send 的問題

transfer and send 只能提供給 2300 gas 給接收方合約使用,所以如果 receive 或 fallback 裡的邏輯過於複雜,操作過多消耗太多 gas 就會失敗,交易失敗就會被revert。

call

1
Address.call{value: ,gas: }("data");

因應transfer and send 只能提供 2300gas 的限制,要使用沒有限制的 call。
回傳值是bool(代表成功失敗)跟 bytes(函數的回傳值)

發送 ETH 的三種方式安全性對比: transfer, send, call

method gas limit tx fail
transfer 2300 revert
send 2300 return false
call non return false

transfer 會直接 revert 不用作後續處理,send 只會回傳 bool 但要做另外處理,可是他們的 gas 只有 2300 沒辦法執行複雜合約,這兩個 function 的安全性相比應該是 transfer >send。因爲 transfer 會直接 revert。

call,return bool,沒有 gas 限制,但視合約本身安全性可能會面對重入攻擊( B 合約先向 A 合約提一次錢收到之後在 receive() 又提一次,如果 A 合約是先轉帳後改狀態就會被重複扣款),transfer 與 send 有 gas 限制就沒辦法在合約裡做那麽多複雜的操作。因此 call 的安全性 < transfer 跟 send,不過優勢在於call 有 gas 的靈活度。
總體安全性 transfer > send > call,但考慮複雜度 transfer 跟 send 很可能就用不了。

沒有 receive() 是否就無法接收 ether 了,如果不是,可以透過哪些方法

  1. fallback() 加 payable
  2. 自定義其他 function 寫 payable
  3. selfdestruct(addr) 強制發送ETH,不論有沒有 receive fallback payable