Requirements: basic understanding of constructors in Solidity.
The challenge 📄
Claim ownership of the following contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import 'openzeppelin-contracts-06/math/SafeMath.sol';
contract Fallout {
using SafeMath for uint256;
mapping (address => uint) allocations;
address payable public owner;
/* constructor */
function Fal1out() public payable {
owner = msg.sender;
allocations[owner] = msg.value;
}
modifier onlyOwner {
require(
msg.sender == owner,
"caller is not the owner"
);
_;
}
function allocate() public payable {
allocations[msg.sender] = allocations[msg.sender].add(msg.value);
}
function sendAllocation(address payable allocator) public {
require(allocations[allocator] > 0);
allocator.transfer(allocations[allocator]);
}
function collectAllocations() public onlyOwner {
msg.sender.transfer(address(this).balance);
}
function allocatorBalance(address allocator) public view returns (uint) {
return allocations[allocator];
}
}
Studying Fallout.sol
👩🏫👨🏫
Similarly to the contract from the previous challenge, Fallout.sol
is a fundraiser. People are allowed pledge and unpledge ether whenever they want and the owner of the contract can withdraw funds.
This contract uses a version of Solidity < v0.8.x
. This means the contract is prone to underflow and overflow. To protect the arithmetic operations the contract implements the SafeMath
library from OpenZeppelin and attaches the functions from this library to the uint256
type.
State Variables:
-
allocations
: keeps track of the amount deposited by each allocator. -
owner
:address
of the current owner of the contract. Thisaddress
is marked aspayable
enabling the account to receive ether from the contract.
Functions:
-
Fal1out
: theconstructor
of the contract. Setmsg.sender
asowner
and themsg.value
send during deployment as theallocation
for the deployer. -
allocate
: method used to deposit ether in the contrac. -
sendAllocation
: method allocators can use to withdraw their allocation. -
collectAllocation
: callable method by theowner
to withdaw the entire balance in the contract. -
allocatorBalance
: reads the amount deposited byallocator
.
Hacking Fallout.sol
💣💣
This challenge was a little tricky for me because after inspecting the contract, the Fal1out
function with the /* constructor */
comment looked weird to me.
When I started learning Solidity, the language was well beyond v0.8.x
and I did not know the syntax to declare a constructor
in older versions, specifically before v0.4.22
.
From the Solidity docs:
Prior to version 0.4.22, constructors were defined as functions with the same name as the contract. This syntax was deprecated and is not allowed anymore in version 0.5.0.
Fal1out
was intended to be the constructor
of the contract but due a typo while writing it, the function is never called automatically because it's not recognized as a constructor and so the contract is not initialized at creation time.
Fal1out
ended up being compiled as a public
function accessible by any EOA to call it and claim the ownership of the contract and to gain access to the balance in the contract.
After that brief explanation, it should be straightforward claiming the ownership of Fallout
.
In your dev tools call the Fal1out
method:
await contract.Fal1out()
After the transaction is mined, verify you own the contract:
await contract.owner() // should return your address
Conclusion ⚡️
Creating a more robust syntax to declare a constructor
is one on the many changes implemented by the core devs to make Solidity a more robust and safe language.
Despite the effort of the core devs, typos can still lead to lose of funds or unusable code, we should always try our best on reading our code before deploying it.
Further reading 🧟♀️🧟
- Solidity docs: Constructors
- SWC-118
Top comments (0)