├── .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 ![tests](https://img.shields.io/github/workflow/status/abigger87/metamorphic/ci/main?label=tests) ![license](https://img.shields.io/github/license/abigger87/metamorphic?label=License) ![solidity](https://img.shields.io/badge/solidity-^0.8.15-lightgrey) ![huff](https://img.shields.io/badge/huff-0.3.0-8b6c5c) 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 | --------------------------------------------------------------------------------