Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add MultisigFactory contract for creating multisig wallets #49

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ deployments/5256.json

.DS_Store

.aider*
yalc.lock
.yalc
154 changes: 154 additions & 0 deletions .openzeppelin/unknown-22040.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
"address": "0xd33aeaC471e077781c08A073491B5c7d974c6645",
"txHash": "0xae6f3627d4174536697a1536fe5522a36c0ff9581c5374a73fd4187bf9caceb0",
"kind": "uups"
},
{
"address": "0x930bafD4580f0ce20E8985Cd38Ee5526A252B14d",
"txHash": "0xe40cbce5a553f2acd6b8f3fc5651a565735394d2ecf3fd52ce5f460f72334ee5",
"kind": "uups"
}
],
"impls": {
Expand Down Expand Up @@ -2188,6 +2193,155 @@
}
}
}
},
"d72b9c478939e3fbf0d0cd1294fdcb550ac3b46a5684e3a14870bd76a6e8afcd": {
"address": "0xB37751C4E07630602cdDC964c15BAF8EeFc872dE",
"txHash": "0x7abb010d82324618cdcbf50b285110aeab51ba41b56d3c668c7027b25a756d6e",
"layout": {
"solcVersion": "0.8.17",
"storage": [
{
"label": "_initialized",
"offset": 0,
"slot": "0",
"type": "t_uint8",
"contract": "Initializable",
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63",
"retypedFrom": "bool"
},
{
"label": "_initializing",
"offset": 1,
"slot": "0",
"type": "t_bool",
"contract": "Initializable",
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68"
},
{
"label": "__gap",
"offset": 0,
"slot": "1",
"type": "t_array(t_uint256)50_storage",
"contract": "ERC1967UpgradeUpgradeable",
"src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169"
},
{
"label": "__gap",
"offset": 0,
"slot": "51",
"type": "t_array(t_uint256)50_storage",
"contract": "UUPSUpgradeable",
"src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111"
},
{
"label": "__gap",
"offset": 0,
"slot": "101",
"type": "t_array(t_uint256)50_storage",
"contract": "ContextUpgradeable",
"src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36"
},
{
"label": "__gap",
"offset": 0,
"slot": "151",
"type": "t_array(t_uint256)50_storage",
"contract": "ERC165Upgradeable",
"src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41"
},
{
"label": "_roles",
"offset": 0,
"slot": "201",
"type": "t_mapping(t_bytes32,t_struct(RoleData)34_storage)",
"contract": "AccessControlUpgradeable",
"src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:62"
},
{
"label": "__gap",
"offset": 0,
"slot": "202",
"type": "t_array(t_uint256)49_storage",
"contract": "AccessControlUpgradeable",
"src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:260"
},
{
"label": "multisigs",
"offset": 0,
"slot": "251",
"type": "t_mapping(t_string_memory_ptr,t_address)",
"contract": "MultisigFactory",
"src": "contracts/multisig/MultisigFactory.sol:15"
}
],
"types": {
"t_address": {
"label": "address",
"numberOfBytes": "20"
},
"t_array(t_uint256)49_storage": {
"label": "uint256[49]",
"numberOfBytes": "1568"
},
"t_array(t_uint256)50_storage": {
"label": "uint256[50]",
"numberOfBytes": "1600"
},
"t_bool": {
"label": "bool",
"numberOfBytes": "1"
},
"t_bytes32": {
"label": "bytes32",
"numberOfBytes": "32"
},
"t_mapping(t_address,t_bool)": {
"label": "mapping(address => bool)",
"numberOfBytes": "32"
},
"t_mapping(t_bytes32,t_struct(RoleData)34_storage)": {
"label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)",
"numberOfBytes": "32"
},
"t_mapping(t_string_memory_ptr,t_address)": {
"label": "mapping(string => address)",
"numberOfBytes": "32"
},
"t_string_memory_ptr": {
"label": "string",
"numberOfBytes": "32"
},
"t_struct(RoleData)34_storage": {
"label": "struct AccessControlUpgradeable.RoleData",
"members": [
{
"label": "members",
"type": "t_mapping(t_address,t_bool)",
"offset": 0,
"slot": "0"
},
{
"label": "adminRole",
"type": "t_bytes32",
"offset": 0,
"slot": "1"
}
],
"numberOfBytes": "64"
},
"t_uint256": {
"label": "uint256",
"numberOfBytes": "32"
},
"t_uint8": {
"label": "uint8",
"numberOfBytes": "1"
},
"t_string_storage": {
"label": "string"
}
}
}
}
}
}
26 changes: 26 additions & 0 deletions contracts/multisig/IMultisigFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

import "./Multisig.sol";
import "./MasterMultisig.sol";

interface IMultisigFactory {
struct MultisigSettings {
address[] signers;
bool[] isInitiatorFlags;
uint threshold;
address owner;
}

// Events
event MultisigCreated(address indexed multisig);
event MultisigRegistered(address indexed multisig);
event MultisigDeleted(address indexed multisig);

function createMultisig(MultisigSettings calldata settings) external returns (address);
function deleteMultisig(address multisigAddress) external;
function registerMultisigs(address[] calldata _multisigsAddresses) external;
function isRegisteredMultisig(address multisig) external view returns (bool);

}

62 changes: 62 additions & 0 deletions contracts/multisig/MultisigFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

import "./Multisig.sol";
import "./MasterMultisig.sol";
import "./IMultisigFactory.sol";

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

contract MultisigFactory is IMultisigFactory, UUPSUpgradeable, AccessControlUpgradeable {
bytes32 constant public CREATOR_ROLE = keccak256("CREATOR_ROLE");

mapping(address => bool) public registeredMultisigs;

function initialize() public initializer {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(CREATOR_ROLE, msg.sender);
__UUPSUpgradeable_init();
}

function createMultisig(MultisigSettings calldata settings) external onlyRole(CREATOR_ROLE) returns (address) {
Multisig newMultisig = new Multisig(
settings.signers,
settings.isInitiatorFlags,
settings.threshold,
settings.owner
);

registeredMultisigs[address(newMultisig)] = true;

emit MultisigCreated(address(newMultisig));
return address(newMultisig);
}

// Register previously deployed multisigs in batch
function registerMultisigs(address[] calldata _multisigs) external onlyRole(CREATOR_ROLE) {
for (uint i = 0; i < _multisigs.length; i++) {
address multisigAddress = _multisigs[i];
require(multisigAddress != address(0), "Invalid multisig address");
require(!registeredMultisigs[multisigAddress], "Already registered");

registeredMultisigs[multisigAddress] = true;

emit MultisigRegistered(multisigAddress);
}
}

function isRegisteredMultisig(address multisig) external view override returns (bool) {
return registeredMultisigs[multisig];
}

function deleteMultisig(address multisigAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(registeredMultisigs[multisigAddress], "Multisig not found");

delete registeredMultisigs[multisigAddress];

emit MultisigDeleted(multisigAddress);
}

function _authorizeUpgrade(address) internal override onlyRole(DEFAULT_ADMIN_ROLE) {}
}
Loading
Loading