-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathMetamorphic.sol
More file actions
184 lines (164 loc) · 8.51 KB
/
Metamorphic.sol
File metadata and controls
184 lines (164 loc) · 8.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
contract MetamorphicFactoryTemplate {
event Deployed(address addr, uint256 salt);
// Creation code breakdown
/** Opcodes Stack state
*
* comment: 0x0000000e - function sig of `callback19F236F3()`. Store this in memory
* 60 0e (PUSH1 0x0e) [0x0000000e]
* 60 e0 (PUSH1 0xe0) [0xe0, 0x0e]
* 1b (SHL) [0x0000000e00000000000000000000000000000000000000000000000000000000]
* 3d (RETURNDATASIZE) [0x00, 0x0000000e00000000000000000000000000000000000000000000000000000000]
* 52 (MSTORE) []
*
* comment: CALL BACK INTO DEPLOYING CONTRACT TO GET THE RUNTIME CODE
* 3d (RETURNDATASIZE) [0x00]
* 3d (RETURNDATASIZE) [0x00, 0x00]
* 60 04 (PUSH1 0x04) [0x04, 0x00, 0x00]
* 3d (RETURNDATASIZE) [0x00, 0x04, 0x00, 0x00]
* 33 (CALLER) [msg.sender, 0x00, 0x04, 0x00, 0x00]
* 5a (GAS) [gasleft, msg.sender, 0x00, 0x04, 0x00, 0x00]
* fa (STATICCALL) [0x01/0x00]
*
* comment: REVERT IF STATIC CALL FAILED
* 60 16 (PUSH1 0x16) [0x16, 0x01/0x00]
* 57 (JUMPI) []
* 60 00 (PUSH1 0x00) [0x00]
* 80 (DUP1) [0x00, 0x00]
* fd (REVERT) []
*
* comment: COPY RUNTIME CODE INTO MEMORY (THIS IS JUMPDEST `0x16`)
* 5b (JUMPDEST) []
* 60 40 (PUSH1 0x40) [0x40]
* 3d (RETURNDATASIZE) [RETURNDATASIZE, 0x40]
* 03 (SUB) [LENGTH]
* 80 (DUP1) [LENGTH, LENGTH]
* 60 40 (PUSH1 0x40) [0x40, LENGTH, LENGTH]
* 60 00 (PUSH1 0x00) [0x00, 0x40, LENGTH, LENGTH]
* 3e (RETURNDATACOPY) [LENGTH]
*
* comment: RETURN RUNTIME CODE FROM MEMORY
* 60 00 (PUSH1 0x00) [0x00, LENGTH]
* f3 (RETURN) []
*/
bytes constant private INIT_CODE = hex"600e60e01b3d52_3d3d60043d335afa_601657600080fd_5b60403d0380604060003e_6000f3";
// note: the assembly block here works considering that the creation code is 31 bytes or less.
// dynamic values are only stored in its slot as long as it's 31 bytes or less. the 32nd byte stores (the length * 2),
// otherwise just ((the length * 2) + 1) is stored at the slot. the value is stored at keccak256(slot).
function deploy(uint256 salt) public returns(address addr){
bytes memory initCode = INIT_CODE;
assembly {
addr := create2(0x00, add(initCode, 0x20), mload(initCode), salt)
}
if(addr == address(0)) revert("Create2 failed");
emit Deployed(addr, salt);
}
// 2. Compute the address of the contract to be deployed
// NOTE: _salt is a random number used to create an address
function getAddressOfMorph(uint256 _salt) public view returns (address) {
bytes32 hash = keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
_salt,
keccak256(INIT_CODE)
)
);
// NOTE: cast last 20 bytes of hash to address
return address(uint160(uint(hash)));
}
bytes implementation;
// morph calls back into factory to call this function which returns the runtime code based on is1
function callback19F236F3() external view returns (bytes memory) {
return implementation;
}
// changes what `get()` returns
// uint8 because 60 (PUSH1) is hardcoded and has a max value of 0xff (255)
function changeRuntimeReturnVal(bytes memory runtime) external {
implementation = runtime;
}
// this must be called before redeploying a morph
function kill(address a) external {
(bool success, ) = a.call(abi.encodeWithSignature("kill()"));
require(success,"kill failed");
}
// convenience to check the runtime code of an address to know if the morph's code changed
function getByte(address addr) external view returns (bytes memory) {
return addr.code;
}
}
/*************************************************************************************************************/
interface Metamorphic {
function get() external pure returns (uint256);
// can only be called by Factory
function kill() external;
}
contract Factory is MetamorphicFactoryTemplate{
// Runtime code breakdown
/** Opcodes Mnemonic Stack state
*
* 6000 (PUSH1 0x00) [0x00]
* 35 (CALLDATALOAD) [(0x00-0x20 0f calldata)]
* 80 (DUP1) [(0x00-0x20 0f calldata), (0x00-0x20 0f calldata)]
* 60 e0 (PUSH1 0xe0) [0xe0, (0x00-0x20 0f calldata), (0x00-0x20 0f calldata)]
* 1c (SHR) [func-sig, (0x00-0x20 0f calldata)]
* 63 6d4ce63c (PUSH4 0x6d4ce63c) [0x6d4ce63c, func-sig, (0x00-0x20 0f calldata)]
* 14 (EQ) [0/1, (0x00-0x20 0f calldata)]
* 60 3d (PUSH1 0x3d) [0x3d, 0/1, (0x00-0x20 0f calldata)]
* 57 (JUMPI) [(0x00-0x20 0f calldata)]
* 80 (DUP1) [(0x00-0x20 0f calldata), (0x00-0x20 0f calldata)]
* 60 e0 (PUSH1 0xe0) [0xe0, (0x00-0x20 0f calldata), (0x00-0x20 0f calldata)]
* 1c (SHR) [func-sig, (0x00-0x20 0f calldata)]
* 63 41c0e1b5 ((PUSH4 0x41c0e1b5) [0x41c0e1b5, func-sig, (0x00-0x20 0f calldata)]
* 14 (EQ) [0/1, (0x00-0x20 0f calldata)]
* 60 1e (PUSH1 0x1e) [0x1e, 0/1, (0x00-0x20 0f calldata)]
* 57 (JUMP1) [(0x00-0x20 0f calldata)]
* fe (INVALID)
*
*
*
*
* JUMPDEST: 0x1e
* -------------------SELF DESTRUCT FUNCTION-----------------------
*
* 5b (JUMPDEST) []
* 73 address(this) (PUSH20 address(this)) [address(this)]
* 80 (DUP1) [address(this), address(this)]
* 33 (CALLER) [msg.sender, address(this), address(this)]
* 14 (EQ) [0/1, address(this)]
* 60 3b (PUSH1 0x3b) [0x3b, 0/1, address(this)]
* 57 (JUMPI) [address(this)]
* fe (INVALID) []
*
* JUMPDEST: 0x3b
* 5b (JUMPDEST) [address(this)]
* ff (SELFDESTRUCT) []
*
*
*
*
* JUMPDEST: 0xed
* -------------------------GET FUNCTION-----------------------------
*
* 5b (JUMPDEST) []
*
* implementation: x is the input parsed into `changeRuntimeReturnVal()` below
default: 01
* 60 x (PUSH1 x) [x]
*
* 60 00 (PUSH1 0x00) [0x00, x]
* 52 (MSTORE) []
* 60 20 (PUSH1 0x20) [0x20]
* 60 00 (PUSH1 0x00) [0x00, 0x20]
* f3 (RETURN) []
*/
constructor () {
implementation =
abi.encodePacked(
hex"6000358060e01c636d4ce63c14603d578060e01c6341c0e1b514601e57fe5b73",
address(this),
hex"803314603b57fe5bff5b600160005260206000f3"
);
}
}