CTF frontend: https://www.solidityctf.xyz/ CTF Goerli contract: 0x3256a635372b4510595eab7219c470ce2143ea4e
For each level, the goal is to use the least gas whilst passing the checks of the level.
Descriptions of each level are given below, you can find some solutions in their respective folder.
levelTest.sol in the tests folder enables you to fuzz test a deployed solution contract on Goerli with Foundry by using the command forge test --rpc-url [GOERLI RPC URL].
This level is really simple. Use the interface bellow to write a smart contract. Your contract should contain a function called solution that returns a uint8. In this case the function body logic is very simply as the answer is always 42.
Interface:
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
interface Isolution {
function solution() external pure returns (uint8);
}Level 0 test contract: 0x43AE454F698D2efD4477Ec84f4158439b7dbC1C9
Write a function that adds two matrices returns the result. To keep things simple the array sizes will be fixed sizes of 2x2 (uint256[2]). Take a look at Wikipedia if you need help understanding matrix addition. Your solution should implement the following interface:
interface Isolution {
function solution(uint256[2] calldata firstArray, uint256[2] calldata secondArray) external returns (uint256[2] calldata finalArray);
}Level 1 test contract: 0x99eAc0b3E6369aa3836d0462342592981b0F34A2
Write a function that sorts an array in ascending order and returns the result. The array will be a fixed of 10 but the contents random. Your solution should implement the following interface:
interface Isolution2 {
function solution(uint256[10] calldata unsortedArray) external returns (uint256[10] memory sortedArray);
}Level 2 test contract: 0x7D0E14BbBf62E3f0Cc0999Cc16f25b9460D89f96
Using the Isolution3 interface write a function that takes an address and returns the codeSize of that address as a uint256.
interface Isolution3 {
function solution(address addr) external view
returns (uint256 codeSize);
}Level 3 test contract: 0x81C81Ae05dB618ffe1FE1ee4e37886fe86f76c34
Using the Isolution4 interface write a function that takes a uint256 and saves it to memory slot 3.
interface Isolution4 {
function solution(uint256 value) external;
}Level 4 test contract: 0xdee429a9041cC9d42Ff3A09935170205F037F169
Using the Isolution5 interface calculate Modular Exponentiation (base**exp % mod). Implementing it from scratch would take too much gas so you will need to use the precompiled contract at address 0x05
interface Isolution5 {
function solution(
bytes32 b,
bytes32 ex,
bytes32 mod)
external returns (
bytes32 result
);
}Level 5 test contract: 0xf420D13dC67191cCd274c1746cE272cfc0143Ff4
For this level we signed some messages off chain using the following front end code:
const ethers = require('ethers');
let messageHash = ethers.utils.id("bidPrice(0.420)");
let messageHashBytes = ethers.utils.arrayify(messageHash);
let flatSig = await wallet.signMessage(messageHashBytes); // Sign the binary data
let sig = ethers.utils.splitSignature(flatSig); // sig.v sig.r sig.s etcUsing the Isolution6 interface write a function that will take the messageHash (plus params) and return the signer of the message.
Hint: Don't forget to prepend your message with “\x19Ethereum Signed Message:\n32”
interface Isolution6 {
function solution(
bytes32 messageHash,
uint8 v,
bytes32 r,
bytes32 s
) external pure
returns (address signer);
}Level 6 test contract: 0x719Df2d793B3b21D84b5e81be450785752834950