Ethernaut – level 7 : Force

(https://ethernaut.openzeppelin.com/level/0x22699e6AdD7159C3C385bf4d7e1C647ddB3a99ea)

         /\_/\   /
    ____/ o o \
  /~____  =ø= /
 (______)__m_m)

that’s right,這是這關的程式碼,相信各位喵星人一看就知道怎麼過這關,但如果你是地球人,我們來看一下過關說明: 請讓此合約的balance 大於零,程式碼如上...,好的,請喵星人跟我們講解一下這次的任務...

讓一個合約獲得以太的方法歸納起來有三種(假設沒有其他payable function):

  1. fallback() or receive(): 當有人send or transfer ether過來合約時,會由fallback payable or receive payable來處理。
  2. mining 目標address:目前我們是可以將mining的獎勵目標設為合約的address,則得到mining獎勵的時候會將以太轉到合約。
  3. selfdestruct(address): 某個合約自我燒毀的時候,可以將剩餘價值轉給某個合約或錢包。

因為這題的程式沒有任何程式碼,因此看來我們只能用上述的2或3的方法,我們選擇2,阿,不,挖來的錢我要放在我的錢包,還是選擇3好了。

首先用Remix 創建一個”類force.sol”如下程式碼(記得consturctor 為payable,並設定value > 0,讓合約的value>0,則selfdestruct時才有錢轉出去,同時記得寫要進行selfdestruct的函數,將selfdestruct(address)中的address設為此關instance)

pragma solidity ^0.6.0;

contract aForce {

    constructor() public payable {
    }


    function destory(address payable _target) public {
            selfdestruct(_target);
    }

}
constructor為payable or funciton 為payable時,使用VALUE欄位輸入value值。

depoly,執行,回ethernaut submit,喵。

另外補充幾個知識點,首先可以另外寫一隻如下的function,來看看我們的contract目前的balance是多少,需要注意的是view這個修飾詞,若沒有這個修飾詞,則不會返回return的值(會被ignore掉)。

另外,除了用contractor 寫上payable,然後deploy時輸入value>0這樣的方式,也可以另外寫一隻如下collect()的payable函式,並一樣於呼叫函數的時候在value的欄位輸入即可。

function showBalance() public view returns(uint){
    return address(this).balance;
}

function collect() public payable {}  //或是如下
function collect(uint _amount) public payable{
    value=_amount;
}

之後,可以在Ethernaut的網頁的console上輸入await web3.eth.getBalance(instance),就可以知道目前level instance 是否有value了 (當selfdestruct完成後可以來查看是否完成)。

*takeaways:

  • 即使你是contract的owner,你也無法完全控制contract的balance,畢竟有人硬要送錢來擋都擋不住。所以建議不要使用類似 address(this).balance == 0 這樣的判斷句來做為行動的依據,因為這是不可控的。
  • 如果用了selfdestruct()函數,建議要檢查msg.sender = owner (可以使用modifier OnlyOwner etc.),並且emit an event,讓外部有紀錄並得知。