Install MetaMask. Switch to the Ropsten test network. Get some Ropsten ether. Clicking the “buy” button in MetaMask will take you to a faucet that gives out free test ether. After you’ve done that, press the red button on the left to deploy the challenge contract.
You don’t need to do anything with the contract once it’s deployed. Just click the “Check Solution” button to verify that you deployed successfully.
1 2 3 4 5 6 7 8
pragma solidity ^0.4.21;
contract DeployChallenge { // This tells the CaptureTheFlag contract that the challenge is complete. functionisComplete() public pure returns (bool) { returntrue; } }
This challenge introduces how a smart contract is deployed since the ropsten network is depreciated I am using the local Ganache network with brownie framework to deploy and interact with the contracts.
It’s time to set your Capture the Ether nickname! This nickname is how you’ll show up on the leaderboard.
The CaptureTheEther smart contract keeps track of a nickname for every player. To complete this challenge, set your nickname to a non-empty string. The smart contract is running on the Ropsten test network at the address 0x71c46Ed333C35e4E6c62D32dc7C8F00D125b4fee.
// Relevant part of the CaptureTheEther contract. contract CaptureTheEther { mapping(address => bytes32) public nicknameOf;
functionsetNickname(bytes32 nickname) public { nicknameOf[msg.sender] = nickname; } }
// Challenge contract. You don't need to do anything with this; it just verifies // that you set a nickname for yourself. contract NicknameChallenge { CaptureTheEther cte; address player;
// Your address gets passed in as a constructor parameter. functionNicknameChallenge(address _player, address _cte) public { player = _player; cte = CaptureTheEther(_cte); }
// Check that the first character is not null. functionisComplete() public view returns (bool) { return cte.nicknameOf(player)[0] != 0; } }
To complete this challenge, we need to choose a nickname by calling the setNickname() function with our nickname as the argument.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
from brownie import CaptureTheEther, NicknameChallenge, accounts
defmain(): deployer = accounts[0] player = accounts[1]
functionGuessTheNumberChallenge() public payable { require(msg.value == 1 ether); }
functionisComplete() public view returns (bool) { returnaddress(this).balance == 0; }
functionguess(uint8 n) public payable { require(msg.value == 1 ether);
if (n == answer) { msg.sender.transfer(2 ether); } } }
To complete this challenge, we need to guess the answer, but the answer is hardcoded inside the contract, and it is 42, so we can complete this challenge just by calling the guess() function with the number 42 as the argument.
1 2 3 4 5 6 7 8 9 10 11 12 13
from brownie import GuessTheNumberChallenge, accounts
defmain(): deployer = accounts[0] player = accounts[1]
functionGuessTheSecretNumberChallenge() public payable { require(msg.value == 1 ether); } functionisComplete() public view returns (bool) { returnaddress(this).balance == 0; }
functionguess(uint8 n) public payable { require(msg.value == 1 ether);
if (keccak256(n) == answerHash) { msg.sender.transfer(2 ether); } } }
To complete this challenge, we need to guess the answer. Unlike the previous challenge, here, the answer hash is hardcoded instead of the answer, and it is almost impossible to crack the hash and get the answer. However, we can observe that the guess() function takes uint8 as the argument, which means the answer range lies between 0-256, which can be brute-forced. So to solve this challenge, we can brute-force the answer and check with hash to get the answer and pass it to the guess() function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from brownie import GuessTheSecretNumberChallenge, accounts, web3
defmain(): deployer = accounts[0] player = accounts[1]
functionisComplete() public view returns (bool) { returnaddress(this).balance == 0; }
functionguess(uint8 n) public payable { require(msg.value == 1 ether);
if (n == answer) { msg.sender.transfer(2 ether); } } }
To complete this challenge, we need to guess the random number generated by the contract. One thing to remember is that an Ethereum virtual machine is a deterministic machine that cannot generate pseudorandom numbers inside the contract. If it does generate a random number, then the miner gets the advantage of executing the transaction multiple times until he gets a random number of his desire and then includes the transaction in the blockchain. This is an unfair advantage for the miner and contradicts the basic concept of decentralisation. However, the contract uses the blockhash of the previous block and the time to get the random number and stores it in the contract. Since all the storage in a smart contract is public, we can read the number and pass it to the guess() function to solve this challenge.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
from brownie import GuessTheRandomNumberChallenge, accounts, web3
defmain(): deployer = accounts[0] player = accounts[1]
if (n == answer) { msg.sender.transfer(2 ether); } } }
This contract calculates the random number in the same way as the last challenge, but this contract does not store the number. However, the blockhash and timestamp are public. We can calculate the random number and call the contract simultaneously so that the guess and the answer match.
In this challenge, we need to lock a guess using the lockInGuess() function, and use the settle() function to evaluate the guess, this time the range is narrowed down to only 10 numbers, so I just passed 0x05 to the lockInGuess() function and waited for the block which gives 5 when the random number is calculated inside the contract and then called settle() function to complete the challenge.
This challenge is very similar to the last challenge. However, this challenge uses only the block.blockhash() function to generate the random number since block.blockhash() gives only block hashes of the last 256 blocks. If we wait for 256 blocks, the function returns 0, which results in the answer being 0, so we can pass 0 to the lockInGuess() function and wait for 256 blocks to complete and then call the settle() function to solve this challenge.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
from brownie import PredictTheBlockHashChallenge, accounts, chain
defmain(): deployer = accounts[0] player = accounts[1]