├── .github
└── workflows
│ └── ci.yaml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── assets
├── metamorphic.jpg
├── metamorphic.png
└── metamorphosis.jpg
├── foundry.toml
├── src
├── ImmutableCreate2Factory.huff
├── MetamorphicFactory.huff
├── Metapod.huff
├── TransientContract.huff
└── interfaces
│ ├── IImmutableCreate2Factory.sol
│ ├── IMetamorphicFactory.sol
│ └── IMetapod.sol
└── tests
└── Metamorphic.t.sol
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on: [push]
4 |
5 | jobs:
6 | tests:
7 | name: Tests with Foundry
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v3
12 | with:
13 | submodules: recursive
14 |
15 | - name: Install Foundry
16 | uses: foundry-rs/foundry-toolchain@v1
17 | with:
18 | version: nightly
19 |
20 | - name: Install Huff
21 | uses: huff-language/huff-toolchain@v2
22 | with:
23 | version: nightly
24 |
25 | - name: Run Tests
26 | run: forge test -vvv
27 |
28 | huff-tests:
29 | name: Tests in Huff
30 | runs-on: ubuntu-latest
31 | steps:
32 | - uses: actions/checkout@v3
33 | with:
34 | submodules: recursive
35 |
36 | - name: Install Foundry
37 | uses: foundry-rs/foundry-toolchain@v1
38 | with:
39 | version: nightly
40 |
41 | - name: Install Huff
42 | uses: huff-language/huff-toolchain@v2
43 | with:
44 | version: nightly
45 |
46 | - name: Run Huff Tests
47 | uses: huff-language/huff-tests-action@v3
48 | with:
49 | # Optional
50 | with-forge-tests: false
51 | test-extension: ".t.huff"
52 |
53 | scripts:
54 | strategy:
55 | fail-fast: true
56 | name: Run Scripts
57 | runs-on: ubuntu-latest
58 | steps:
59 | - uses: actions/checkout@v3
60 | with:
61 | submodules: recursive
62 |
63 | - name: Install Foundry
64 | uses: foundry-rs/foundry-toolchain@v1
65 | with:
66 | version: nightly
67 |
68 | - name: Install Huff
69 | uses: huff-language/huff-toolchain@v2
70 | with:
71 | version: nightly
72 |
73 | - name: Run Forge build
74 | run: |
75 | forge --version
76 | forge build --sizes
77 | id: build
78 | continue-on-error: true
79 |
80 | - name: Run scripts
81 | run: |
82 | ls -lsa
83 | ls script/
84 | for file in script/*; do
85 | forge script $file -vvvv
86 | done
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Any Node Modules
2 | node_modules/
3 |
4 | # Environment Variables
5 | .env
6 | .env.prod
7 |
8 | # Cached Build
9 | cache/
10 | out/
11 |
12 | # Vscode
13 | .vscode/
14 |
15 | # huffc artifacts
16 | artifacts
17 |
18 | # Ignore flattened files
19 | flattened.txt
20 |
21 | # Ignore Broadcasts
22 | broadcast
23 |
24 | # Logs
25 | logs
26 | *.log
27 | npm-debug.log*
28 | yarn-debug.log*
29 | yarn-error.log*
30 | lerna-debug.log*
31 |
32 | # Diagnostic reports (https://nodejs.org/api/report.html)
33 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
34 |
35 | # Runtime data
36 | pids
37 | *.pid
38 | *.seed
39 | *.pid.lock
40 |
41 | # Directory for instrumented libs generated by jscoverage/JSCover
42 | lib-cov
43 |
44 | # Coverage directory used by tools like istanbul
45 | coverage
46 | *.lcov
47 |
48 | # nyc test coverage
49 | .nyc_output
50 |
51 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
52 | .grunt
53 |
54 | # Bower dependency directory (https://bower.io/)
55 | bower_components
56 |
57 | # node-waf configuration
58 | .lock-wscript
59 |
60 | # Compiled binary addons (https://nodejs.org/api/addons.html)
61 | build/Release
62 |
63 | # Dependency directories
64 | node_modules/
65 | jspm_packages/
66 |
67 | # TypeScript v1 declaration files
68 | typings/
69 |
70 | # TypeScript cache
71 | *.tsbuildinfo
72 |
73 | # Optional npm cache directory
74 | .npm
75 |
76 | # Optional eslint cache
77 | .eslintcache
78 |
79 | # Microbundle cache
80 | .rpt2_cache/
81 | .rts2_cache_cjs/
82 | .rts2_cache_es/
83 | .rts2_cache_umd/
84 |
85 | # Optional REPL history
86 | .node_repl_history
87 |
88 | # Output of 'npm pack'
89 | *.tgz
90 |
91 | # Yarn Integrity file
92 | .yarn-integrity
93 |
94 | # dotenv environment variables file
95 | .env
96 | .env.test
97 |
98 | # parcel-bundler cache (https://parceljs.org/)
99 | .cache
100 |
101 | # Next.js build output
102 | .next
103 |
104 | # Nuxt.js build / generate output
105 | .nuxt
106 | dist
107 |
108 | # Gatsby files
109 | .cache/
110 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
111 | # https://nextjs.org/blog/next-9-1#public-directory-support
112 | # public
113 |
114 | # vuepress build output
115 | .vuepress/dist
116 |
117 | # Serverless directories
118 | .serverless/
119 |
120 | # FuseBox cache
121 | .fusebox/
122 |
123 | # DynamoDB Local files
124 | .dynamodb/
125 |
126 | # TernJS port file
127 | .tern-port
128 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/forge-std"]
2 | path = lib/forge-std
3 | url = https://github.com/foundry-rs/forge-std
4 | [submodule "lib/foundry-huff"]
5 | path = lib/foundry-huff
6 | url = https://github.com/huff-language/foundry-huff
7 | [submodule "lib/huffmate"]
8 | path = lib/huffmate
9 | url = https://github.com/pentagonxyz/huffmate
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 asnared
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # metamorphic    
4 |
5 | [Huff](https://github.com/huff-language) Smart Contracts for creating Metamorphic (or "redeployable") EVM Contracts.
6 |
7 | > **Note**
8 | > This is a rewrite of [0age](https://github.com/0age)'s [metamorphic contracts](https://github.com/0age/metamorphic) in [Huff](https://github.com/huff-language).
9 |
10 |
11 | ### A Trip Down Ethereum History
12 |
13 | Prior to [EIP-1014](https://eips.ethereum.org/EIPS/eip-1014) (included in the Constantinople hard fork), contracts on ethereum were _completely_ immutable. Code deployed to a given address could only be created and subsequently destroyed using the `CREATE` and `SELFDESTRUCT` opcodes. Migrating contracts involved replaying state onto a new contract, which is expensive and not scalable.
14 |
15 | Fortunately, [EIP-1014](https://eips.ethereum.org/EIPS/eip-1014) introduced the `CREATE2` opcode, a form of ["wild magic"](https://medium.com/@jason.carver/defend-against-wild-magic-in-the-next-ethereum-upgrade-b008247839d2) allowing a contract to be **redeployed to the same address with different bytecode**.
16 |
17 | `CREATE2` uses the **caller’s address**, a supplied **salt** parameter, and the **initialization code** of the contract that is created. Altering any one of these parameters will result in your bytecode being deployed to a completely different contract address.
18 |
19 | Cool, so we have completely deterministic, redeployable contracts on Ethereum using `CREATE2`, right?
20 |
21 | Well, this fails if the initialization code of the contract is non-deterministic. [0age](https://github.com/0age) presents a simple example: consider a contract that calls into some external contract and uses the variable return data to construct the final bytecode. Then the initialization code is in fact non-deterministic, and `CREATE2` will generate an entirely new address for each time the contract is redeployed if the return data from the external contract changes.
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | // TODO:
31 |
32 |
33 | ### Usage
34 |
35 | **Deploying Metamorphic Contracts**
36 |
37 | // TODO:
38 |
39 | Clone factory contracts should use the [`HuffCloneLib`](src/HuffCloneLib.huff) library. `CLONE` is the main macro for creating clones.
40 |
41 | Contracts intended to be cloned should include [`HuffClone`](src/HuffClone.huff) to get access to the helper macros for reading immutable args.
42 |
43 | To see an example usage of the library, check out [`ExampleClone`](src/ExampleClone.huff) and [`ExampleCloneFactory`](src/ExampleCloneFactory.huff).
44 |
45 | **Installing as a Foundry Library**
46 |
47 | To install with [Foundry](https://github.com/foundry-rs/foundry):
48 |
49 | ```
50 | forge install abigger87/metamorphic
51 | ```
52 |
53 | > **Warning**
54 | >
55 | > These contracts are **unaudited** and are not recommended for use in production.
56 | >
57 | > Although contracts have been rigorously reviewed, this is **experimental software** and is provided on an "as is" and "as available" basis.
58 | > We **do not give any warranties** and **will not be liable for any loss** incurred through any use of this codebase.
59 |
60 |
61 | ### Contracts
62 |
63 | ```txt
64 | .
65 | ├─ src
66 | | ├─ interfaces
67 | | | ├─ IImmutableCreate2Factory.sol —
68 | | | ├─ IMetamorphicFactory.sol —
69 | | | └─ IMetapod.sol —
70 | | ├─ ImmutableCreate2Factory.huff —
71 | | ├─ MetamorphicFactory.huff —
72 | | ├─ Metapod.huff —
73 | | └─ TransientContract.huff —
74 | └─ tests
75 | └─ 🧪🧪🧪
76 | ```
77 |
78 | ### Acknowledgements
79 |
80 | - [femplate](https://github.com/0age/metamorphic)
81 | - [huffplate](https://github.com/abigger87/huffplate)
82 | - [forge-std](https://github.com/brockelmore/forge-std)
83 |
84 |
--------------------------------------------------------------------------------
/assets/metamorphic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/refcell/metamorphic/127dde07e12be1a20b0dcd00191702f0f54191ec/assets/metamorphic.jpg
--------------------------------------------------------------------------------
/assets/metamorphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/refcell/metamorphic/127dde07e12be1a20b0dcd00191702f0f54191ec/assets/metamorphic.png
--------------------------------------------------------------------------------
/assets/metamorphosis.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/refcell/metamorphic/127dde07e12be1a20b0dcd00191702f0f54191ec/assets/metamorphosis.jpg
--------------------------------------------------------------------------------
/foundry.toml:
--------------------------------------------------------------------------------
1 | [profile.default]
2 | test = "tests"
3 | solc_version = '0.8.15'
4 | auto_detect_solc = false
5 | optimizer = true
6 | optimizer_runs = 200
7 | ffi = true
8 | fuzz_runs = 1_000
9 | remappings = [
10 | "forge-std=lib/forge-std/src/",
11 | "foundry-huff=lib/foundry-huff/src/",
12 | "huffmate=lib/huffmate/src/",
13 | ]
14 | fs_permissions = [
15 | { access = "read", path = "./src/ImmutableCreate2Factory.huff" },
16 | { access = "read", path = "./src/MetamorphicFactory.huff" },
17 | { access = "read", path = "./src/Metapod.huff" },
18 | { access = "read", path = "./src/TransientContract.huff" },
19 | ]
20 |
--------------------------------------------------------------------------------
/src/ImmutableCreate2Factory.huff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/refcell/metamorphic/127dde07e12be1a20b0dcd00191702f0f54191ec/src/ImmutableCreate2Factory.huff
--------------------------------------------------------------------------------
/src/MetamorphicFactory.huff:
--------------------------------------------------------------------------------
1 | /// @title Metamorphic Factory
2 | /// @notice SPDX-License-Identifier: MIT
3 | /// @author asnared
4 | /// @notice A factory to create metamorphic contracts
5 | /// @notice Metamorphic contracts can be redeployed with new code to the same address
6 | /// @notice Adapted from
7 |
8 |
9 | /// -----------------------
10 | ///
11 | /// How does Metamorphism work?
12 | ///
13 | /// In the constructor, set up the initialization code for metamorphic contracts.
14 | /// The bytes passed into the Metamorphic Factory is used to deploy any transient contracts,
15 | /// which will deploy any metamorphic contracts that require the use of a constructor.
16 | ///
17 | /// Metamorphic contract initialization code (29 bytes): 0x5860208158601c335a63aaf10f428752fa158151803b80938091923cf3
18 | ///
19 | /// Breaking down the metamorphic contract initialization code
20 | ///
21 | /// -----------------------
22 | ///
23 | /// Format:
24 | /// pc | op | name | [stack] | | // Description
25 | ///
26 | /// -----------------------
27 | ///
28 | /// 00 58 getpc [0] <> // Set the first stack item to zero (using the program counter (or pc) since it is zero)
29 | /// 01 60 push1 [0] <> // Pushes the next byte onto the stack
30 | /// 02 20 outsize [32, 0] <> // Value pushed to the stack: 32 (the length of word returned from staticcall)
31 | /// 03 81 dup2 [0, 32, 0] <> // Duplicates the second stack item (0) (the position of word returned from staticcall)
32 | /// 04 58 getpc [4, 0, 32, 0] <> // Set fourth stack item to 4, length of selector given to staticcall
33 | /// 05 60 push1 [4, 0, 32, 0] <> // Pushes the next byte onto the stack
34 | /// 06 1c inpos [28, 4, 32, 0] <> // Value pushed to stack: 28 (position of selector given to staticcall)
35 | /// 07 33 caller [caller, 28, 4, 0, 32, 0] <> // Pushes msg.sender to the stack (target address for staticcall)
36 | /// 08 5a gas [gas, caller, 28, 4, 0, 32, 0] <> // Pushes msg.gas to the stack (gas to forward for staticcall)
37 | /// 09 63 push4 [gas, caller, 28, 4, 0, 32, 0] <> // Pushes the next 4 bytes to the stack (the function selector)
38 | /// 10 aaf10f42 selector [0xaaf10f42, gas, caller, 28, 4, 0, 32, 0] <> // The 4byte function selector pushed to the stack
39 | /// 11 87 dup8 [0, 0xaaf10f42, gas, caller, 28, 4, 0, 32, 0] <> // Push the offset where to store the function selector in memory
40 | /// 12 52 mstore [gas, caller, 28, 4, 0, 32, 0] <0xaaf10f42> // Places the function selector in memory at location 0x00 using mstore
41 | /// 13 fa staticcall [result (1 if success), 0] // Calls staticcall (places address in memory)
42 | /// 14 15 iszero [result == 0, 0] // Flips the success bit of the staticcall
43 | /// 15 81 dup2 [0, result == 0, 0] // Duplicates the second stack item (0) (the position of address in memory)
44 | /// 16 51 mload [address, result == 0, 0] <> // Loads address from position in memory onto the stack
45 | /// 17 80 dup1 [address, address, result == 0, 0] <> // Duplicates the address on the stack (the address for extcodesize to read)
46 | /// 18 3b extcodesize [size, address, result == 0, 0] <> // Gets the extcodesize of address and places on the stack
47 | /// 19 80 dup1 [size, size, address, result == 0, 0] <> // Duplicates the size of code at the address (reordering stack for extcodecopy)
48 | /// 20 93 swap4 [0, size, address, result == 0, size] <> // Swaps the size with 0 (reordering stack for extcodecopy)
49 | /// 21 80 dup1 [0, 0, size, address, result == 0, size] <> // Duplicates the first stack item (reordering stack for extcodecopy)
50 | /// 22 91 swap2 [size, 0, 0, address, result == 0, size] <> // Swaps the first and third stack items (reordering stack for extcodecopy)
51 | /// 23 92 swap3 [address, 0, 0, size, result == 0, size] <> // Swaps the first and fourth stack item (reordering stack for extcodecopy)
52 | /// 24 3c extcodecopy [result == 0, size] // Calls extcodecopy with four stack items (placing the runtime code in memory)
53 | /// 25 f3 return [] // Return to deploy final code in memory
54 | ///
55 | /// -----------------------
56 |
57 |
58 | // Imports
59 | #include "huffmate/data-structures/Hashmap.huff"
60 | #include "huffmate/utils/CommonErrors.huff"
61 |
62 | // Stateful Interface
63 | #define function deployMetamorphicContract(bytes32, bytes calldata, bytes calldata) payable returns (address)
64 | #define function deployMetamorphicContractFromExistingImplementation(bytes32, address, bytes calldata) payable returns (address)
65 | #define function deployMetamorphicContractWithConstructor(bytes32, bytes calldata) payable returns (address)
66 |
67 | // Viewable Interface
68 | #define function getImplementation() view returns (address)
69 | #define function getInitializationCode() view returns (bytes memory)
70 | #define function getImplementationContractAddress(address) view returns (address)
71 |
72 | #define function getMetamorphicContractInstanceInitializationCode(address) view returns (bytes memory)
73 | #define function findMetamorphicContractAddress(bytes32) view returns (address)
74 | #define function findTransientContractAddress(bytes32) view returns (address)
75 | #define function findMetamorphicContractAddressWithConstructor(bytes32) view returns (address)
76 |
77 | #define function getMetamorphicContractInitializationCode() view returns (bytes memory)
78 | #define function getMetamorphicContractInitializationCodeHash() view returns (bytes32)
79 | #define function getTransientContractInitializationCode() view returns (bytes memory)
80 | #define function getTransientContractInitializationCodeHash() view returns (bytes32)
81 |
82 |
83 | /// @notice Fires when a metamorphic contract is deployed by cloning another contract
84 | #define event Metamorphosed(address metamorphicContract, address newImplementation)
85 |
86 | /// @notice Fires when a metamorphic contract is deployed through a transient contract
87 | #define event MetamorphosedWithConstructor(address metamorphicContract, address transientContract)
88 |
89 | /// @notice Store the initialization code for metamorphic contracts
90 | #define constant MEAMORPHIC_CONTRACT_INITIALIZATION_CODE = 0x5860208158601c335a63aaf10f428752fa158151803b80938091923cf3
91 |
92 | /// @notice Store hash of the initialization code for metamorphic contracts as well
93 | #define constant METAMORPHIC_CONTRACT_INITIALIZATION_CODE_HASH = 0x7e18b382dec96fdc3badcb1ca6258e4f14469630399ad6ccb243b0d9f5344366
94 |
95 | /// @notice Store init code for transient contracts that deploy metamorphic contracts
96 | #define constant TRANSIENT_CONTRACT_INITIALIZATION_CODE = FREE_STORAGE_POINTER()
97 |
98 | /// @notice Store the hash of the initialization code for transient contracts as well
99 | #define constant TRANSIENT_CONTRACT_INTIALIZALIZATION_CODE_HASH = FREE_STORAGE_POINTER()
100 |
101 | /// @notice Maintain a mapping of metamorphic contracts to metamorphic implementations
102 | /// @notice This is a mapping and should use the hashmap helpers: LOAD_ELEMENTS_FROM_KEYS and STORE_ELEMENT_FROM_KEYS
103 | #define constant IMPLEMENTATIONS = FREE_STORAGE_POINTER()
104 |
105 | /// @notice Maintain a mapping of transient contracts to metamorphic init codes
106 | /// @notice This is a mapping and should use the hashmap helpers: LOAD_ELEMENTS_FROM_KEYS and STORE_ELEMENT_FROM_KEYS
107 | #define constant INIT_CODES = FREE_STORAGE_POINTER()
108 |
109 | /// @notice Internal
110 | /// @notice Helper macro to copy the bytes memory constructor argument
111 | #define macro _LOAD_CONSTRUCTOR_ARGS() = takes (0) returns (1) {
112 | // Input Stack: []
113 | // Output Stack: [memory location of initialization bytes]
114 |
115 | // Codecopy the bytecode
116 | codesize dup1 0x00 0x00 // [destOffset, offset, size, size]
117 | codecopy // [size]
118 |
119 | // Word-align the size
120 | 0x10 add // [size + 0x10]
121 | 0x20 swap1 div // [(size + 0x10) / 0x20]
122 | 0x20 mul // [((size + 0x10) / 0x20) * 0x20]
123 |
124 | // Iterate backwards until we find: 0x20 | size | bytes (where bytes.length == size)
125 | 0x00 // [i, size]
126 | loop:
127 | dup2 dup2 // [i, size, i, size]
128 | 0x20 add swap1 sub // [size - (i + 0x20), i, size]
129 | mload dup2 // [i, bytecode[size - (i + 0x20)], i, size]
130 | // NOTE: we have to use less than here since the index is word aligned and bytes may not be
131 | swap1 lt // [bytecode[size - (i + 0x20)] < i, i, size]
132 | dup2 0x40 add // [i + 0x40, bytecode[size - (i + 0x20)] == i, i, size]
133 | dup4 sub mload // [bytecode[size - (i + 0x40)], bytecode[size - (i + 0x20)] == i, i, size]
134 | 0x20 eq // [bytecode[size - (i + 0x40)] == 0x20, bytecode[size - (i + 0x20)] == i, i, size]
135 | and // [bytecode[size - (i + 0x40)] == 0x20 && bytecode[size - (i + 0x20)] == i, i, size]
136 | found jumpi // [i, size]
137 |
138 | // Increment and revert on underflow
139 | 0x20 add dup1 0x20 add // [i + 0x40, i + 0x40, size]
140 | dup3 sub iszero iszero // [size - (i + 0x40) > 0, i + 0x20, size]
141 | loop jumpi // [i, size]
142 |
143 | 0x00 dup1 revert // _reverts_
144 |
145 | found:
146 | // Get the pointer to the bytes size
147 | 0x20 add swap1 sub // [size - i]
148 | }
149 |
150 | /// @notice Internal
151 | /// @notice Saves bytes memory to storage
152 | #define macro _SAVE_BYTES_TO_STORAGE() = takes (1) returns (0) {
153 | // Input Stack: [&storage[data], &mem[data]]
154 | // Output Stack: []
155 |
156 | // Load the size and save to storage
157 | dup1 // [&storage[data], &storage[data], &mem[data]]
158 | dup3 mload dup1 // [size, size, &storage[data], &storage[data], &mem[data]]
159 | swap2 sstore // [size, &storage[data], &mem[data]]
160 |
161 | // Loop over data and save to storage
162 | swap1 swap2 0x20 add // [&mem[data] + 0x20, size, &storage[data]]
163 | 0x00 // [i, &mem[data] + 0x20, size, &storage[data]]
164 |
165 | loop:
166 | dup3 dup2 lt iszero // [i >= size, i, &mem[data], size, &storage[data]]
167 | done jumpi // [i, &mem[data], size, &storage[data]]
168 | dup2 dup2 add // [&mem[data] + i, i, &mem[data], size, &storage[data]]
169 | dup5 sstore // [i, &mem[data], size, &storage[data]]
170 | 0x20 add // [i + 0x20, &mem[data], size, &storage[data]]
171 | loop jump
172 |
173 | done:
174 |
175 | // Clean the stack
176 | pop pop pop pop
177 | }
178 |
179 | /// @notice Internal
180 | /// @notice Hashes the transient initialization code from storage
181 | #define macro _HASH_STORAGE_BYTES() = takes (0) returns (1) {
182 | // Input Stack: [&storage[data]]
183 | // Output Stack: [hash]
184 |
185 | // Save bytes to memory
186 | dup1 0x20 add swap1 // [&storage[data], &storage[data] + 0x20]
187 | sload dup1 0x00 mstore // [size, &storage[data] + 0x20]
188 | 0x00 // [i, size, &storage[data] + 0x20]
189 |
190 | // Loop over data and store to memory
191 | memStoreLoop:
192 | dup2 dup2 lt iszero // [i >= size, i, size, &storage[data] + 0x20]
193 | hashMem jumpi // [i, size, &storage[data] + 0x20]
194 | dup3 dup2 add // [&storage[data] + 0x20 + i, i, size, &storage[data] + 0x20]
195 | sload // [word, i, size, &storage[data] + 0x20]
196 | 0x20 add dup1 mstore // [i + 0x20, size, &storage[data] + 0x20]
197 | memStoreLoop jump // [i + 0x20, size, &storage[data] + 0x20]
198 |
199 | // Hash memory at 0x20 for size &mem[0x00:0x20]
200 | hashMem:
201 | pop swap1 pop // [size]
202 | 0x20 // [offset, size]
203 | sha3 // [hash]
204 | }
205 |
206 | /// @notice Constructor
207 | #define macro CONSTRUCTOR() = takes (0) returns (0) {
208 | // Load the transient initialization code from the creation code
209 | _LOAD_CONSTRUCTOR_ARGS() // [transientContractInitializationCode]
210 |
211 | // Store the transient contract initialization code in storage
212 | [TRANSIENT_CONTRACT_INITIALIZATION_CODE] // [initCode, transientContractInitializationCode]
213 | _SAVE_BYTES_TO_STORAGE() // []
214 |
215 | // Calculate the transient contract initialization code hash
216 | [TRANSIENT_CONTRACT_INITIALIZATION_CODE] // [initCode]
217 | _HASH_STORAGE_BYTES() // [hash]
218 |
219 | // Store the transient contract initialization code hash in storage
220 | [TRANSIENT_CONTRACT_INTIALIZALIZATION_CODE_HASH] sstore // []
221 | }
222 |
223 | /// @notice The function dispatch (main contract entrypoint)
224 | #define macro MAIN() = takes (0) returns (0) {
225 | // Load the function selector
226 | pc calldataload 0xE0 shr // [selector]
227 |
228 | // Dispatch Stateful Functions With Selector
229 | dup1 __FUNC_SIG(deployMetamorphicContract) eq deplyMContractJump jumpi // [selector]
230 | dup1 __FUNC_SIG(deployMetamorphicContractFromExistingImplementation) eq deployMContractExistingJump jumpi // [selector]
231 | dup1 __FUNC_SIG(deployMetamorphicContractWithConstructor) eq deployMContractConstructorJump jumpi // [selector]
232 |
233 | // Dispatch Viewable Functions With Selector
234 | dup1 __FUNC_SIG(getImplementation) eq getImplJump jumpi // [selector]
235 | dup1 __FUNC_SIG(getInitializationCode) eq getInitJump jumpi // [selector]
236 | dup1 __FUNC_SIG(getImplementationContractAddress) eq getImplContJump jumpi // [selector]
237 |
238 | dup1 __FUNC_SIG(getMetamorphicContractInstanceInitializationCode) eq getMInstanceInitCodeJump jumpi // [selector]
239 | dup1 __FUNC_SIG(findMetamorphicContractAddress) eq findMContractAddressJump jumpi // [selector]
240 | dup1 __FUNC_SIG(findTransientContractAddress) eq findTContractAddressJump jumpi // [selector]
241 | dup1 __FUNC_SIG(findMetamorphicContractAddressWithConstructor) eq findMContractAddressConstructorJump jumpi // [selector]
242 |
243 |
244 | dup1 __FUNC_SIG(getMetamorphicContractInitializationCode) eq getMInitCodeJump jumpi // [selector]
245 | dup1 __FUNC_SIG(getMetamorphicContractInitializationCodeHash) eq getMInitCodeHashJump jumpi // [selector]
246 | dup1 __FUNC_SIG(getTransientContractInitializationCode) eq getTInitCodeJump jumpi // [selector]
247 | dup1 __FUNC_SIG(getTransientContractInitializationCodeHash) eq getTInitCodeHashJump jumpi // [selector]
248 |
249 |
250 | // Revert on invalid dispatch
251 | 0x00 dup1 revert // _reverts_
252 |
253 | // Jump Dests
254 | deplyMContractJump: DEPLOY_METAMORPHIC_CONTRACT() // _stops_
255 | deployMContractExistingJump: DEPLOY_METAMORPHIC_CONTRACT_FROM_EXISTING() // _stops_
256 | deployMContractConstructorJump: DEPLOY_METAMORPHIC_CONTRACT_WITH_CONSTRUCTOR() // _stops_
257 |
258 | getImplJump: GET_IMPLEMENTATION() // _stops_
259 | getInitJump: GET_INIT_CODE() // _stops_
260 | getImplContJump: GET_IMPLEMENTATION_FOR_ADDRESS() // _stops_
261 |
262 | getMInstanceInitCodeJump: GET_CONTRACT_INIT_CODE() // _stops_
263 | findMContractAddressJump: COMPUTE_METAMORPHIC_ADDRESS() // _stops_
264 | findTContractAddressJump: COMPUTE_TRANSIENT_ADDRESS() // _stops_
265 | findMContractAddressConstructorJump: COMPUTE_METAMORPHIC_ADDRESS_WITH_CONSTRUCTOR() // _stops_
266 |
267 | getMInitCodeJump: GET_METAMORPHIC_INITIALIZATION_CODE() // _stops_
268 | getMInitCodeHashJump: GET_METAMORPHIC_INITIALIZATION_CODE_HASH() // _stops_
269 | getTInitCodeJump: GET_TRANSIENT_INITIALIZATION_CODE() // _stops_
270 | getTInitCodeHashJump: GET_TRANSIENT_INITIALIZATION_CODE_HASH() // _stops_
271 | }
272 |
273 |
274 | // ----------------------------------
275 | // Stateful Functions
276 | // ----------------------------------
277 |
278 | /// @notice Stateful
279 | /// @notice Equivalent of `deployMetamorphicContract`
280 | /// @notice Deploy a metamorphic contract by submitting a given salt or nonce along
281 | /// with the initialization code for the metamorphic contract, and
282 | /// optionally provide calldata for initializing the new metamorphic contract.
283 | /// To replace the contract, first selfdestruct the current contract, then call
284 | /// with the same salt value and new initialization code (be aware that all
285 | /// existing state will be wiped from the existing contract). Also note that
286 | /// the first 20 bytes of the salt must match the calling address, which
287 | /// prevents contracts from being created by unintended parties.
288 | /// @param salt bytes32 The nonce that will be passed into the CREATE2 call and
289 | /// thus will determine the resulant address of the metamorphic contract.
290 | /// @param implementationContractInitializationCode bytes The initialization
291 | /// code for the implementation contract for the metamorphic contract. It will
292 | /// be used to deploy a new contract that the metamorphic contract will then
293 | /// clone in its constructor.
294 | /// @param metamorphicContractInitializationCalldata bytes An optional data
295 | /// parameter that can be used to atomically initialize the metamorphic contract.
296 | /// @return Address of the metamorphic contract that will be created.
297 | #define macro DEPLOY_METAMORPHIC_CONTRACT() = takes (0) returns (0) {
298 | // Load the salt from calldata
299 | 0x04 calldataload // [bytes32(salt)]
300 |
301 | // Load the implementation contract init code to the same location in memory
302 | 0x24 calldataload // [&calldata[init_code], salt]
303 | dup1 calldataload // [size, &calldata[init_code], salt]
304 | dup2 dup1 calldatacopy // [&mem[init_code], salt]
305 |
306 | // Load the metamorphic contract init calldata to the same place in memory
307 | 0x44 calldataload // [&calldata[init_data], &mem[init_code], salt]
308 | dup1 calldataload // [size, &calldata[init_data], &mem[init_code], salt]
309 | dup2 dup1 calldatacopy // [&mem[init_data], &mem[init_code], salt]
310 |
311 | // Modifiers
312 | dup3 CONTAINS_CALLER() // [&mem[init_data], &mem[init_code], salt]
313 |
314 | // Get the metamorphic contract address
315 | dup3 _COMPUTE_METAMORPHIC_ADDRESS() // [address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
316 |
317 | // Deploy the implementation init code
318 | dup3 dup1 calldataload // [init_code_size, &mem[init_code], address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
319 | swap1 0x20 add 0x00 // [value, mem[init_code + 0x20], init_code_size, address(metamoprhicContract), mem[init_data], mem[init_code], salt]
320 | create // [address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
321 |
322 | // Validate Creation
323 | dup1 validCreateJump jumpi // [address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
324 | REVERT_CREATE_FAILED(0x00) // _reverts_
325 | validCreateJump:
326 |
327 | // Store the implementation contract address
328 | dup1 dup3 [IMPLEMENTATIONS]
329 | STORE_ELEMENT_FROM_KEYS(0x00)
330 |
331 | // Deploy the metamorphic contract data with create2
332 | dup5 // [salt, address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
333 | [MEAMORPHIC_CONTRACT_INITIALIZATION_CODE] 0x00 mstore // [salt, address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
334 | 0x1D // [size, salt ,address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
335 | 0x00 // [offset, size, salt, address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
336 | 0x00 // [value, offset, size, salt, address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
337 | create2 // [address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
338 |
339 | // Validate the Creation
340 | dup3 dup2 eq validCreate2Jump // [address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
341 | REVERT_CREATE_TWO_FAILED(0x00) // _reverts_
342 | validCreate2Jump:
343 |
344 | // If any data or value is provided
345 | dup4 mload iszero // [init_data.length == 0, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
346 | callvalue iszero and // [msg.value == 0 && init_data.length == 0, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
347 | emitEventJump jumpi // [address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
348 |
349 | // Initialize the new metamorphic contract
350 | 0x00 // [retSize, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
351 | dup1 // [retOffset, retSize, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
352 | dup6 mload // [argSize, retOffset, retSize, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
353 | dup7 0x20 add // [argOffset, argSize, retOffset, retSize, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
354 | callvalue // [value, argOffset, argSize, retOffset, retSize, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
355 | dup6 // [address, value, argOffset, argSize, retOffset, retSize, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
356 | gas // [gas, address, value, argOffset, argSize, retOffset, retSize, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
357 | call // [success, address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
358 |
359 | // Validate call success
360 | emitEventJump jumpi // [address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
361 | INITIALIZATION_FAILED(0x00) // _reverts_
362 |
363 | // Emit the Metamorphosed event
364 | emitEventJump: // [address(newMetaContract), address(implContract), address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
365 | __EVENT_HASH(Metamorphosed) 0x00 0x00 log3 // [address(metamoprhicContract), &mem[init_data], &mem[init_code], salt]
366 |
367 | // Return the metamorphic contract address
368 | 0x00 mstore // [&mem[init_data], &mem[init_code], salt]
369 | 0x20 0x00 return // _returns_
370 | }
371 |
372 | /// @notice Stateful
373 | /// @notice Equivalent of `deployMetamorphicContractFromExistingImplementation`
374 | /// @notice Deploy a metamorphic contract by submitting a given salt or nonce
375 | /// along with the address of an existing implementation contract to clone, and
376 | /// optionally provide calldata for initializing the new metamorphic contract.
377 | /// To replace the contract, first selfdestruct the current contract, then call
378 | /// with the same salt value and a new implementation address (be aware that
379 | /// all existing state will be wiped from the existing contract). Also note
380 | /// that the first 20 bytes of the salt must match the calling address, which
381 | /// prevents contracts from being created by unintended parties.
382 | /// @param salt bytes32 The nonce that will be passed into the CREATE2 call and
383 | /// thus will determine the resulant address of the metamorphic contract.
384 | /// @param implementationContract address The address of the existing
385 | /// implementation contract to clone.
386 | /// @param metamorphicContractInitializationCalldata bytes An optional data
387 | /// parameter that can be used to atomically initialize the metamorphic
388 | /// contract.
389 | /// @return Address of the metamorphic contract that will be created.
390 | #define macro DEPLOY_METAMORPHIC_CONTRACT_FROM_EXISTING() = takes (0) returns (0) {
391 | // Load the salt from calldata
392 | 0x04 calldataload // [bytes32(salt)]
393 |
394 | // Load the implementation contract address
395 | 0x24 calldataload // [implAddress, salt]
396 |
397 | // Load the metamorphic contract init calldata to the same place in memory
398 | 0x44 calldataload // [&calldata[init_data], implAddress, salt]
399 | dup1 calldataload // [size, &calldata[init_data], implAddress, salt]
400 | dup2 dup1 calldatacopy // [&mem[init_data], implAddress, salt]
401 |
402 | // Modifiers
403 | dup3 CONTAINS_CALLER() // [&mem[init_data], implAddress, salt]
404 |
405 | // Get the metamorphic contract address
406 | dup3 _COMPUTE_METAMORPHIC_ADDRESS() // [address(metamoprhicContract), &mem[init_data], implAddress, salt]
407 |
408 | // Store the implementation address to be retrieved by the metamoprhic contract
409 | dup3 dup2 [IMPLEMENTATIONS] // [slot, address(metamoprhicContract), implAddress, address(metamoprhicContract), &mem[init_data], implAddress, salt]
410 | STORE_ELEMENT_FROM_KEYS(0x00) // [address(metamoprhicContract), &mem[init_data], implAddress, salt]
411 |
412 | // Deploy the metamorphic contract data with create2
413 | dup4 // [salt, address(metamoprhicContract), &mem[init_data], implAddress, salt]
414 | [MEAMORPHIC_CONTRACT_INITIALIZATION_CODE] 0x00 mstore // [salt, address(metamoprhicContract), &mem[init_data], implAddress, salt]
415 | 0x1D // [size, salt, address(metamoprhicContract), &mem[init_data], implAddress, salt]
416 | 0x00 // [offset, size, salt, address(metamoprhicContract), &mem[init_data], implAddress, salt]
417 | 0x00 // [value, offset, size, salt, address(metamoprhicContract), &mem[init_data], implAddress, salt]
418 | create2 // [address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
419 |
420 | // Validate the Creation
421 | dup2 dup2 eq validCreate2Jump // [address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
422 | REVERT_CREATE_TWO_FAILED(0x00) // _reverts_
423 | validCreate2Jump: // [address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
424 |
425 | // Check if either the init data or msg.value are nonzero
426 | dup3 mload iszero // [init_data.length == 0, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
427 | callvalue iszero and // [msg.value == 0 && init_data.length == 0, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
428 | emitEventJump jumpi // [address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
429 |
430 | // Initialize the metamorphic contract
431 | 0x00 // [retSize, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
432 | dup1 // [retOffset, retSize, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
433 | dup5 mload // [argSize, retOffset, retSize, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
434 | dup6 0x20 add // [argOffset, argSize, retOffset, retSize, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
435 | callvalue // [value, argOffset, argSize, retOffset, retSize, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
436 | dup6 // [address, value, argOffset, argSize, retOffset, retSize, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
437 | gas // [gas, address, value, argOffset, argSize, retOffset, retSize, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
438 | call // [success, address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
439 |
440 | // Validate call success
441 | emitEventJump jumpi // [address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
442 | INITIALIZATION_FAILED(0x00) // _reverts_
443 |
444 | // Emit the Metamorphosed event
445 | emitEventJump: // [address(newMetaContract), address(metamoprhicContract), &mem[init_data], implAddress, salt]
446 | dup4 swap1 __EVENT_HASH(Metamorphosed) 0x00 0x00 log3 // [address(metamoprhicContract), &mem[init_data], implAddress, salt]
447 |
448 | // Return the metamorphic contract address
449 | 0x00 mstore // [&mem[init_data], implAddress, salt]
450 | 0x20 0x00 return // _returns_
451 | }
452 |
453 | /// @notice Stateful
454 | /// @notice Equivalent of `deployMetamorphicContractWithConstructor`
455 | /// @notice Deploy a metamorphic contract by submitting a given salt or nonce
456 | /// along with the initialization code to a transient contract which will then
457 | /// deploy the metamorphic contract before immediately selfdestructing. To
458 | /// replace the metamorphic contract, first selfdestruct the current contract,
459 | /// then call with the same salt value and new initialization code (be aware
460 | /// that all existing state will be wiped from the existing contract). Also
461 | /// note that the first 20 bytes of the salt must match the calling address,
462 | /// which prevents contracts from being created by unintended parties.
463 | /// @param salt bytes32 The nonce that will be passed into the CREATE2 call and
464 | /// thus will determine the resulant address of the metamorphic contract.
465 | /// @param initializationCode bytes The initialization code for the metamorphic
466 | /// contract that will be deployed by the transient contract.
467 | /// @return Address of the metamorphic contract that will be created.
468 | #define macro DEPLOY_METAMORPHIC_CONTRACT_WITH_CONSTRUCTOR() = takes (0) returns (0) {
469 | // Load the salt from calldata
470 | 0x04 calldataload // [salt]
471 |
472 | // Load the init code from calldata
473 | 0x24 calldataload // [&calldata[initCode], salt]
474 |
475 | // Load the transient init code storage pointer
476 | [TRANSIENT_CONTRACT_INITIALIZATION_CODE] // [&storage[transientInitCode], &calldata[initCode], salt]
477 |
478 | // Get the transient contract address using the salt
479 | dup3 _COMPUTE_TRANSIENT_ADDRESS() // [address, &storage[transientInitCode], &calldata[initCode], salt]
480 |
481 | // Store the init code in storage
482 | dup1 [INIT_CODES] GET_SLOT_FROM_KEYS(0x00) // [&storage[initCodes], address, &storage[transientInitCode], &calldata[initCode], salt]
483 | dup4 calldataload // [size, &storage[initCodes], address, &storage[transientInitCode], &calldata[initCode], salt]
484 | dup1 dup3 sstore // [size, &storage[initCodes], address, &storage[transientInitCode], &calldata[initCode], salt]
485 | swap1 // [&storage[initCodes], size, address, &storage[transientInitCode], &calldata[initCode], salt]
486 | 0x00 // [i, &storage[initCodes], size, address, &storage[transientInitCode], &calldata[initCode], salt]
487 |
488 | iterateCalldataCode:
489 | dup3 dup2 lt iszero // [i >= size, i, &storage[initCodes], size, address, &storage[transientInitCode], &calldata[initCode], salt]
490 | loadTransientContractInitCode jumpi // [i, &storage[initCodes], size, address, &storage[transientInitCode], &calldata[initCode], salt]
491 | dup6 0x20 add calldataload // [initCodeChunk, i, &storage[initCodes], size, address, &storage[transientInitCode], &calldata[initCode], salt]
492 | swap2 0x20 add // [&storage[initCodes] + 0x20, i, initCodeChunk, size, address, &storage[transientInitCode], &calldata[initCode], salt]
493 | swap2 dup3 sstore // [i, &storage[initCodes] + 0x20, size, address, &storage[transientInitCode], &calldata[initCode], salt]
494 | 0x20 add // [i + 0x20, &storage[initCodes] + 0x20, size, address, &storage[transientInitCode], &calldata[initCode], salt]
495 | iterateCalldataCode jump // [i + 0x20, &storage[initCodes] + 0x20, size, address, &storage[transientInitCode], &calldata[initCode], salt]
496 |
497 | // Load transient contract data and length
498 | loadTransientContractInitCode:
499 | pop pop pop // [address, &storage[transientInitCode], &calldata[initCode], salt]
500 | swap1 // [&storage[transientInitCode], address, &calldata[initCode], salt]
501 | dup1 sload dup1 0x00 mstore // [size, &storage[transientInitCode], address, &calldata[initCode], salt]
502 | 0x00 // [i, size, &storage[transientInitCode], address, &calldata[initCode], salt]
503 | iterateTransientInitCode:
504 | dup2 dup2 lt iszero // [i >= size, i, size, &storage[transientInitCode], address, &calldata[initCode], salt]
505 | createJump jumpi // [i, size, &storage[transientInitCode], address, &calldata[initCode], salt]
506 | dup3 0x20 add dup2 add // [&storage[transientInitCode] + 0x20 + i, i, size, &storage[transientInitCode], address, &calldata[initCode], salt]
507 | sload dup2 0x20 add mstore // [i, size, &storage[transientInitCode], address, &calldata[initCode], salt]
508 | 0x20 add // [i + 0x20, size, &storage[transientInitCode], address, &calldata[initCode], salt]
509 | iterateTransientInitCode jump // [i + 0x20, size, &storage[transientInitCode], address, &calldata[initCode], salt]
510 |
511 | // Deploy with CREATE2
512 | createJump:
513 | swap5 swap1 // [size, salt, &storage[transientInitCode], address, &calldata[initCode], i]
514 | 0x20 // [offset, size, salt, &storage[transientInitCode], address, &calldata[initCode], i]
515 | callvalue // [value, offset, size, salt, &storage[transientInitCode], address, &calldata[initCode], i]
516 | create2 // [deployedAddress, &storage[transientInitCode], address, &calldata[initCode], i]
517 |
518 | // Validate the deployed Addgress
519 | dup3 eq emitMetamorphosed jumpi // [&storage[transientInitCode], address, &calldata[initCode], i]
520 | REVERT_CREATE_TWO_FAILED(0x00) // _reverts_
521 | emitMetamorphosed: // [&storage[transientInitCode], address, &calldata[initCode], i]
522 |
523 | // Get the metamorphic address
524 | pop // [address, &calldata[initCode], i]
525 | dup1 _COMPUTE_ADDRESS_WITH_CONSTRUCTOR() // [metamorphicAddress, address, &calldata[initCode], i]
526 |
527 | // Emit
528 | swap1 dup2 // [metamorphicAddress, address, metamorphicAddress, &calldata[initCode], i]
529 | __EVENT_HASH(Metamorphosed) 0x00 0x00 log3 // [metamorphicAddress, &calldata[initCode], i]
530 |
531 | // Return the metamorphic contract address
532 | 0x00 mstore // [&calldata[initCode], i]
533 | 0x20 0x00 return // _returns_
534 | }
535 |
536 |
537 | // ----------------------------------
538 | // Viewable Functions
539 | // ----------------------------------
540 |
541 |
542 | /// @notice View
543 | /// @notice Equivalent of `getImplementation`
544 | /// @notice Gets the implementation for the msg.sender
545 | /// @notice Called by the constructor of each metamorphic contract
546 | #define macro GET_IMPLEMENTATION() = takes (0) returns (0) {
547 | // Load the implementation from internal mapping
548 | caller [IMPLEMENTATIONS] // [loc, msg.sender]
549 | LOAD_ELEMENT_FROM_KEYS(0x00) // [address(implementation)]
550 |
551 | // Return the implementation address
552 | 0x00 mstore // []
553 | 0x20 0x00 return // _returns_
554 | }
555 |
556 | /// @notice View
557 | /// @notice Equivalent of `getInitializationCode`
558 | /// @notice Gets the initialization code for the msg.sender
559 | /// @notice Called by the constructor of each transient contract
560 | #define macro GET_INIT_CODE() = takes (0) returns (0) {
561 | // Load the init code from the internal mapping
562 | caller [INIT_CODES] // [loc, msg.sender]
563 | LOAD_ELEMENT_FROM_KEYS(0x00) // [init_code]
564 |
565 | // Return the initialization code
566 | 0x00 mstore // []
567 | 0x20 0x00 return // _returns_
568 | }
569 |
570 | /// @notice View
571 | /// @notice Equivalent of `getImplementationContractAddress`
572 | /// @notice Gets the implementation contract for a given metamorphic contract address
573 | /// @param `metamorphic` The metamorphic contract address
574 | #define macro GET_IMPLEMENTATION_FOR_ADDRESS() = takes (0) returns (0) {
575 | // Load the address from calldata
576 | 0x04 calldataload // [address]
577 | [IMPLEMENTATIONS] // [loc, address]
578 | LOAD_ELEMENT_FROM_KEYS(0x00) // [implementation]
579 |
580 | // Return the implementation address
581 | 0x00 mstore // []
582 | 0x20 0x00 return // _returns_
583 | }
584 |
585 | /// @notice View
586 | /// @notice Equivalent of `getMetamorphicContractInstanceInitializationCode`
587 | /// @notice Gets the init code of a metamorphic contract instance
588 | #define macro GET_CONTRACT_INIT_CODE() = takes (0) returns (0) {
589 | // Load the contract address from calldata
590 | 0x04 calldataload // [contract]
591 | [INIT_CODES] // [loc, contract]
592 | LOAD_ELEMENT_FROM_KEYS(0x00) // [init_code]
593 |
594 | // Return the init code
595 | 0x00 mstore // []
596 | 0x20 0x00 return // _returns_
597 | }
598 |
599 | /// @notice View
600 | /// @notice Equivalent of `findMetamorphicContractAddress`
601 | /// @notice Compute the address of the metamorphic contract that will be created upon submitting a given salt to the contract
602 | #define macro COMPUTE_METAMORPHIC_ADDRESS() = takes (0) returns (0) {
603 | // Load the bytes32 salt from calldata
604 | 0x04 calldataload // [salt]
605 |
606 | // Get the metamorphic contract address
607 | _COMPUTE_METAMORPHIC_ADDRESS() // [address]
608 |
609 | // Return
610 | 0x00 mstore // []
611 | 0x20 0x00 return // _returns_
612 | }
613 |
614 | /// @notice View
615 | /// @notice Equivalent of `findTransientContractAddress`
616 | /// @notice Compute the address of the transient contract that will be created upon submitting a given salt to the contract
617 | #define macro COMPUTE_TRANSIENT_ADDRESS() = takes (0) returns (0) {
618 | // Load the bytes32 salt from calldata
619 | 0x04 calldataload // [salt]
620 |
621 | // Get the transient contract address
622 | _COMPUTE_TRANSIENT_ADDRESS() // [address]
623 |
624 | // Return
625 | 0x00 mstore // []
626 | 0x20 0x00 return // _returns_
627 | }
628 |
629 | /// @notice View
630 | /// @notice Equivalent of `findMetamorphicContractAddressWithConstructor`
631 | /// @notice ompute the address of the metamorphic contract that will be created by the transient contract upon submitting a given salt to the contract
632 | #define macro COMPUTE_METAMORPHIC_ADDRESS_WITH_CONSTRUCTOR() = takes (0) returns (0) {
633 | // Load the bytes32 salt from calldata
634 | 0x04 calldataload // [salt]
635 |
636 | // Get the transient contract address
637 | _COMPUTE_TRANSIENT_ADDRESS() // [address]
638 |
639 | // Compute the address of the metamorphic contract deployed via a transient contract
640 | _COMPUTE_ADDRESS_WITH_CONSTRUCTOR() // [address]
641 |
642 | // Return
643 | 0x00 mstore // []
644 | 0x20 0x00 return // _returns_
645 | }
646 |
647 | /// @notice View
648 | /// @notice Equivalent of `getMetamorphicContractInitializationCode`
649 | /// @notice Retrieves the initialization code of metamorphic contracts
650 | #define macro GET_METAMORPHIC_INITIALIZATION_CODE() = takes (0) returns (0) {
651 | [MEAMORPHIC_CONTRACT_INITIALIZATION_CODE] // [init_code]
652 | 0x00 mstore // []
653 | 0x20 0x00 return // _returns_
654 | }
655 |
656 | /// @notice View
657 | /// @notice Equivalent of `getMetamorphicContractInitializationCodeHash`
658 | /// @notice Retrieves the keccak256 hash of the initialization code of metamorphic contracts
659 | #define macro GET_METAMORPHIC_INITIALIZATION_CODE_HASH() = takes (0) returns (0) {
660 | [METAMORPHIC_CONTRACT_INITIALIZATION_CODE_HASH] // [hash]
661 | 0x00 mstore // []
662 | 0x20 0x00 return // _returns_
663 | }
664 |
665 | /// @notice View
666 | /// @notice Equivalent of `getTransientContractInitializationCode`
667 | /// @notice Retrieves the initialization code of transient contracts
668 | #define macro GET_TRANSIENT_INITIALIZATION_CODE() = takes (0) returns (0) {
669 | // TODO: load bytes memory from storage @ TRANSIENT_CONTRACT_INITIALIZATION_CODE
670 |
671 | 0x00 mstore // []
672 | 0x20 0x00 return // _returns_
673 | }
674 |
675 | /// @notice View
676 | /// @notice Equivalent of `getTransientContractInitializationCodeHash`
677 | /// @notice Retrieves the keccak256 hash of the initialization code of transient contracts
678 | #define macro GET_TRANSIENT_INITIALIZATION_CODE_HASH() = takes (0) returns (0) {
679 | [TRANSIENT_CONTRACT_INTIALIZALIZATION_CODE_HASH] // [hash]
680 | 0x00 mstore // []
681 | 0x20 0x00 return // _returns_
682 | }
683 |
684 |
685 | // ----------------------------------
686 | // Internal Helpers
687 | // ----------------------------------
688 |
689 | #define constant CREATE_FAILED = 0x4352454154455f4641494c454400000000000000000000000000000000000000
690 | #define constant CREATE_FAILED_LENGTH = 0x0d
691 |
692 | #define constant CREATE_TWO_FAILED = 0x435245415445325f4641494c4544000000000000000000000000000000000000
693 | #define constant CREATE_TWO_FAILED_LENGTH = 0x0e
694 |
695 | #define constant INITIALIZATION_FAILED = 0x494e495449414c495a4154494f4e5f4641494c45440000000000000000000000
696 | #define constant INITIALIZATION_FAILED_LENGTH = 0x15
697 |
698 | /// @notice Internal
699 | /// @notice Reverts with "CREATE_FAILED"
700 | #define macro REVERT_CREATE_FAILED(condition) = takes (0) returns (0) {
701 | [CREATE_FAILED] // [errStr]
702 | [CREATE_FAILED_LENGTH] // [errLen, errStr]
703 | // [cond, errLen, errStr]
704 | REQUIRE() // []
705 | }
706 |
707 | /// @notice Internal
708 | /// @notice Reverts with "CREATE2_FAILED"
709 | #define macro REVERT_CREATE_TWO_FAILED(condition) = takes (0) returns (0) {
710 | [CREATE_TWO_FAILED] // [errStr]
711 | [CREATE_TWO_FAILED_LENGTH] // [errLen, errStr]
712 | // [cond, errLen, errStr]
713 | REQUIRE() // []
714 | }
715 |
716 | /// @notice Internal
717 | /// @notice Reverts with "INITIALIZATION_FAILED"
718 | #define macro REVERT_INITIALIZATION_FAILED(condition) = takes (0) returns (0) {
719 | [INITIALIZATION_FAILED] // [errStr]
720 | [INITIALIZATION_FAILED_LENGTH] // [errLen, errStr]
721 | // [cond, errLen, errStr]
722 | REQUIRE() // []
723 | }
724 |
725 | /// @notice Internal
726 | /// @notice Calculates the metamorphic contract address given a salt
727 | #define macro _COMPUTE_METAMORPHIC_ADDRESS() = takes (1) returns (1) {
728 | // Input stack: [salt]
729 | // Output stack: [address]
730 |
731 | // Compute the address
732 | [METAMORPHIC_CONTRACT_INITIALIZATION_CODE_HASH] // [hash, salt]
733 | swap1 // [salt, hash]
734 | _COMPUTE_ADDRESS() // [address]
735 | }
736 |
737 | /// @notice Internal
738 | /// @notice Calculates the transient contract address given a salt
739 | #define macro _COMPUTE_TRANSIENT_ADDRESS() = takes (1) returns (1) {
740 | // Input stack: [salt]
741 | // Output stack: [address]
742 |
743 | // Compute the address
744 | [TRANSIENT_CONTRACT_INTIALIZALIZATION_CODE_HASH] // [hash, salt]
745 | swap1 // [salt, hash]
746 | _COMPUTE_ADDRESS() // [address]
747 | }
748 |
749 | /// @notice Internal
750 | /// @notice Calculates a contract address given a particular salt
751 | #define macro _COMPUTE_ADDRESS() = takes (1) returns (1) {
752 | // Input stack: [salt, hash]
753 | // Output stack: [address]
754 |
755 | // Start with 0xff to distinguish from RLP
756 | // Stored in memory @ 0x1f:0x20 (the last byte of the first word)
757 | 0xff 0x00 mstore // [salt]
758 |
759 | // Store this address @ 0x20:0x34
760 | address 0x60 shl 0x20 mstore // [salt]
761 |
762 | // Store the salt @ 0x34:0x54
763 | 0x34 mstore // []
764 |
765 | // Store the code hash @ 0x54:0x74
766 | 0x54 mstore // []
767 |
768 | // Hash the packed data
769 | 0x55 0x1f sha3 // [raw_hash]
770 |
771 | // Clean the upper 12 bytes (96 bits or 0x60)
772 | 0x60 shl 0x60 shr // [address]
773 | }
774 |
775 | #define test TEST_COMPUTE_ADDRESS() = takes (0) returns (0) {
776 | // TODO: use a known pre-image to compute the deterministic address
777 |
778 | }
779 |
780 | /// @notice Internal
781 | /// @notice Computes the address for a metamorphic contract address deployed via a transient contract given the address of the transient contract
782 | #define macro _COMPUTE_ADDRESS_WITH_CONSTRUCTOR() = takes (1) returns (1) {
783 | // Input stack: [address]
784 | // Output stack: [address]
785 |
786 | // Store the first RLP byte @ 0x1f:0x20
787 | 0xd6 0x00 mstore // [address]
788 |
789 | // Store the second RLP byte @ 0x20:0x21
790 | 0x94 0xf8 shl 0x20 mstore // [address]
791 |
792 | // Store the transient contract address @ 0x21:0x35
793 | 0x21 mstore // []
794 |
795 | // Store the nonce @ 0x35:0x36
796 | 0x01 0xf8 shl 0x35 mstore // []
797 |
798 | // Hash the packed data
799 | 0x17 0x1f sha3 // [hash]
800 |
801 | // Clean the upper 12 bytes (96 bits or 0x60)
802 | 0x60 shl 0x60 shr // [address]
803 | }
804 |
805 | #define test TEST_COMPUTE_ADDRESS_WITH_CONSTRUCTOR() = takes (0) returns (0) {
806 | // TODO: test
807 |
808 | }
809 |
810 | /// @notice Modifier to check that the first 20 bytes of a submitted salt match those of the calling account
811 | /// @notice This provides protection against the salt being stolen by frontrunners or other attackers
812 | #define macro CONTAINS_CALLER() = takes (1) returns (0) {
813 | // Input stack: [salt]
814 | 0x60 shr // [calling_account]
815 | caller eq // [msg.sender == calling_account]
816 | __ValidCallingAccountJump jumpi // []
817 | UNAUTHORIZED(0x00) // _reverts
818 | __ValidCallingAccountJump: // []
819 | }
820 |
821 | #define test TEST_CONTAINS_VALID_CALLER() = takes (0) returns (0) {
822 | // Create a valid salt
823 |
824 | }
825 |
826 | #define test FAIL_INVALID_CALLER() = takes (0) returns (0) {
827 | // Invalid salt
828 |
829 | }
830 |
--------------------------------------------------------------------------------
/src/Metapod.huff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/refcell/metamorphic/127dde07e12be1a20b0dcd00191702f0f54191ec/src/Metapod.huff
--------------------------------------------------------------------------------
/src/TransientContract.huff:
--------------------------------------------------------------------------------
1 | /// @title Transient Contract
2 | /// @notice SPDX-License-Identifier: MIT
3 | /// @author asnared
4 | /// @notice A metamorphic contract without transparent proxy reliance
5 | /// @notice Adapted from
6 | /// @notice This contract will create a metamorphic contract, or an upgradeable
7 | /// contract that does not rely on a transparent proxy, when deployed using
8 | /// CREATE2. Unlike with upgradeable transparent proxies, the state of a
9 | /// metamorphic contract will be wiped clean with each upgrade. The metamorphic
10 | /// contract can also use a constructor if desired. With great power comes great
11 | /// responsibility - implement appropriate controls and educate the users of your
12 | /// contract if it will be interacted with!
13 |
14 | /// @notice Transient Contract Deployer must implement this function
15 | #define function getInitializationCode() view returns (bytes memory initializationCode)
16 |
17 | /// @notice Payable
18 | /// @notice Must be called by a contract that implements the `getInitializationCode` function
19 | #define macro CONSTRUCTOR() = takes (0) returns (0) {
20 | // Retrieve the target implementation address from creator of this contract.
21 | __FUNC_SIG(getInitializationCode) 0x00 mstore
22 | 0x00 // [retSize]
23 | 0x00 // [retOffset, retSize]
24 | dup1 // [argSize, retOffset, retSize]
25 | dup1 // [argOffset, argSize, retOffset, retSize]
26 | caller // [msg.sender, argOffset, argSize, retOffset, retSize]
27 | gas // [gas, msg.sender, argOffset, argSize, retOffset, retSize]
28 | staticcall // [success]
29 |
30 | // Revert if the call failed
31 | success jumpi // []
32 | 0x00 dup1 revert // _reverts_
33 | success: // []
34 |
35 | // Copy the initialization code from return data
36 | returndatasize // [retSize]
37 | 0x00 // [retOffset, retSize]
38 | dup1 // [destOffset]
39 | returndatacopy // []
40 |
41 | // Create the contract using the initialization code in memory
42 | 0x00 mload // [initCodeOffset]
43 | dup1 mload // [initCodeSize, initCodeOffset]
44 | swap1 0x20 add // [initCodeOffset, initCodeSize]
45 | callvalue // [value, initCodeOffset, initCodeSize]
46 | create // [address]
47 |
48 | // Check that the address does not equal zero
49 | dup1 valid jumpi // [address]
50 | 0x00 dup1 revert // _reverts_
51 | valid: // [address]
52 |
53 | // Destroy this transient contract
54 | // Forwards the remaining callvalue to the new address
55 | selfdestruct
56 | }
--------------------------------------------------------------------------------
/src/interfaces/IImmutableCreate2Factory.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.15;
3 |
4 | interface IImmutableCreate2Factory {}
5 |
--------------------------------------------------------------------------------
/src/interfaces/IMetamorphicFactory.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.15;
3 |
4 | /// @title Metamorphic Contract Factory Interface
5 | /// @notice An interface to the factory contract that holds a reference to the
6 | /// initialization code that will be used by the transient contract to deploy
7 | /// the metamorphic contract.
8 | interface FactoryInterface {
9 | /// @notice Deploys a metamorphic contract
10 | function deployMetamorphicContract(
11 | bytes32 salt,
12 | bytes calldata implementationContractInitializationCode,
13 | bytes calldata metamorphicContractInitializationCalldata
14 | ) external payable returns (address metamorphicContractAddress);
15 |
16 | /// @notice Deploys a meamorphic contract from a given implementation
17 | function deployMetamorphicContractFromExistingImplementation(
18 | bytes32 salt,
19 | address implementationContract,
20 | bytes calldata metamorphicContractInitializationCalldata
21 | ) external payable returns (address metamorphicContractAddress);
22 |
23 | /// @notice Deploys a metamorphic contract with constructor args
24 | function deployMetamorphicContractWithConstructor(
25 | bytes32 salt,
26 | bytes calldata initializationCode
27 | ) external payable returns (address metamorphicContractAddress);
28 |
29 | /// @notice Returns the implementation address that will be used
30 | function getImplementation() external view returns (address implementation);
31 |
32 | /// @notice Returns the address of the initialization code that will be used
33 | function getInitializationCode()
34 | external
35 | view
36 | returns (bytes memory initializationCode);
37 |
38 | /// @notice Returns the address of the implementation that will be used
39 | function getImplementationContractAddress(
40 | address metamorphicContractAddress
41 | ) external view returns (address implementationContractAddress);
42 |
43 | /// @notice Gets the metamorphic contract initialization code
44 | function getMetamorphicContractInstanceInitializationCode(
45 | address transientContractAddress
46 | ) external view returns (bytes memory initializationCode);
47 |
48 | /// @notice Computes the metamorphic contract address
49 | function findMetamorphicContractAddress(bytes32 salt)
50 | external
51 | view
52 | returns (address metamorphicContractAddress);
53 |
54 | /// @notice Computes the address of the transient contract
55 | function findTransientContractAddress(bytes32 salt)
56 | external
57 | view
58 | returns (address transientContractAddress);
59 |
60 | /// @notice Computes the metamorphic contract address with constructor
61 | function findMetamorphicContractAddressWithConstructor(bytes32 salt)
62 | external
63 | view
64 | returns (address metamorphicContractAddress);
65 |
66 | /// @notice Computes the metamoprhic contract address with initialization code
67 | function getMetamorphicContractInitializationCode()
68 | external
69 | view
70 | returns (bytes memory metamorphicContractInitializationCode);
71 |
72 | /// @notice Computes the initialization code hash for a metamorphic contract
73 | function getMetamorphicContractInitializationCodeHash()
74 | external
75 | view
76 | returns (bytes32 metamorphicContractInitializationCodeHash);
77 |
78 | /// @notice Retrieves the initialization code of a transient contract
79 | function getTransientContractInitializationCode()
80 | external
81 | view
82 | returns (bytes memory transientContractInitializationCode);
83 |
84 | /// @notice Computes the keccak256 hash of a transient contract's initialization code
85 | function getTransientContractInitializationCodeHash()
86 | external
87 | view
88 | returns (bytes32 transientContractInitializationCodeHash);
89 | }
90 |
--------------------------------------------------------------------------------
/src/interfaces/IMetapod.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.15;
3 |
4 | interface IMetapod {}
5 |
--------------------------------------------------------------------------------
/tests/Metamorphic.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.15;
3 |
4 | import {Test} from "forge-std/Test.sol";
5 | import {HuffDeployer} from "foundry-huff/HuffDeployer.sol";
6 |
7 | // import {IMetamorph} from "src/interfaces/IMetamorph.sol";
8 | import {FactoryInterface} from "src/interfaces/IMetamorphicFactory.sol";
9 |
10 | contract MetamorphicFactoryTest is Test {
11 | FactoryInterface internal factory;
12 |
13 | address deployedImplementation = address(0x0);
14 |
15 | function setUp() public {
16 | // Deploy the metamorphic factory contract
17 | bytes
18 | memory construct_args = hex"2c51145c0734d56da60852a03e2aafae8a36ffd8c12b32f1ee8671f229d5dd08530500000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000113b608060405234801561001057600080fd5b50306e2b13cccec913420a21e4d11b2dcd3c1461008e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f496e636f7272656374206465706c6f796d656e7420616464726573732e000000604482015290519081900360640190fd5b7fb7d11e258d6663925ce8e43f07ba3b7792a573ecc2fd7682d01f8a70b222329460001b604051806060016040528060288152602001611113602891396040516020018082805190602001908083835b602083106100fd5780518252601f1990920191602091820191016100de565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201461018e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260318152602001806110e26031913960400191505060405180910390fd5b604080516000815260208101918290525190207fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4701461022e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f496e636f7272656374206861736820666f7220656d70747920646174612e0000604482015290519081900360640190fd5b610ea58061023d6000396000f3fe6080604052600436106100bc5760003560e01c80634b7fa04511610074578063b5714de61161004e578063b5714de6146102ee578063e21f6d3014610318578063eaf53a4514610350576100bc565b80634b7fa0451461028557806357b9f523146102af578063a32cfb69146102c4576100bc565b80631215c971116100a55780631215c971146101725780632d2aae91146101aa5780633190a597146101e4576100bc565b8063010fcf85146100c15780630563ef93146100e8575b600080fd5b3480156100cd57600080fd5b506100d661037a565b60408051918252519081900360200190f35b3480156100f457600080fd5b506100fd61039e565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561013757818101518382015260200161011f565b50505050905090810190601f1680156101645780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561017e57600080fd5b506100d66004803603602081101561019557600080fd5b50356bffffffffffffffffffffffff166103be565b3480156101b657600080fd5b506101e2600480360360208110156101cd57600080fd5b50356bffffffffffffffffffffffff166103cf565b005b610269600480360360408110156101fa57600080fd5b6bffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561022a57600080fd5b82018360208201111561023c57600080fd5b8035906020019184600183028401116401000000008311171561025e57600080fd5b509092509050610504565b604080516001600160a01b039092168252519081900360200190f35b34801561029157600080fd5b50610269600480360360208110156102a857600080fd5b5035610646565b3480156102bb57600080fd5b506100fd610661565b3480156102d057600080fd5b50610269600480360360208110156102e757600080fd5b50356106f7565b3480156102fa57600080fd5b506102696004803603602081101561031157600080fd5b5035610702565b34801561032457600080fd5b506101e26004803603602081101561033b57600080fd5b50356bffffffffffffffffffffffff16610715565b34801561035c57600080fd5b506100fd6004803603602081101561037357600080fd5b50356107ca565b7fb7d11e258d6663925ce8e43f07ba3b7792a573ecc2fd7682d01f8a70b222329490565b6060604051806060016040528060288152602001610e5260289139905090565b60006103c9826107e3565b92915050565b60006103da826107e3565b90506103e5816107eb565b50604080517f58730000000000000000000000000000000000000000000000000000000000006020808301919091523360601b60228301527f905959593031856108fcf150ff0000000000000000000000000000000000000060368301528251602381840301815260439092019092528051610465926000920190610c8a565b5060006060604051806060016040528060288152602001610e5260289139905080602001815184818334f5935050506001600160a01b0382166104f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603e815260200180610ddb603e913960400191505060405180910390fd5b6104fe600080610d08565b50505050565b600080610510856107e3565b905061051e60008585610d4f565b50600061052a826107eb565b905060006060604051806060016040528060288152602001610e5260289139905080602001815185818334f5935050506001600160a01b0382166105cf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4661696c656420746f206465706c6f7920636f6e74726163742e000000000000604482015290519081900360640190fd5b6105d8826108b8565b94506105ec856105e785610939565b6109b0565b6105f7600080610d08565b604080516001600160a01b03871681526020810186905281517fdac6a47173fc05715a5fa4232c433edb0223d14e77705ecee25f76638c4a2ad2929181900390910190a1505050509392505050565b60006103c961065c61065784610aff565b610b9a565b610c11565b60008054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106ed5780601f106106c2576101008083540402835291602001916106ed565b820191906000526020600020905b8154815290600101906020018083116106d057829003601f168201915b5050505050905090565b60006103c982610aff565b60006103c961071083610aff565b6108b8565b6000610720826107e3565b9050600061073061071083610aff565b6040519091506001600160a01b03821690600081818181865af19150503d8060008114610779576040519150601f19603f3d011682016040523d82523d6000602084013e61077e565b606091505b5050604080516001600160a01b03841681526020810185905281517f700c3541b523e60eedc9d8483de029723df0e706473f0243434570393f8fb40393509081900390910190a1505050565b60606103c96107de61065c61065785610aff565b610939565b3360601b1790565b6000806107f783610aff565b9050606061080482610b9a565b905061080f81610c11565b92506001600160a01b03831631156108b157823f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081141561086057816020018251600081836000f55050506108af565b6040516001600160a01b03851690600081818181865af19150503d80600081146108a6576040519150601f19603f3d011682016040523d82523d6000602084013e6108ab565b606091505b5050505b505b5050919050565b604080517fd6940000000000000000000000000000000000000000000000000000000000006020808301919091526001600160a01b0390931660601b60228201527f01000000000000000000000000000000000000000000000000000000000000006036820152815160178183030181526037909101909152805191012090565b604080517f6e2b13cccec913420a21e4d11b2dcd3c3318602b57730000000000000000000060208201526001600160a01b0390921660601b60368301527fff5b000000000000000000000000000000000000000000000000000000000000604a8301528051602c818403018152604c909201905290565b6040805160608101909152602c808252600060208301853c806040516020018082805190602001908083835b602083106109fb5780518252601f1990920191602091820191016109dc565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120826040516020018082805190602001908083835b60208310610a695780518252601f199092019160209182019101610a4a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012014610afa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526039815260200180610e196039913960400191505060405180910390fd5b505050565b604080517fff000000000000000000000000000000000000000000000000000000000000006020808301919091527a2b13cccec913420a21e4d11b2dcd3c000000000000000000000000602183015260358201939093527fb7d11e258d6663925ce8e43f07ba3b7792a573ecc2fd7682d01f8a70b2223294605580830191909152825180830390910181526075909101909152805191012090565b604080517f586e2b13cccec913420a21e4d11b2dcd3c33185857595959303173000000000060208201526001600160a01b0390921660601b603b8301527f5af160315981595939f300000000000000000000000000000000000000000000604f830152805160398184030181526059909201905290565b8051602091820120604080517fff00000000000000000000000000000000000000000000000000000000000000818501527a2b13cccec913420a21e4d11b2dcd3c000000000000000000000000602182015260006035820152605580820193909352815180820390930183526075019052805191012090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610ccb57805160ff1916838001178555610cf8565b82800160010185558215610cf8579182015b82811115610cf8578251825591602001919060010190610cdd565b50610d04929150610dbd565b5090565b50805460018160011615610100020316600290046000825580601f10610d2e5750610d4c565b601f016020900490600052602060002090810190610d4c9190610dbd565b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610d905782800160ff19823516178555610cf8565b82800160010185558215610cf8579182015b82811115610cf8578235825591602001919060010190610da2565b610dd791905b80821115610d045760008155600101610dc3565b9056fe5265636f76657279206661696c6564202d20656e7375726520746861742074686520636f6e747261637420686173206265656e2064657374726f7965642e4465706c6f7965642072756e74696d6520636f646520646f6573206e6f74206861766520746865207265717569726564207072656c7564652e58601c59585992335a6357b9f5235952fa5060403031813d03839281943ef08015602557ff5b80fda165627a7a723058206411f371afb1521ed97b533674cf320a713eaf657fa9416375ed4d1317700f690029496e636f7272656374206861736820666f72207472616e7369656e7420696e697469616c697a6174696f6e20636f64652e58601c59585992335a6357b9f5235952fa5060403031813d03839281943ef08015602557ff5b80fd0000000000";
19 | address factoryAddress = HuffDeployer
20 | .config()
21 | .with_args(construct_args)
22 | .deploy("MetamorphicFactory");
23 | factory = FactoryInterface(factoryAddress);
24 | }
25 |
26 | function testMetadata() public {
27 | address implementation = factory.getImplementation();
28 | assertEq(implementation, deployedImplementation);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------