Skip to content

Commit

Permalink
Merge branch 'main' into getsafe
Browse files Browse the repository at this point in the history
  • Loading branch information
dodger213 authored Aug 18, 2024
2 parents 4d1659d + 6c21341 commit 9c61643
Show file tree
Hide file tree
Showing 20 changed files with 2,301 additions and 1,998 deletions.
18 changes: 0 additions & 18 deletions .eslintrc.js

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: safe-smart-account
on: [push, pull_request]
env:
NODE_VERSION: 18.17.1
NODE_VERSION: 20.16.0

jobs:
lint-solidity:
Expand Down
65 changes: 65 additions & 0 deletions certora/specs/Safe2.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
methods {
//
function getThreshold() external returns (uint256) envfree;
function disableModule(address,address) external;
function nonce() external returns (uint256) envfree;

// harnessed
function getModule(address) external returns (address) envfree;
function getOwnersCount() external returns (uint256) envfree;
function getOwnersCountFromArray() external returns (uint256) envfree;

// optional
function execTransactionFromModuleReturnData(address,uint256,bytes,SafeHarness.Operation) external returns (bool, bytes memory);
function execTransactionFromModule(address,uint256,bytes,SafeHarness.Operation) external returns (bool);
function execTransaction(address,uint256,bytes,SafeHarness.Operation,uint256,uint256,uint256,address,address,bytes) external returns (bool);

}

definition noHavoc(method f) returns bool =
f.selector != sig:execTransactionFromModuleReturnData(address,uint256,bytes,SafeHarness.Operation).selector
&& f.selector != sig:execTransactionFromModule(address,uint256,bytes,SafeHarness.Operation).selector
&& f.selector != sig:execTransaction(address,uint256,bytes,SafeHarness.Operation,uint256,uint256,uint256,address,address,bytes).selector;

definition reachableOnly(method f) returns bool =
f.selector != sig:setup(address[],uint256,address,bytes,address,address,uint256,address).selector
&& f.selector != sig:simulateAndRevert(address,bytes).selector;

definition ownerUpdatingFunctions(method f) returns bool =
f.selector != sig:addOwnerWithThreshold(address,uint256).selector
&& f.selector != sig:removeOwner(address,address,uint256).selector;


invariant safeIsSetup() getThreshold() > 0;

invariant safeOwnerCountConsistency() getOwnersCount() == getOwnersCountFromArray();

invariant threholdShouldBeLessThanOwners() getOwnersCount() >= getThreshold();

invariant safeOwnerCannotBeItself(env e) !isOwner(e, currentContract);

invariant safeOwnerCannotBeSentinelAddress(env e) !isOwner(e, 1);

rule safeOwnerCountCannotBeUpdatedByNonOwnerUpdatingFunctions(method f) filtered {
f -> ownerUpdatingFunctions(f)
}
{
requireInvariant safeIsSetup;
uint256 ownerCountBefore = getOwnersCount();
calldataarg args; env e;
f(e, args);
uint256 ownerCountAfter = getOwnersCount();
assert ownerCountAfter == ownerCountBefore;
}

rule onlyEnableModuleFunctionCanAddModule(method f, address moduleAddress) filtered {
f -> f.selector != sig: enableModule(address).selector
}
{
requireInvariant safeIsSetup;
calldataarg args; env e;
require !isModuleEnabled(e, moduleAddress);
f(e, args);
assert !isModuleEnabled(e, moduleAddress);

}
2 changes: 2 additions & 0 deletions contracts/SafeL2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ contract SafeL2 is Safe {

/**
* @inheritdoc ModuleManager
*/
function onBeforeExecTransactionFromModule(address to, uint256 value, bytes memory data, Enum.Operation operation) internal override {
emit SafeModuleTransaction(msg.sender, to, value, data, operation);

}
}
1 change: 1 addition & 0 deletions contracts/base/ModuleManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager {

/**
* @notice A hook that gets called before execution of {execTransactionFromModule*} methods.
* @param to Destination address of module transaction.
* @param value Ether value of module transaction.
* @param data Data payload of module transaction.
Expand Down
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
2 changes: 1 addition & 1 deletion contracts/test/ERC20Token.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ contract ERC20Token is ERC20 {
/**
* @dev Constructor that sets the name and symbol of the token and mints an initial supply to the contract deployer.
*/
constructor() public ERC20("TestToken", "TT") {
constructor() ERC20("TestToken", "TT") {
_mint(msg.sender, 1000000000000000);
}
}
20 changes: 20 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import prettier from "eslint-plugin-prettier/recommended";
import noOnlyTests from "eslint-plugin-no-only-tests";

export default [
eslint.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/no-unused-vars": ["error", { ignoreRestSiblings: true }],
},
plugins: {
noOnlyTests,
},
},
prettier,
];
Loading

0 comments on commit 9c61643

Please sign in to comment.