Ethernaut系列-Level 18(MagicNum)
Published: 2022-05-31 07:23:00

## LEVEL 18 （MagicNum）:
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract MagicNum {

  address public solver;

  constructor() public {}

  function setSolver(address _solver) public {
    solver = _solver;
  }

  /*
    ____________/\\\_______/\\\\\\\\\_____        
     __________/\\\\\_____/\\\///////\\\___       
      ________/\\\/\\\____\///______\//\\\__      
       ______/\\\/\/\\\______________/\\\/___     
        ____/\\\/__\/\\\___________/\\\//_____    
         __/\\\\\\\\\\\\\\\\_____/\\\//________   
          _\///////////\\\//____/\\\/___________  
           ___________\/\\\_____/\\\\\\\\\\\\\\\_ 
            ___________\///_____\///////////////__
  */
}
```
## 通关要求
  写个合约，设置为solver
  合约要求：
1.调用合约的whatIsTheMeaningOfLife()方法返回一个代表生命意思的答案（科幻梗数字42）
2.合约的字节码要足够小，extcodesize <=10
         

##要点
  1.了解yul编码(或以太坊的opcodes)
https://docs.soliditylang.org/en/v0.8.14/yul.html

##解题思路
由于需要考虑到合约的大小，所以不能用solidity来编写
可以使用yul来编写，参考官方文档的例子
https://docs.soliditylang.org/en/v0.8.14/yul.html
新建18MagicNum.yul
```solidity
object "magic42" {
    code {
        //部署
        datacopy(0, dataoffset("runtime"), datasize("runtime"))
        return(0, datasize("runtime"))
    }
    object "runtime" {
        code {
            mstore(0, 0x2a)  //设置mem[0..32]=0x2a
            return(0, 0x20)  //返回mem[0..32]
        }
    }
}
```
然后用命令编译：
solc --strict-assembly --optimize contracts/18MagicNum.yul
得到
```
Binary representation:
600a80600c6000396000f3fe602a60005260206000f3
```
如果使用在线的remix,也可以在线用yul编译,再复制Bytecode->object
如图：
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19pwiz1t6xg1cghksnb1.png)
 
这串是合约部署bytecode，实际部署完会更小
线上过关可以在chrome控制台执行
```javascript
bytecode = '600a80600c6000396000f3fe602a60005260206000f3'
txn = await web3.eth.sendTransaction({from: player, data: bytecode})
await contract.setSolver(txn.contractAddress)
```

hardhat里
contracts/18MagicNumRun.sol
```solidity
  function check(address _runAddress,uint codeszie) external payable {
    require(ILevel(_runAddress).whatIsTheMeaningOfLife() == 42, "not equal 42");

    uint256 size;
    assembly {
      size := extcodesize(_runAddress)
    }
    
    require(size <= codeszie,"bigger codeszie ");
  } 
```
test/18MagicNum.js
```javascript
describe("18MagicNumb", function () {
  let player, levelOwner, levelContract, runContract;
  it("setup", async function () {
    [player, levelOwner] = await ethers.getSigners();
    const interface = ["function whatIsTheMeaningOfLife() returns (uint)"];
    //使用：得到这个solc --strict-assembly --optimize contracts/18MagicNumber.yul
    //也可以使用remix在线编译，再复制Bytecode
    const bytecode = "600a80600c6000396000f3fe602a60005260206000f3";
    const Contract = new ethers.ContractFactory(
      interface,
      bytecode,
      levelOwner
    );
    levelContract = await Contract.deploy();
    await levelContract.deployed();

    runContract = await tools.deployContract("MagicNumRun", player);
  });

  it("attacks", async function () {});

  it("check", async function () {
    //检查通过条件
    await runContract.check(levelContract.address, 10);
  });
});
```