Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- SafeMigration
- Optimization enabled
- false
- Compiler version
- v0.7.6+commit.7338295f
- EVM Version
- default
- Verified at
- 2026-01-28T16:09:52.482816Z
contracts/libraries/SafeMigration.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import {SafeStorage} from "../libraries/SafeStorage.sol";
interface ISafe {
function setFallbackHandler(address handler) external;
}
/**
* @title Migration Contract for Safe Upgrade
* @notice This is a generic contract that facilitates Safe and SafeL2 proxy contracts to migrate their singleton address.
* The supported target Safe version is immutable and set in the constructor during the deployment of the contract.
* This contract also supports migration with fallback handler update.
* @author @safe-global/safe-protocol
* @dev IMPORTANT: The library is intended to be used with the Safe standard proxy that stores the singleton address
* at the storage slot 0. Use at your own risk with custom proxy implementations. The contract will allow invocations
* to the migration functions only via delegatecall.
*/
contract SafeMigration is SafeStorage {
/**
* @notice Address of this contract
*/
address public immutable MIGRATION_SINGLETON;
/**
* @notice Address of the Safe Singleton implementation
*/
address public immutable SAFE_SINGLETON;
/**
* @notice Address of the Safe Singleton (L2) implementation
*/
address public immutable SAFE_L2_SINGLETON;
/**
* @notice Address of the Fallback Handler
*/
address public immutable SAFE_FALLBACK_HANDLER;
/**
* @notice Event indicating a change of a singleton address. Named master copy here for legacy reasons.
* @param singleton New master copy address
*/
event ChangedMasterCopy(address singleton);
/**
* @notice Modifier to make a function callable via delegatecall only.
* If the function is called via a regular call, it will revert.
*/
modifier onlyDelegateCall() {
require(address(this) != MIGRATION_SINGLETON, "Migration should only be called via delegatecall");
_;
}
/**
* @notice Constructor
* @param safeSingleton Address of the Safe Singleton implementation
* @param safeL2Singleton Address of the SafeL2 Singleton implementation
* @param fallbackHandler Address of the fallback handler implementation
*/
constructor(address safeSingleton, address safeL2Singleton, address fallbackHandler) {
MIGRATION_SINGLETON = address(this);
require(hasCode(safeSingleton), "Safe Singleton is not deployed");
require(hasCode(safeL2Singleton), "Safe Singleton (L2) is not deployed");
require(hasCode(fallbackHandler), "fallback handler is not deployed");
SAFE_SINGLETON = safeSingleton;
SAFE_L2_SINGLETON = safeL2Singleton;
SAFE_FALLBACK_HANDLER = fallbackHandler;
}
/**
* @notice Migrate the Safe contract to a new Safe Singleton implementation.
*/
function migrateSingleton() public onlyDelegateCall {
singleton = SAFE_SINGLETON;
emit ChangedMasterCopy(SAFE_SINGLETON);
}
/**
* @notice Migrate to Safe Singleton and set the fallback handler. This function is intended to be used when migrating
* a Safe to a version which also requires updating fallback handler.
*/
function migrateWithFallbackHandler() external onlyDelegateCall {
migrateSingleton();
ISafe(address(this)).setFallbackHandler(SAFE_FALLBACK_HANDLER);
}
/**
* @notice Migrate the Safe contract to a new Safe Singleton (L2) implementation.
*/
function migrateL2Singleton() public onlyDelegateCall {
singleton = SAFE_L2_SINGLETON;
emit ChangedMasterCopy(SAFE_L2_SINGLETON);
}
/**
* @notice Migrate to Safe Singleton (L2) and set the fallback handler. This function is intended to be used when migrating
* a Safe to a version which also requires updating fallback handler.
*/
function migrateL2WithFallbackHandler() external onlyDelegateCall {
migrateL2Singleton();
ISafe(address(this)).setFallbackHandler(SAFE_FALLBACK_HANDLER);
}
/**
* @notice Checks whether an account has code.
* @param account The address of the account to be checked.
* @return A boolean value indicating whether the address has code (true) or not (false).
* @dev This function relies on the `extcodesize` assembly opcode to determine whether an address has code.
* It does not reliably determine whether or not an address is a smart contract or an EOA.
*/
function hasCode(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;
}
}
contracts/libraries/SafeStorage.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/**
* @title SafeStorage - Storage layout of the Safe contracts to be used in libraries.
* @dev Should be always the first base contract of a library that is used with a Safe.
* @author Richard Meissner - @rmeissner
*/
contract SafeStorage {
// From /common/Singleton.sol
address internal singleton;
// From /common/ModuleManager.sol
mapping(address => address) internal modules;
// From /common/OwnerManager.sol
mapping(address => address) internal owners;
uint256 internal ownerCount;
uint256 internal threshold;
// From /Safe.sol
uint256 internal nonce;
bytes32 internal _deprecatedDomainSeparator;
mapping(bytes32 => uint256) internal signedMessages;
mapping(address => mapping(bytes32 => uint256)) internal approvedHashes;
}
Compiler Settings
{"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":false},"metadata":{"useLiteralContent":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"safeSingleton","internalType":"address"},{"type":"address","name":"safeL2Singleton","internalType":"address"},{"type":"address","name":"fallbackHandler","internalType":"address"}]},{"type":"event","name":"ChangedMasterCopy","inputs":[{"type":"address","name":"singleton","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"MIGRATION_SINGLETON","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"SAFE_FALLBACK_HANDLER","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"SAFE_L2_SINGLETON","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"SAFE_SINGLETON","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrateL2Singleton","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrateL2WithFallbackHandler","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrateSingleton","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrateWithFallbackHandler","inputs":[]}]
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100885760003560e01c80639bf47d6e1161005b5780639bf47d6e14610109578063caa12add1461013d578063ed007fc614610171578063f6682ab01461017b57610088565b806307f464a41461008d5780630d7101f71461009757806368cb3d94146100cb57806372f7a956146100d5575b600080fd5b610095610185565b005b61009f6102f9565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100d361031d565b005b6100dd61046d565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610111610491565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101456104b5565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101796104d9565b005b610183610629565b005b7f000000000000000000000000526643f69b81b008f46d95cd5ced5ec0edffdac673ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16141561022a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603081526020018061079e6030913960400191505060405180910390fd5b7f00000000000000000000000029fcb43b46531bca003ddc8fcb67ffe91900c7626000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f75e41bc35ff1bf14d81d1d2f649c0084a0f974f9289c803ec9898eeec4c8d0b87f00000000000000000000000029fcb43b46531bca003ddc8fcb67ffe91900c762604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b7f000000000000000000000000fd0732dc9e303f09fcef3a7388ad10a83459ec9981565b7f000000000000000000000000526643f69b81b008f46d95cd5ced5ec0edffdac673ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614156103c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603081526020018061079e6030913960400191505060405180910390fd5b6103ca610185565b3073ffffffffffffffffffffffffffffffffffffffff1663f08a03237f000000000000000000000000fd0732dc9e303f09fcef3a7388ad10a83459ec996040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561045357600080fd5b505af1158015610467573d6000803e3d6000fd5b50505050565b7f000000000000000000000000526643f69b81b008f46d95cd5ced5ec0edffdac681565b7f00000000000000000000000029fcb43b46531bca003ddc8fcb67ffe91900c76281565b7f00000000000000000000000041675c099f32341bf84bfc5382af534df5c7461a81565b7f000000000000000000000000526643f69b81b008f46d95cd5ced5ec0edffdac673ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16141561057e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603081526020018061079e6030913960400191505060405180910390fd5b610586610629565b3073ffffffffffffffffffffffffffffffffffffffff1663f08a03237f000000000000000000000000fd0732dc9e303f09fcef3a7388ad10a83459ec996040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561060f57600080fd5b505af1158015610623573d6000803e3d6000fd5b50505050565b7f000000000000000000000000526643f69b81b008f46d95cd5ced5ec0edffdac673ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614156106ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603081526020018061079e6030913960400191505060405180910390fd5b7f00000000000000000000000041675c099f32341bf84bfc5382af534df5c7461a6000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f75e41bc35ff1bf14d81d1d2f649c0084a0f974f9289c803ec9898eeec4c8d0b87f00000000000000000000000041675c099f32341bf84bfc5382af534df5c7461a604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a156fe4d6967726174696f6e2073686f756c64206f6e6c792062652063616c6c6564207669612064656c656761746563616c6ca2646970667358221220225c3ae21c323c66a6ac816f6d90cf900873611c034a6b26050d6022c9efdafd64736f6c63430007060033