Blockchain / Global / Address
Contract
0xd8507c97EBd4D2188A7C79da075823b7767e8d07
- Balance
- 0 SOMI
- Transactions sent
- 83
- Type
- Contract · 4,309 bytes of code
SafeProxyFactory Verified
- Compiler
- solc 0.7.6+commit.7338295f
- Language
- Solidity
- Optimization
- No
- EVM version
- istanbul
- License
- —
- Verified
- 2026-10-12
contracts/proxies/SafeProxyFactory.sol
and 2 more files
Solidity
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import {IProxyCreationCallback} from "./IProxyCreationCallback.sol";
import {SafeProxy} from "./SafeProxy.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 - @Georgi87
*/
contract SafeProxyFactory {
event ProxyCreation(SafeProxy indexed proxy, address singleton);
event ProxyCreationL2(SafeProxy indexed proxy, address singleton, bytes initializer, uint256 saltNonce);
/// @dev Allows to retrieve the creation code used for the Proxy deployment. With this it is easily possible to calculate predicted address.
function proxyCreationCode() public pure returns (bytes memory) {
return type(SafeProxy).creationCode;
}
/**
* @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");
bytes memory deploymentData = abi.encodePacked(type(SafeProxy).creationCode, uint256(uint160(_singleton)));
/* solhint-disable no-inline-assembly */
/// @solidity memory-safe-assembly
assembly {
proxy := create2(0x0, add(0x20, deploymentData), mload(deploymentData), salt)
}
/* solhint-enable no-inline-assembly */
require(address(proxy) != address(0), "Create2 call failed");
if (initializer.length > 0) {
/* solhint-disable no-inline-assembly */
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0)) {
revert(0, 0)
}
}
/* solhint-enable no-inline-assembly */
}
}
/**
* @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 concatenating it
bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
proxy = deployProxy(_singleton, initializer, salt);
emit ProxyCreation(proxy, _singleton);
}
/**
* @notice Deploys a new proxy with `_singleton` singleton and `saltNonce` salt. Optionally executes an initializer call to a new proxy.
* @dev Emits an extra event to allow tracking of `initializer` and `saltNonce`.
* @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 createProxyWithNonceL2(address _singleton, bytes memory initializer, uint256 saltNonce) public returns (SafeProxy proxy) {
proxy = createProxyWithNonce(_singleton, initializer, saltNonce);
emit ProxyCreationL2(proxy, _singleton, initializer, saltNonce);
}
/**
* @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,
uint256 saltNonce
) public returns (SafeProxy proxy) {
// If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatenating it
bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce, getChainId()));
proxy = deployProxy(_singleton, initializer, salt);
emit ProxyCreation(proxy, _singleton);
}
/**
* @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,
uint256 saltNonce,
IProxyCreationCallback callback
) public returns (SafeProxy proxy) {
uint256 saltNonceWithCallback = uint256(keccak256(abi.encodePacked(saltNonce, callback)));
proxy = createProxyWithNonce(_singleton, initializer, saltNonceWithCallback);
if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce);
}
/**
* @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`.
* @dev Emits an extra event to allow tracking of `initializer` and `saltNonce`.
* @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 createProxyWithCallbackL2(
address _singleton,
bytes memory initializer,
uint256 saltNonce,
IProxyCreationCallback callback
) public returns (SafeProxy proxy) {
uint256 saltNonceWithCallback = uint256(keccak256(abi.encodePacked(saltNonce, callback)));
proxy = createProxyWithNonceL2(_singleton, initializer, saltNonceWithCallback);
if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce);
}
/**
* @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 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 no-inline-assembly */
/// @solidity memory-safe-assembly
assembly {
size := extcodesize(account)
}
/* solhint-enable no-inline-assembly */
return size > 0;
}
/**
* @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 no-inline-assembly */
/// @solidity memory-safe-assembly
assembly {
id := chainid()
}
/* solhint-enable no-inline-assembly */
return id;
}
}
Other files
contracts/proxies/IProxyCreationCallback.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.7.0 <0.9.0; import {SafeProxy} from "./SafeProxy.sol"; /** * @title IProxyCreationCallback * @dev An interface for a contract that implements a callback function to be executed after the creation of a proxy instance. */ interface IProxyCreationCallback { /** * @dev Function to be called after the creation of a SafeProxy instance. * @param proxy The newly created SafeProxy instance. * @param _singleton The address of the singleton contract used to create the proxy. * @param initializer The initializer function call data. * @param saltNonce The nonce used to generate the salt for the proxy deployment. */ function proxyCreated(SafeProxy proxy, address _singleton, bytes calldata initializer, uint256 saltNonce) external; }contracts/proxies/SafeProxy.sol
// SPDX-License-Identifier: LGPL-3.0-only /* solhint-disable one-contract-per-file */ pragma solidity >=0.7.0 <0.9.0; /** * @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 - <stefan@gnosis.io> * @author Richard Meissner - <richard@gnosis.io> */ 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. // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt` address internal singleton; /** * @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; } /// @dev Fallback function forwards all transactions and returns all received return data. fallback() external payable { // Note that this assembly block is **intentionally** not marked as memory-safe. First of all, it isn't memory // safe to begin with, and turning this into memory-safe assembly would just make it less gas efficient. // Additionally, we noticed that converting this to memory-safe assembly had no affect on optimizations of other // contracts (as it always gets compiled alone in its own compilation unit anyway). /* solhint-disable no-inline-assembly */ assembly { let _singleton := sload(0) // 0xa619486e == bytes4(keccak256("masterCopy()")). The value is right padded to 32-bytes with 0s if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) { // We mask the singleton address when handling the `masterCopy()` call to ensure that it is correctly // ABI-encoded. We do this by shifting the address left by 96 bits (or 12 bytes) and then storing it in // memory with a 12 byte offset from where the return data starts. Note that we **intentionally** only // do this for the `masterCopy()` call, since the EVM `DELEGATECALL` opcode ignores the most-significant // 12 bytes from the address, so we do not need to make sure the top bytes are cleared when proxying // calls to the `singleton`. This saves us a tiny amount of gas per proxied call. mstore(0x0c, shl(96, _singleton)) return(0, 0x20) } calldatacopy(0, 0, calldatasize()) let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) if iszero(success) { revert(0, returndatasize()) } return(0, returndatasize()) } /* solhint-enable no-inline-assembly */ } }
ABI · 9 entries
json
[
{
"name": "ProxyCreation",
"type": "event",
"inputs": [
{
"name": "proxy",
"type": "address",
"indexed": true,
"internalType": "contract SafeProxy"
},
{
"name": "singleton",
"type": "address",
"indexed": false,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "ProxyCreationL2",
"type": "event",
"inputs": [
{
"name": "proxy",
"type": "address",
"indexed": true,
"internalType": "contract SafeProxy"
},
{
"name": "singleton",
"type": "address",
"indexed": false,
"internalType": "address"
},
{
"name": "initializer",
"type": "bytes",
"indexed": false,
"internalType": "bytes"
},
{
"name": "saltNonce",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "createChainSpecificProxyWithNonce",
"type": "function",
"inputs": [
{
"name": "_singleton",
"type": "address",
"internalType": "address"
},
{
"name": "initializer",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "saltNonce",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "proxy",
"type": "address",
"internalType": "contract SafeProxy"
}
],
"stateMutability": "nonpayable"
},
{
"name": "createProxyWithCallback",
"type": "function",
"inputs": [
{
"name": "_singleton",
"type": "address",
"internalType": "address"
},
{
"name": "initializer",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "saltNonce",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "callback",
"type": "address",
"internalType": "contract IProxyCreationCallback"
}
],
"outputs": [
{
"name": "proxy",
"type": "address",
"internalType": "contract SafeProxy"
}
],
"stateMutability": "nonpayable"
},
{
"name": "createProxyWithCallbackL2",
"type": "function",
"inputs": [
{
"name": "_singleton",
"type": "address",
"internalType": "address"
},
{
"name": "initializer",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "saltNonce",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "callback",
"type": "address",
"internalType": "contract IProxyCreationCallback"
}
],
"outputs": [
{
"name": "proxy",
"type": "address",
"internalType": "contract SafeProxy"
}
],
"stateMutability": "nonpayable"
},
{
"name": "createProxyWithNonce",
"type": "function",
"inputs": [
{
"name": "_singleton",
"type": "address",
"internalType": "address"
},
{
"name": "initializer",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "saltNonce",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "proxy",
"type": "address",
"internalType": "contract SafeProxy"
}
],
"stateMutability": "nonpayable"
},
{
"name": "createProxyWithNonceL2",
"type": "function",
"inputs": [
{
"name": "_singleton",
"type": "address",
"internalType": "address"
},
{
"name": "initializer",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "saltNonce",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "proxy",
"type": "address",
"internalType": "contract SafeProxy"
}
],
"stateMutability": "nonpayable"
},
{
"name": "getChainId",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "proxyCreationCode",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"stateMutability": "pure"
}
]