Skip to content

Commit

Permalink
Merge pull request #5 from dodger213/migrate-l2-111
Browse files Browse the repository at this point in the history
Migrate l2 111
  • Loading branch information
dodger213 authored Aug 18, 2024
2 parents 42d977f + 2b2f3ac commit 6c21341
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 10 deletions.
18 changes: 8 additions & 10 deletions contracts/libraries/SafeToL2Migration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,6 @@ contract SafeToL2Migration is SafeStorage {
_;
}

/**
* @notice Modifier to prevent using initialized Safes.
* If Safe has a nonce higher than 0, it will revert
*/
modifier onlyNonceZero() {
// Nonce is increased before executing a tx, so first executed tx will have nonce=1
require(nonce == 1, "Safe must have not executed any tx");
_;
}

/**
* @dev Internal function with common migration steps, changes the singleton and emits SafeMultiSigTransaction event
*/
Expand All @@ -76,6 +66,7 @@ contract SafeToL2Migration is SafeStorage {
// Encode nonce, sender, threshold
bytes memory additionalInfo = abi.encode(0, msg.sender, threshold);


// Simulate a L2 transaction so Safe Tx Service indexer picks up the Safe
emit SafeMultiSigTransaction(
MIGRATION_SINGLETON,
Expand All @@ -101,11 +92,13 @@ contract SafeToL2Migration is SafeStorage {
*/
function migrateToL2(address l2Singleton) public onlyDelegateCall onlyNonceZero {
require(address(singleton) != l2Singleton, "Safe is already using the singleton");

bytes32 oldSingletonVersion = keccak256(abi.encodePacked(ISafe(singleton).VERSION()));
bytes32 newSingletonVersion = keccak256(abi.encodePacked(ISafe(l2Singleton).VERSION()));

require(oldSingletonVersion == newSingletonVersion, "L2 singleton must match current version singleton");
// There's no way to make sure if address is a valid singleton, unless we configure the contract for every chain

require(
newSingletonVersion == keccak256(abi.encodePacked("1.3.0")) || newSingletonVersion == keccak256(abi.encodePacked("1.4.1")),
"Provided singleton version is not supported"
Expand All @@ -117,13 +110,16 @@ contract SafeToL2Migration is SafeStorage {
}

/**
* @notice Migrate from Safe 1.1.1 Singleton to 1.3.0 or 1.4.1 L2
* Safe is required to have nonce 0 so backend can support it after the migration
* @dev This function should only be called via a delegatecall to perform the upgrade.
* Singletons version will be checked, so it implies that contracts exist.
* A valid and compatible fallbackHandler needs to be provided, only existance will be checked.
*/
function migrateFromV111(address l2Singleton, address fallbackHandler) public onlyDelegateCall onlyNonceZero {

require(isContract(fallbackHandler), "fallbackHandler is not a contract");

bytes32 oldSingletonVersion = keccak256(abi.encodePacked(ISafe(singleton).VERSION()));
Expand Down Expand Up @@ -156,13 +152,15 @@ contract SafeToL2Migration is SafeStorage {
*/
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 */


// If the code size is greater than 0, it is a contract; otherwise, it is an EOA.
return size > 0;
}
Expand Down
7 changes: 7 additions & 0 deletions test/libraries/SafeToL2Migration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { expect } from "chai";
import hre, { ethers, deployments } from "hardhat";
import { AddressZero } from "@ethersproject/constants";
import { getSafe, getSafeSingletonAt, getMock } from "../utils/setup";

import deploymentData from "../json/safeDeployment.json";
import safeRuntimeBytecode from "../json/safeRuntimeBytecode.json";
import {
Expand All @@ -16,10 +17,12 @@ const SAFE_SINGLETON_141_ADDRESS = "0x3E5c63644E683549055b9Be8653de26E0B4CD36E";

const SAFE_SINGLETON_141_L2_ADDRESS = "0xfb1bffC9d739B8D520DaF37dF666da4C687191EA";


const SAFE_SINGLETON_150_L2_ADDRESS = "0x551A2F9a71bF88cDBef3CBe60E95722f38eE0eAA";

const COMPATIBILITY_FALLBACK_HANDLER_150 = "0x4c95c836D31d329d80d696cb679f3dEa028Ad4e5";


const FALLBACK_HANDLER_STORAGE_SLOT = "0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5";

const GUARD_STORAGE_SLOT = "0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8";
Expand Down Expand Up @@ -52,8 +55,10 @@ describe("SafeToL2Migration library", () => {
const singleton130 = await getSafeSingletonAt(singleton130Address);
const singleton141 = await getSafeSingletonAt(SAFE_SINGLETON_141_ADDRESS);


const guardContract = await hre.ethers.getContractAt("ITransactionGuard", AddressZero);
const guardEip165Calldata = guardContract.interface.encodeFunctionData("supportsInterface", ["0xe6d7a83a"]);

const validGuardMock = await getMock();
await validGuardMock.givenCalldataReturnBool(guardEip165Calldata, true);

Expand Down Expand Up @@ -83,9 +88,11 @@ describe("SafeToL2Migration library", () => {
const safeToL2MigrationContract = await hre.ethers.getContractFactory("SafeToL2Migration");
const migration = await safeToL2MigrationContract.deploy();
return {

safe111: await getSafe({ singleton: singleton111, owners: [user1.address] }),
safe130: await getSafe({ singleton: singleton130, owners: [user1.address] }),
safe141: await getSafe({ singleton: singleton141, owners: [user1.address] }),

safeWith1967Proxy,
migration,
signers,
Expand Down

0 comments on commit 6c21341

Please sign in to comment.