(https://ethernaut.openzeppelin.com/level/0x22699e6AdD7159C3C385bf4d7e1C647ddB3a99ea)
/\_/\ /
____/ o o \
/~____ =ø= /
(______)__m_m)
that’s right,這是這關的程式碼,相信各位喵星人一看就知道怎麼過這關,但如果你是地球人,我們來看一下過關說明: 請讓此合約的balance 大於零,程式碼如上...,好的,請喵星人跟我們講解一下這次的任務...
讓一個合約獲得以太的方法歸納起來有三種(假設沒有其他payable function):
- fallback() or receive(): 當有人send or transfer ether過來合約時,會由fallback payable or receive payable來處理。
- mining 目標address:目前我們是可以將mining的獎勵目標設為合約的address,則得到mining獎勵的時候會將以太轉到合約。
- 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);
}
}
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,讓外部有紀錄並得知。