Transfer
向合約發送餘額失敗
我在玩ethernaut,山丘之王。我做了一個練習目標契約和一個進攻契約。我想向攻擊合約發送價值(這可行),然後我想將攻擊合約的餘額發送給實踐目標合約(這失敗)。我可以將餘額發送到零地址,但不能發送到這個練習目標,所以我認為問題在於我如何編寫練習目標。我在這裡的其他執行緒中讀到它需要一個應付的備份或接收功能,但不管有沒有這些,它都會失敗。這是練習目標:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract practice { uint public amount; event paid(uint amount); event received(uint amount); receive() external payable { emit received(msg.value); amount += msg.value; } fallback() external payable { emit paid(msg.value); amount += msg.value; } }
這是攻擊合約:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract King { uint public amount; address public target; constructor() payable { amount += msg.value; } event attempt(uint amount, address sender); event fallbackCalled(uint amount, address sender); event valueAdded(uint amount, address sender); event successfulTransfer(uint amount); event failed(uint amount); function setTarget(address _target) public { target = _target; } function addValue() public payable { emit valueAdded(msg.value, msg.sender); amount += msg.value; } function sendBalance() public { emit attempt(address(this).balance, msg.sender); bool success = payable(target).send(address(this).balance); if (success) { emit successfulTransfer(address(this).balance); amount = 0; } if (!success) emit failed(address(this).balance); } }
不確定這是否重要,但我正在通過 remix injection web3 在 rinkeby 網路上對其進行測試。
這裡的問題是
payable(target).send()
. 這是因為send()
氣體限制為 2,300,這幾乎足以記錄一個事件。但由於該receive()
函式包含狀態改變操作,send()
會因gas overrun而失敗。您可以改為使用
target.call{value: address(this).balance}("")
將 ETH 發送到目標合約。與ethernaut一切順利!