567 lines
26 KiB
Solidity
567 lines
26 KiB
Solidity
|
// SPDX-License-Identifier: MIT
|
||
|
|
||
|
pragma solidity 0.5.6;
|
||
|
|
||
|
/**
|
||
|
* @title Metamorphic Contract Factory
|
||
|
* @author 0age
|
||
|
* @notice This contract creates metamorphic contracts, or contracts that can be
|
||
|
* redeployed with new code to the same address. It does so by deploying a
|
||
|
* contract with fixed, non-deterministic initialization code via the CREATE2
|
||
|
* opcode. This contract clones the implementation contract in its constructor.
|
||
|
* Once a contract undergoes metamorphosis, all existing storage will be deleted
|
||
|
* and any existing contract code will be replaced with the deployed contract
|
||
|
* code of the new implementation contract.
|
||
|
* @dev CREATE2 will not be available on mainnet until (at least) block
|
||
|
* 7,280,000. This contract has not yet been fully tested or audited - proceed
|
||
|
* with caution and please share any exploits or optimizations you discover.
|
||
|
*/
|
||
|
contract MetamorphicContractFactory {
|
||
|
// fires when a metamorphic contract is deployed by cloning another contract.
|
||
|
event Metamorphosed(address metamorphicContract, address newImplementation);
|
||
|
|
||
|
// fires when a metamorphic contract is deployed through a transient contract.
|
||
|
event MetamorphosedWithConstructor(address metamorphicContract, address transientContract);
|
||
|
|
||
|
// store the initialization code for metamorphic contracts.
|
||
|
bytes private _metamorphicContractInitializationCode;
|
||
|
|
||
|
// store hash of the initialization code for metamorphic contracts as well.
|
||
|
bytes32 private _metamorphicContractInitializationCodeHash;
|
||
|
|
||
|
// store init code for transient contracts that deploy metamorphic contracts.
|
||
|
bytes private _transientContractInitializationCode;
|
||
|
|
||
|
// store the hash of the initialization code for transient contracts as well.
|
||
|
bytes32 private _transientContractInitializationCodeHash;
|
||
|
|
||
|
// maintain a mapping of metamorphic contracts to metamorphic implementations.
|
||
|
mapping(address => address) private _implementations;
|
||
|
|
||
|
// maintain a mapping of transient contracts to metamorphic init codes.
|
||
|
mapping(address => bytes) private _initCodes;
|
||
|
|
||
|
/**
|
||
|
* @dev In the constructor, set up the initialization code for metamorphic
|
||
|
* contracts as well as the keccak256 hash of the given initialization code.
|
||
|
* @param transientContractInitializationCode bytes The initialization code
|
||
|
* that will be used to deploy any transient contracts, which will deploy any
|
||
|
* metamorphic contracts that require the use of a constructor.
|
||
|
*
|
||
|
* Metamorphic contract initialization code (29 bytes):
|
||
|
*
|
||
|
* 0x5860208158601c335a63aaf10f428752fa158151803b80938091923cf3
|
||
|
*
|
||
|
* Description:
|
||
|
*
|
||
|
* pc|op|name | [stack] | <memory>
|
||
|
*
|
||
|
* ** set the first stack item to zero - used later **
|
||
|
* 00 58 getpc [0] <>
|
||
|
*
|
||
|
* ** set second stack item to 32, length of word returned from staticcall **
|
||
|
* 01 60 push1
|
||
|
* 02 20 outsize [0, 32] <>
|
||
|
*
|
||
|
* ** set third stack item to 0, position of word returned from staticcall **
|
||
|
* 03 81 dup2 [0, 32, 0] <>
|
||
|
*
|
||
|
* ** set fourth stack item to 4, length of selector given to staticcall **
|
||
|
* 04 58 getpc [0, 32, 0, 4] <>
|
||
|
*
|
||
|
* ** set fifth stack item to 28, position of selector given to staticcall **
|
||
|
* 05 60 push1
|
||
|
* 06 1c inpos [0, 32, 0, 4, 28] <>
|
||
|
*
|
||
|
* ** set the sixth stack item to msg.sender, target address for staticcall **
|
||
|
* 07 33 caller [0, 32, 0, 4, 28, caller] <>
|
||
|
*
|
||
|
* ** set the seventh stack item to msg.gas, gas to forward for staticcall **
|
||
|
* 08 5a gas [0, 32, 0, 4, 28, caller, gas] <>
|
||
|
*
|
||
|
* ** set the eighth stack item to selector, "what" to store via mstore **
|
||
|
* 09 63 push4
|
||
|
* 10 aaf10f42 selector [0, 32, 0, 4, 28, caller, gas, 0xaaf10f42] <>
|
||
|
*
|
||
|
* ** set the ninth stack item to 0, "where" to store via mstore ***
|
||
|
* 11 87 dup8 [0, 32, 0, 4, 28, caller, gas, 0xaaf10f42, 0] <>
|
||
|
*
|
||
|
* ** call mstore, consume 8 and 9 from the stack, place selector in memory **
|
||
|
* 12 52 mstore [0, 32, 0, 4, 0, caller, gas] <0xaaf10f42>
|
||
|
*
|
||
|
* ** call staticcall, consume items 2 through 7, place address in memory **
|
||
|
* 13 fa staticcall [0, 1 (if successful)] <address>
|
||
|
*
|
||
|
* ** flip success bit in second stack item to set to 0 **
|
||
|
* 14 15 iszero [0, 0] <address>
|
||
|
*
|
||
|
* ** push a third 0 to the stack, position of address in memory **
|
||
|
* 15 81 dup2 [0, 0, 0] <address>
|
||
|
*
|
||
|
* ** place address from position in memory onto third stack item **
|
||
|
* 16 51 mload [0, 0, address] <>
|
||
|
*
|
||
|
* ** place address to fourth stack item for extcodesize to consume **
|
||
|
* 17 80 dup1 [0, 0, address, address] <>
|
||
|
*
|
||
|
* ** get extcodesize on fourth stack item for extcodecopy **
|
||
|
* 18 3b extcodesize [0, 0, address, size] <>
|
||
|
*
|
||
|
* ** dup and swap size for use by return at end of init code **
|
||
|
* 19 80 dup1 [0, 0, address, size, size] <>
|
||
|
* 20 93 swap4 [size, 0, address, size, 0] <>
|
||
|
*
|
||
|
* ** push code position 0 to stack and reorder stack items for extcodecopy **
|
||
|
* 21 80 dup1 [size, 0, address, size, 0, 0] <>
|
||
|
* 22 91 swap2 [size, 0, address, 0, 0, size] <>
|
||
|
* 23 92 swap3 [size, 0, size, 0, 0, address] <>
|
||
|
*
|
||
|
* ** call extcodecopy, consume four items, clone runtime code to memory **
|
||
|
* 24 3c extcodecopy [size, 0] <code>
|
||
|
*
|
||
|
* ** return to deploy final code in memory **
|
||
|
* 25 f3 return [] *deployed!*
|
||
|
*
|
||
|
*
|
||
|
* Transient contract initialization code derived from TransientContract.sol.
|
||
|
*/
|
||
|
constructor(bytes memory transientContractInitializationCode) public {
|
||
|
// assign the initialization code for the metamorphic contract.
|
||
|
_metamorphicContractInitializationCode = (hex"5860208158601c335a63aaf10f428752fa158151803b80938091923cf3");
|
||
|
|
||
|
// calculate and assign keccak256 hash of metamorphic initialization code.
|
||
|
_metamorphicContractInitializationCodeHash = keccak256(abi.encodePacked(_metamorphicContractInitializationCode));
|
||
|
|
||
|
// store the initialization code for the transient contract.
|
||
|
_transientContractInitializationCode = transientContractInitializationCode;
|
||
|
|
||
|
// calculate and assign keccak256 hash of transient initialization code.
|
||
|
_transientContractInitializationCodeHash = keccak256(abi.encodePacked(_transientContractInitializationCode));
|
||
|
}
|
||
|
|
||
|
/* solhint-disable function-max-lines */
|
||
|
/**
|
||
|
* @dev Deploy a metamorphic contract by submitting a given salt or nonce
|
||
|
* along with the initialization code for the metamorphic contract, and
|
||
|
* optionally provide calldata for initializing the new metamorphic contract.
|
||
|
* To replace the contract, first selfdestruct the current contract, then call
|
||
|
* with the same salt value and new initialization code (be aware that all
|
||
|
* existing state will be wiped from the existing contract). Also note that
|
||
|
* the first 20 bytes of the salt must match the calling address, which
|
||
|
* prevents contracts from being created by unintended parties.
|
||
|
* @param salt bytes32 The nonce that will be passed into the CREATE2 call and
|
||
|
* thus will determine the resulant address of the metamorphic contract.
|
||
|
* @param implementationContractInitializationCode bytes The initialization
|
||
|
* code for the implementation contract for the metamorphic contract. It will
|
||
|
* be used to deploy a new contract that the metamorphic contract will then
|
||
|
* clone in its constructor.
|
||
|
* @param metamorphicContractInitializationCalldata bytes An optional data
|
||
|
* parameter that can be used to atomically initialize the metamorphic
|
||
|
* contract.
|
||
|
* @return Address of the metamorphic contract that will be created.
|
||
|
*/
|
||
|
function deployMetamorphicContract(
|
||
|
bytes32 salt,
|
||
|
bytes calldata implementationContractInitializationCode,
|
||
|
bytes calldata metamorphicContractInitializationCalldata
|
||
|
) external payable containsCaller(salt) returns (address metamorphicContractAddress) {
|
||
|
// move implementation init code and initialization calldata to memory.
|
||
|
bytes memory implInitCode = implementationContractInitializationCode;
|
||
|
bytes memory data = metamorphicContractInitializationCalldata;
|
||
|
|
||
|
// move the initialization code from storage to memory.
|
||
|
bytes memory initCode = _metamorphicContractInitializationCode;
|
||
|
|
||
|
// declare variable to verify successful metamorphic contract deployment.
|
||
|
address deployedMetamorphicContract;
|
||
|
|
||
|
// determine the address of the metamorphic contract.
|
||
|
metamorphicContractAddress = _getMetamorphicContractAddress(salt);
|
||
|
|
||
|
// declare a variable for the address of the implementation contract.
|
||
|
address implementationContract;
|
||
|
|
||
|
// load implementation init code and length, then deploy via CREATE.
|
||
|
/* solhint-disable no-inline-assembly */
|
||
|
assembly {
|
||
|
let encoded_data := add(0x20, implInitCode) // load initialization code.
|
||
|
let encoded_size := mload(implInitCode) // load init code's length.
|
||
|
implementationContract := create(
|
||
|
// call CREATE with 3 arguments.
|
||
|
0, // do not forward any endowment.
|
||
|
encoded_data, // pass in initialization code.
|
||
|
encoded_size // pass in init code's length.
|
||
|
)
|
||
|
} /* solhint-enable no-inline-assembly */
|
||
|
|
||
|
require(implementationContract != address(0), "Could not deploy implementation.");
|
||
|
|
||
|
// store the implementation to be retrieved by the metamorphic contract.
|
||
|
_implementations[metamorphicContractAddress] = implementationContract;
|
||
|
|
||
|
// load metamorphic contract data and length of data and deploy via CREATE2.
|
||
|
/* solhint-disable no-inline-assembly */
|
||
|
assembly {
|
||
|
let encoded_data := add(0x20, initCode) // load initialization code.
|
||
|
let encoded_size := mload(initCode) // load the init code's length.
|
||
|
deployedMetamorphicContract := create2(
|
||
|
// call CREATE2 with 4 arguments.
|
||
|
0, // do not forward any endowment.
|
||
|
encoded_data, // pass in initialization code.
|
||
|
encoded_size, // pass in init code's length.
|
||
|
salt // pass in the salt value.
|
||
|
)
|
||
|
} /* solhint-enable no-inline-assembly */
|
||
|
|
||
|
// ensure that the contracts were successfully deployed.
|
||
|
require(deployedMetamorphicContract == metamorphicContractAddress, "Failed to deploy the new metamorphic contract.");
|
||
|
|
||
|
// initialize the new metamorphic contract if any data or value is provided.
|
||
|
if (data.length > 0 || msg.value > 0) {
|
||
|
/* solhint-disable avoid-call-value */
|
||
|
(bool success, ) = deployedMetamorphicContract.call.value(msg.value)(data);
|
||
|
/* solhint-enable avoid-call-value */
|
||
|
|
||
|
require(success, "Failed to initialize the new metamorphic contract.");
|
||
|
}
|
||
|
|
||
|
emit Metamorphosed(deployedMetamorphicContract, implementationContract);
|
||
|
} /* solhint-enable function-max-lines */
|
||
|
|
||
|
/**
|
||
|
* @dev Deploy a metamorphic contract by submitting a given salt or nonce
|
||
|
* along with the address of an existing implementation contract to clone, and
|
||
|
* optionally provide calldata for initializing the new metamorphic contract.
|
||
|
* To replace the contract, first selfdestruct the current contract, then call
|
||
|
* with the same salt value and a new implementation address (be aware that
|
||
|
* all existing state will be wiped from the existing contract). Also note
|
||
|
* that the first 20 bytes of the salt must match the calling address, which
|
||
|
* prevents contracts from being created by unintended parties.
|
||
|
* @param salt bytes32 The nonce that will be passed into the CREATE2 call and
|
||
|
* thus will determine the resulant address of the metamorphic contract.
|
||
|
* @param implementationContract address The address of the existing
|
||
|
* implementation contract to clone.
|
||
|
* @param metamorphicContractInitializationCalldata bytes An optional data
|
||
|
* parameter that can be used to atomically initialize the metamorphic
|
||
|
* contract.
|
||
|
* @return Address of the metamorphic contract that will be created.
|
||
|
*/
|
||
|
function deployMetamorphicContractFromExistingImplementation(
|
||
|
bytes32 salt,
|
||
|
address implementationContract,
|
||
|
bytes calldata metamorphicContractInitializationCalldata
|
||
|
) external payable containsCaller(salt) returns (address metamorphicContractAddress) {
|
||
|
// move initialization calldata to memory.
|
||
|
bytes memory data = metamorphicContractInitializationCalldata;
|
||
|
|
||
|
// move the initialization code from storage to memory.
|
||
|
bytes memory initCode = _metamorphicContractInitializationCode;
|
||
|
|
||
|
// declare variable to verify successful metamorphic contract deployment.
|
||
|
address deployedMetamorphicContract;
|
||
|
|
||
|
// determine the address of the metamorphic contract.
|
||
|
metamorphicContractAddress = _getMetamorphicContractAddress(salt);
|
||
|
|
||
|
// store the implementation to be retrieved by the metamorphic contract.
|
||
|
_implementations[metamorphicContractAddress] = implementationContract;
|
||
|
|
||
|
// using inline assembly: load data and length of data, then call CREATE2.
|
||
|
/* solhint-disable no-inline-assembly */
|
||
|
assembly {
|
||
|
let encoded_data := add(0x20, initCode) // load initialization code.
|
||
|
let encoded_size := mload(initCode) // load the init code's length.
|
||
|
deployedMetamorphicContract := create2(
|
||
|
// call CREATE2 with 4 arguments.
|
||
|
0, // do not forward any endowment.
|
||
|
encoded_data, // pass in initialization code.
|
||
|
encoded_size, // pass in init code's length.
|
||
|
salt // pass in the salt value.
|
||
|
)
|
||
|
} /* solhint-enable no-inline-assembly */
|
||
|
|
||
|
// ensure that the contracts were successfully deployed.
|
||
|
require(deployedMetamorphicContract == metamorphicContractAddress, "Failed to deploy the new metamorphic contract.");
|
||
|
|
||
|
// initialize the new metamorphic contract if any data or value is provided.
|
||
|
if (data.length > 0 || msg.value > 0) {
|
||
|
/* solhint-disable avoid-call-value */
|
||
|
(bool success, ) = metamorphicContractAddress.call.value(msg.value)(data);
|
||
|
/* solhint-enable avoid-call-value */
|
||
|
|
||
|
require(success, "Failed to initialize the new metamorphic contract.");
|
||
|
}
|
||
|
|
||
|
emit Metamorphosed(deployedMetamorphicContract, implementationContract);
|
||
|
}
|
||
|
|
||
|
/* solhint-disable function-max-lines */
|
||
|
/**
|
||
|
* @dev Deploy a metamorphic contract by submitting a given salt or nonce
|
||
|
* along with the initialization code to a transient contract which will then
|
||
|
* deploy the metamorphic contract before immediately selfdestructing. To
|
||
|
* replace the metamorphic contract, first selfdestruct the current contract,
|
||
|
* then call with the same salt value and new initialization code (be aware
|
||
|
* that all existing state will be wiped from the existing contract). Also
|
||
|
* note that the first 20 bytes of the salt must match the calling address,
|
||
|
* which prevents contracts from being created by unintended parties.
|
||
|
* @param salt bytes32 The nonce that will be passed into the CREATE2 call and
|
||
|
* thus will determine the resulant address of the metamorphic contract.
|
||
|
* @param initializationCode bytes The initialization code for the metamorphic
|
||
|
* contract that will be deployed by the transient contract.
|
||
|
* @return Address of the metamorphic contract that will be created.
|
||
|
*/
|
||
|
function deployMetamorphicContractWithConstructor(bytes32 salt, bytes calldata initializationCode)
|
||
|
external
|
||
|
payable
|
||
|
containsCaller(salt)
|
||
|
returns (address metamorphicContractAddress)
|
||
|
{
|
||
|
// move transient contract initialization code from storage to memory.
|
||
|
bytes memory initCode = _transientContractInitializationCode;
|
||
|
|
||
|
// declare variable to verify successful transient contract deployment.
|
||
|
address deployedTransientContract;
|
||
|
|
||
|
// determine the address of the transient contract.
|
||
|
address transientContractAddress = _getTransientContractAddress(salt);
|
||
|
|
||
|
// store the initialization code to be retrieved by the transient contract.
|
||
|
_initCodes[transientContractAddress] = initializationCode;
|
||
|
|
||
|
// load transient contract data and length of data, then deploy via CREATE2.
|
||
|
/* solhint-disable no-inline-assembly */
|
||
|
assembly {
|
||
|
let encoded_data := add(0x20, initCode) // load initialization code.
|
||
|
let encoded_size := mload(initCode) // load the init code's length.
|
||
|
deployedTransientContract := create2(
|
||
|
// call CREATE2 with 4 arguments.
|
||
|
callvalue, // forward any supplied endowment.
|
||
|
encoded_data, // pass in initialization code.
|
||
|
encoded_size, // pass in init code's length.
|
||
|
salt // pass in the salt value.
|
||
|
)
|
||
|
} /* solhint-enable no-inline-assembly */
|
||
|
|
||
|
// ensure that the contracts were successfully deployed.
|
||
|
require(
|
||
|
deployedTransientContract == transientContractAddress,
|
||
|
"Failed to deploy metamorphic contract using given salt and init code."
|
||
|
);
|
||
|
|
||
|
metamorphicContractAddress = _getMetamorphicContractAddressWithConstructor(transientContractAddress);
|
||
|
|
||
|
emit MetamorphosedWithConstructor(metamorphicContractAddress, transientContractAddress);
|
||
|
} /* solhint-enable function-max-lines */
|
||
|
|
||
|
/**
|
||
|
* @dev View function for retrieving the address of the implementation
|
||
|
* contract to clone. Called by the constructor of each metamorphic contract.
|
||
|
*/
|
||
|
function getImplementation() external view returns (address implementation) {
|
||
|
return _implementations[msg.sender];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev View function for retrieving the initialization code for a given
|
||
|
* metamorphic contract to deploy via a transient contract. Called by the
|
||
|
* constructor of each transient contract.
|
||
|
* @return The initialization code to use to deploy the metamorphic contract.
|
||
|
*/
|
||
|
function getInitializationCode() external view returns (bytes memory initializationCode) {
|
||
|
return _initCodes[msg.sender];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev View function for retrieving the address of the current implementation
|
||
|
* contract of a given metamorphic contract, where the address of the contract
|
||
|
* is supplied as an argument. Be aware that the implementation contract has
|
||
|
* an independent state and may have been altered or selfdestructed from when
|
||
|
* it was last cloned by the metamorphic contract.
|
||
|
* @param metamorphicContractAddress address The address of the metamorphic
|
||
|
* contract.
|
||
|
* @return Address of the corresponding implementation contract.
|
||
|
*/
|
||
|
function getImplementationContractAddress(address metamorphicContractAddress)
|
||
|
external
|
||
|
view
|
||
|
returns (address implementationContractAddress)
|
||
|
{
|
||
|
return _implementations[metamorphicContractAddress];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev View function for retrieving the initialization code for a given
|
||
|
* metamorphic contract instance deployed via a transient contract, where the address
|
||
|
* of the transient contract is supplied as an argument.
|
||
|
* @param transientContractAddress address The address of the transient
|
||
|
* contract that deployed the metamorphic contract.
|
||
|
* @return The initialization code used to deploy the metamorphic contract.
|
||
|
*/
|
||
|
function getMetamorphicContractInstanceInitializationCode(address transientContractAddress)
|
||
|
external
|
||
|
view
|
||
|
returns (bytes memory initializationCode)
|
||
|
{
|
||
|
return _initCodes[transientContractAddress];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Compute the address of the metamorphic contract that will be created
|
||
|
* upon submitting a given salt to the contract.
|
||
|
* @param salt bytes32 The nonce passed into CREATE2 by metamorphic contract.
|
||
|
* @return Address of the corresponding metamorphic contract.
|
||
|
*/
|
||
|
function findMetamorphicContractAddress(bytes32 salt) external view returns (address metamorphicContractAddress) {
|
||
|
// determine the address where the metamorphic contract will be deployed.
|
||
|
metamorphicContractAddress = _getMetamorphicContractAddress(salt);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Compute the address of the transient contract that will be created
|
||
|
* upon submitting a given salt to the contract.
|
||
|
* @param salt bytes32 The nonce passed into CREATE2 when deploying the
|
||
|
* transient contract.
|
||
|
* @return Address of the corresponding transient contract.
|
||
|
*/
|
||
|
function findTransientContractAddress(bytes32 salt) external view returns (address transientContractAddress) {
|
||
|
// determine the address where the transient contract will be deployed.
|
||
|
transientContractAddress = _getTransientContractAddress(salt);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Compute the address of the metamorphic contract that will be created
|
||
|
* by the transient contract upon submitting a given salt to the contract.
|
||
|
* @param salt bytes32 The nonce passed into CREATE2 when deploying the
|
||
|
* transient contract.
|
||
|
* @return Address of the corresponding metamorphic contract.
|
||
|
*/
|
||
|
function findMetamorphicContractAddressWithConstructor(bytes32 salt)
|
||
|
external
|
||
|
view
|
||
|
returns (address metamorphicContractAddress)
|
||
|
{
|
||
|
// determine the address of the metamorphic contract.
|
||
|
metamorphicContractAddress = _getMetamorphicContractAddressWithConstructor(_getTransientContractAddress(salt));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev View function for retrieving the initialization code of metamorphic
|
||
|
* contracts for purposes of verification.
|
||
|
*/
|
||
|
function getMetamorphicContractInitializationCode() external view returns (bytes memory metamorphicContractInitializationCode) {
|
||
|
return _metamorphicContractInitializationCode;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev View function for retrieving the keccak256 hash of the initialization
|
||
|
* code of metamorphic contracts for purposes of verification.
|
||
|
*/
|
||
|
function getMetamorphicContractInitializationCodeHash()
|
||
|
external
|
||
|
view
|
||
|
returns (bytes32 metamorphicContractInitializationCodeHash)
|
||
|
{
|
||
|
return _metamorphicContractInitializationCodeHash;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev View function for retrieving the initialization code of transient
|
||
|
* contracts for purposes of verification.
|
||
|
*/
|
||
|
function getTransientContractInitializationCode() external view returns (bytes memory transientContractInitializationCode) {
|
||
|
return _transientContractInitializationCode;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev View function for retrieving the keccak256 hash of the initialization
|
||
|
* code of transient contracts for purposes of verification.
|
||
|
*/
|
||
|
function getTransientContractInitializationCodeHash() external view returns (bytes32 transientContractInitializationCodeHash) {
|
||
|
return _transientContractInitializationCodeHash;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Internal view function for calculating a metamorphic contract address
|
||
|
* given a particular salt.
|
||
|
*/
|
||
|
function _getMetamorphicContractAddress(bytes32 salt) internal view returns (address) {
|
||
|
// determine the address of the metamorphic contract.
|
||
|
return
|
||
|
address(
|
||
|
uint160( // downcast to match the address type.
|
||
|
uint256( // convert to uint to truncate upper digits.
|
||
|
keccak256( // compute the CREATE2 hash using 4 inputs.
|
||
|
abi.encodePacked( // pack all inputs to the hash together.
|
||
|
hex"ff", // start with 0xff to distinguish from RLP.
|
||
|
address(this), // this contract will be the caller.
|
||
|
salt, // pass in the supplied salt value.
|
||
|
_metamorphicContractInitializationCodeHash // the init code hash.
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Internal view function for calculating a transient contract address
|
||
|
* given a particular salt.
|
||
|
*/
|
||
|
function _getTransientContractAddress(bytes32 salt) internal view returns (address) {
|
||
|
// determine the address of the transient contract.
|
||
|
return
|
||
|
address(
|
||
|
uint160( // downcast to match the address type.
|
||
|
uint256( // convert to uint to truncate upper digits.
|
||
|
keccak256( // compute the CREATE2 hash using 4 inputs.
|
||
|
abi.encodePacked( // pack all inputs to the hash together.
|
||
|
hex"ff", // start with 0xff to distinguish from RLP.
|
||
|
address(this), // this contract will be the caller.
|
||
|
salt, // pass in the supplied salt value.
|
||
|
_transientContractInitializationCodeHash // supply init code hash.
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Internal view function for calculating a metamorphic contract address
|
||
|
* that has been deployed via a transient contract given the address of the
|
||
|
* transient contract.
|
||
|
*/
|
||
|
function _getMetamorphicContractAddressWithConstructor(address transientContractAddress) internal pure returns (address) {
|
||
|
// determine the address of the metamorphic contract.
|
||
|
return
|
||
|
address(
|
||
|
uint160( // downcast to match the address type.
|
||
|
uint256( // set to uint to truncate upper digits.
|
||
|
keccak256( // compute CREATE hash via RLP encoding.
|
||
|
abi.encodePacked( // pack all inputs to the hash together.
|
||
|
bytes1(0xd6), // first RLP byte.
|
||
|
bytes1(0x94), // second RLP byte.
|
||
|
transientContractAddress, // called by the transient contract.
|
||
|
bytes1(0x01) // nonce begins at 1 for contracts.
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Modifier to ensure that the first 20 bytes of a submitted salt match
|
||
|
* those of the calling account. This provides protection against the salt
|
||
|
* being stolen by frontrunners or other attackers.
|
||
|
* @param salt bytes32 The salt value to check against the calling address.
|
||
|
*/
|
||
|
modifier containsCaller(bytes32 salt) {
|
||
|
// prevent contract submissions from being stolen from tx.pool by requiring
|
||
|
// that the first 20 bytes of the submitted salt match msg.sender.
|
||
|
require(address(bytes20(salt)) == msg.sender, "Invalid salt - first 20 bytes of the salt must match calling address.");
|
||
|
_;
|
||
|
}
|
||
|
}
|