-
Notifications
You must be signed in to change notification settings - Fork 987
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
69 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,28 @@ | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
pragma solidity >=0.7.0 <0.9.0; | ||
|
||
/// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain | ||
/// @author Richard Meissner - <[email protected]> | ||
/** | ||
* @title IProxy - Helper interface to access the singleton address of the Proxy on-chain. | ||
* @author Richard Meissner - @rmeissner | ||
*/ | ||
interface IProxy { | ||
function masterCopy() external view returns (address); | ||
} | ||
|
||
/// @title SafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. | ||
/// @author Stefan George - <[email protected]> | ||
/// @author Richard Meissner - <[email protected]> | ||
/** | ||
* @title SafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. | ||
* @author Stefan George - <[email protected]> | ||
* @author Richard Meissner - <[email protected]> | ||
*/ | ||
contract SafeProxy { | ||
// singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated. | ||
// Singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated. | ||
// To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt` | ||
address internal singleton; | ||
|
||
/// @dev Constructor function sets address of singleton contract. | ||
/// @param _singleton Singleton address. | ||
/** | ||
* @notice Constructor function sets address of singleton contract. | ||
* @param _singleton Singleton address. | ||
*/ | ||
constructor(address _singleton) { | ||
require(_singleton != address(0), "Invalid singleton address provided"); | ||
singleton = _singleton; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,10 @@ pragma solidity >=0.7.0 <0.9.0; | |
import "./SafeProxy.sol"; | ||
import "./IProxyCreationCallback.sol"; | ||
|
||
/// @title Proxy Factory - Allows to create a new proxy contract and execute a message call to the new proxy within one transaction. | ||
/// @author Stefan George - <[email protected]> | ||
/** | ||
* @title Proxy Factory - Allows to create a new proxy contract and execute a message call to the new proxy within one transaction. | ||
* @author Stefan George - @Georgi87 | ||
*/ | ||
contract SafeProxyFactory { | ||
event ProxyCreation(SafeProxy proxy, address singleton); | ||
|
||
|
@@ -14,11 +16,13 @@ contract SafeProxyFactory { | |
return type(SafeProxy).creationCode; | ||
} | ||
|
||
/// @dev Allows to create a new proxy contract using CREATE2. Optionally executes an initializer call to a new proxy. | ||
/// This method is only meant as an utility to be called from other methods | ||
/// @param _singleton Address of singleton contract. Must be deployed at the time of execution. | ||
/// @param initializer Payload for a message call to be sent to a new proxy contract. | ||
/// @param salt Create2 salt to use for calculating the address of the new proxy contract. | ||
/** | ||
* @notice Internal method to create a new proxy contract using CREATE2. Optionally executes an initializer call to a new proxy. | ||
* @param _singleton Address of singleton contract. Must be deployed at the time of execution. | ||
* @param initializer (Optional) Payload for a message call to be sent to a new proxy contract. | ||
* @param salt Create2 salt to use for calculating the address of the new proxy contract. | ||
* @return proxy Address of the new proxy contract. | ||
*/ | ||
function deployProxy(address _singleton, bytes memory initializer, bytes32 salt) internal returns (SafeProxy proxy) { | ||
require(isContract(_singleton), "Singleton contract not deployed"); | ||
|
||
|
@@ -39,22 +43,27 @@ contract SafeProxyFactory { | |
} | ||
} | ||
|
||
/// @dev Allows to create a new proxy contract and execute a message call to the new proxy within one transaction. | ||
/// @param _singleton Address of singleton contract. Must be deployed at the time of execution. | ||
/// @param initializer Payload for a message call to be sent to a new proxy contract. | ||
/// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract. | ||
/** | ||
* @notice Deploys a new proxy with `_singleton` singleton and `saltNonce` salt. Optionally executes an initializer call to a new proxy. | ||
* @param _singleton Address of singleton contract. Must be deployed at the time of execution. | ||
* @param initializer Payload for a message call to be sent to a new proxy contract. | ||
* @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract. | ||
*/ | ||
function createProxyWithNonce(address _singleton, bytes memory initializer, uint256 saltNonce) public returns (SafeProxy proxy) { | ||
// If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatinating it | ||
bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce)); | ||
proxy = deployProxy(_singleton, initializer, salt); | ||
emit ProxyCreation(proxy, _singleton); | ||
} | ||
|
||
/// @dev Allows to create a new proxy contract that should exist only on 1 network (e.g. specific governance or admin accounts) | ||
/// by including the chain id in the create2 salt. Such proxies cannot be created on other networks by replaying the transaction. | ||
/// @param _singleton Address of singleton contract. Must be deployed at the time of execution. | ||
/// @param initializer Payload for a message call to be sent to a new proxy contract. | ||
/// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract. | ||
/** | ||
* @notice Deploys a new chain-specific proxy with `_singleton` singleton and `saltNonce` salt. Optionally executes an initializer call to a new proxy. | ||
* @dev Allows to create a new proxy contract that should exist only on 1 network (e.g. specific governance or admin accounts) | ||
* by including the chain id in the create2 salt. Such proxies cannot be created on other networks by replaying the transaction. | ||
* @param _singleton Address of singleton contract. Must be deployed at the time of execution. | ||
* @param initializer Payload for a message call to be sent to a new proxy contract. | ||
* @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract. | ||
*/ | ||
function createChainSpecificProxyWithNonce( | ||
address _singleton, | ||
bytes memory initializer, | ||
|
@@ -66,11 +75,14 @@ contract SafeProxyFactory { | |
emit ProxyCreation(proxy, _singleton); | ||
} | ||
|
||
/// @dev Allows to create a new proxy contract, execute a message call to the new proxy and call a specified callback within one transaction | ||
/// @param _singleton Address of singleton contract. Must be deployed at the time of execution. | ||
/// @param initializer Payload for a message call to be sent to a new proxy contract. | ||
/// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract. | ||
/// @param callback Callback that will be invoked after the new proxy contract has been successfully deployed and initialized. | ||
/** | ||
* @notice Deploy a new proxy with `_singleton` singleton and `saltNonce` salt. | ||
* Optionally executes an initializer call to a new proxy and calls a specified callback address `callback`. | ||
* @param _singleton Address of singleton contract. Must be deployed at the time of execution. | ||
* @param initializer Payload for a message call to be sent to a new proxy contract. | ||
* @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract. | ||
* @param callback Callback that will be invoked after the new proxy contract has been successfully deployed and initialized. | ||
*/ | ||
function createProxyWithCallback( | ||
address _singleton, | ||
bytes memory initializer, | ||
|
@@ -82,8 +94,13 @@ contract SafeProxyFactory { | |
if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce); | ||
} | ||
|
||
/// @dev Returns true if `account` is a contract. | ||
/// @param account The address being queried | ||
/** | ||
* @notice Returns true if `account` is a contract. | ||
* @dev This function will return false if invoked during the constructor of a contract, | ||
* as the code is not actually created until after the constructor finishes. | ||
* @param account The address being queried | ||
* @return True if `account` is a contract | ||
*/ | ||
function isContract(address account) internal view returns (bool) { | ||
uint256 size; | ||
// solhint-disable-next-line no-inline-assembly | ||
|
@@ -93,7 +110,10 @@ contract SafeProxyFactory { | |
return size > 0; | ||
} | ||
|
||
/// @dev Returns the chain id used by this contract. | ||
/** | ||
* @notice Returns the ID of the chain the contract is currently deployed on. | ||
* @return The ID of the current chain as a uint256. | ||
*/ | ||
function getChainId() public view returns (uint256) { | ||
uint256 id; | ||
// solhint-disable-next-line no-inline-assembly | ||
|