Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/access/Ownable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
"
},
"contracts/utils/MultiSig.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\r
pragma solidity 0.8.20;\r
\r
/**\r
* @title MultiSig\r
* @dev Multi-signature contract that automatically allows registered contracts from Registry\r
* Supports multiple pending transactions from different contracts simultaneously\r
*/\r
contract MultiSig {\r
\r
// =============================================================\r
// STRUCTS\r
// =============================================================\r
\r
struct Transaction {\r
address targetContract; // Contract to call\r
bytes data; // Function call data\r
uint256 approvals; // Current approval count\r
bool executed; // Execution status\r
address proposer; // Who proposed the transaction\r
uint256 timestamp; // When proposed\r
string description; // Human readable description\r
}\r
\r
// =============================================================\r
// STATE VARIABLES\r
// =============================================================\r
\r
/// @notice Array of the 5 authorized signers\r
address[5] public signers;\r
\r
/// @notice Maps transaction ID to transaction details\r
mapping(uint256 => Transaction) public transactions;\r
\r
/// @notice Maps transaction ID to signer address to approval status\r
mapping(uint256 => mapping(address => bool)) public hasApproved;\r
\r
/// @notice Next transaction ID to use\r
uint256 public nextTransactionId;\r
\r
/// @notice Minimum approvals required (3 out of 5)\r
uint256 public constant REQUIRED_APPROVALS = 3;\r
\r
/// @notice Reference to the Registry contract\r
address public registry;\r
\r
/// @notice Maps contract addresses that can delegate to this Multi-Sig\r
mapping(address => bool) public authorizedContracts;\r
\r
// =============================================================\r
// EVENTS\r
// =============================================================\r
\r
/**\r
* @notice Emitted when a transaction is proposed\r
* @param txId The unique transaction ID\r
* @param targetContract The contract the transaction will call\r
* @param proposer The address that proposed the transaction\r
* @param description Human readable description\r
*/\r
event TransactionProposed(\r
uint256 indexed txId,\r
address indexed targetContract,\r
address indexed proposer,\r
string description\r
);\r
\r
/**\r
* @notice Emitted when a signer approves a transaction\r
* @param txId The transaction ID\r
* @param signer The address of the approving signer\r
* @param approvalCount Current approval count\r
*/\r
event TransactionApproved(\r
uint256 indexed txId,\r
address indexed signer,\r
uint256 approvalCount\r
);\r
\r
/**\r
* @notice Emitted when a transaction is executed\r
* @param txId The transaction ID\r
* @param executor The address that executed the transaction\r
* @param targetContract The contract that was called\r
*/\r
event TransactionExecuted(\r
uint256 indexed txId,\r
address indexed executor,\r
address indexed targetContract\r
);\r
\r
/**\r
* @notice Emitted when a contract is authorized to use Multi-Sig\r
* @param contractAddress The address of the authorized contract\r
* @param authorized Whether the contract is authorized\r
*/\r
event ContractAuthorized(\r
address indexed contractAddress,\r
bool authorized\r
);\r
\r
/**\r
* @notice Emitted when signers are updated\r
* @param oldSigners The previous array of signers\r
* @param newSigners The new array of signers\r
*/\r
event SignersUpdated(\r
address[5] oldSigners,\r
address[5] newSigners\r
);\r
\r
// =============================================================\r
// MODIFIERS\r
// =============================================================\r
\r
/**\r
* @dev Modifier to check if the caller is one of the authorized signers\r
*/\r
modifier onlySigner() {\r
require(isSigner(msg.sender), "MultiSig: Not authorized signer");\r
_;\r
}\r
\r
/**\r
* @dev Modifier to check if the caller is an authorized contract\r
*/\r
modifier onlyAuthorizedContract() {\r
require(_isAuthorizedContract(msg.sender), "MultiSig: Not authorized contract");\r
_;\r
}\r
\r
/**\r
* @dev Modifier to check if transaction exists and hasn't been executed\r
*/\r
modifier validTransaction(uint256 txId) {\r
require(txId < nextTransactionId, "MultiSig: Transaction does not exist");\r
require(!transactions[txId].executed, "MultiSig: Transaction already executed");\r
_;\r
}\r
\r
// =============================================================\r
// CONSTRUCTOR\r
// =============================================================\r
\r
/**\r
* @notice Initialize the multi-sig with 5 authorized signers and registry\r
* @param _signer1 First authorized signer address\r
* @param _signer2 Second authorized signer address\r
* @param _signer3 Third authorized signer address\r
* @param _signer4 Fourth authorized signer address\r
* @param _signer5 Fifth authorized signer address\r
* @param _registry Address of the Registry contract\r
*/\r
constructor(\r
address _signer1,\r
address _signer2,\r
address _signer3,\r
address _signer4,\r
address _signer5,\r
address _registry\r
) {\r
require(_signer1 != address(0), "MultiSig: Invalid signer1");\r
require(_signer2 != address(0), "MultiSig: Invalid signer2");\r
require(_signer3 != address(0), "MultiSig: Invalid signer3");\r
require(_signer4 != address(0), "MultiSig: Invalid signer4");\r
require(_signer5 != address(0), "MultiSig: Invalid signer5");\r
\r
require(_signer1 != _signer2 && _signer1 != _signer3 && _signer1 != _signer4 && _signer1 != _signer5 &&\r
_signer2 != _signer3 && _signer2 != _signer4 && _signer2 != _signer5 &&\r
_signer3 != _signer4 && _signer3 != _signer5 &&\r
_signer4 != _signer5,\r
"MultiSig: Duplicate signers not allowed");\r
\r
signers[0] = _signer1;\r
signers[1] = _signer2;\r
signers[2] = _signer3;\r
signers[3] = _signer4;\r
signers[4] = _signer5;\r
registry = _registry;\r
nextTransactionId = 1; // Start from 1 to avoid confusion with default values\r
}\r
\r
// =============================================================\r
// ADMIN FUNCTIONS\r
// =============================================================\r
\r
/**\r
* @notice Authorize a contract to delegate transactions to this Multi-Sig\r
* @param contractAddress The address of the contract to authorize\r
* @param authorized Whether to authorize or deauthorize\r
*/\r
function setAuthorizedContract(address contractAddress, bool authorized) external onlySigner {\r
require(contractAddress != address(0), "MultiSig: Invalid contract address");\r
require(contractAddress != address(this), "MultiSig: Cannot authorize self");\r
\r
// This needs Multi-Sig approval too\r
bytes memory data = abi.encodeWithSignature("_setAuthorizedContract(address,bool)", contractAddress, authorized);\r
uint256 txId = _createTransaction(\r
address(this),\r
data,\r
string(abi.encodePacked("Authorize contract: ", _addressToString(contractAddress)))\r
);\r
\r
// Auto-approve from the proposer\r
hasApproved[txId][msg.sender] = true;\r
transactions[txId].approvals++;\r
\r
emit TransactionProposed(txId, address(this), msg.sender, string(abi.encodePacked("Authorize contract: ", _addressToString(contractAddress))));\r
emit TransactionApproved(txId, msg.sender, transactions[txId].approvals);\r
}\r
\r
/**\r
* @dev Internal function to actually set authorized contract (called after Multi-Sig approval)\r
*/\r
function _setAuthorizedContract(address contractAddress, bool authorized) external {\r
require(msg.sender == address(this), "MultiSig: Only self can call");\r
authorizedContracts[contractAddress] = authorized;\r
emit ContractAuthorized(contractAddress, authorized);\r
}\r
\r
/**\r
* @notice Propose to replace the current signers with new ones (requires Multi-Sig approval)\r
* @param _newSigner1 New first signer address\r
* @param _newSigner2 New second signer address\r
* @param _newSigner3 New third signer address\r
* @param _newSigner4 New fourth signer address\r
* @param _newSigner5 New fifth signer address\r
*/\r
function proposeSignerReplacement(\r
address _newSigner1,\r
address _newSigner2,\r
address _newSigner3,\r
address _newSigner4,\r
address _newSigner5\r
) external onlySigner {\r
require(_newSigner1 != address(0), "MultiSig: Invalid signer1");\r
require(_newSigner2 != address(0), "MultiSig: Invalid signer2");\r
require(_newSigner3 != address(0), "MultiSig: Invalid signer3");\r
require(_newSigner4 != address(0), "MultiSig: Invalid signer4");\r
require(_newSigner5 != address(0), "MultiSig: Invalid signer5");\r
\r
require(_newSigner1 != _newSigner2 && _newSigner1 != _newSigner3 && _newSigner1 != _newSigner4 && _newSigner1 != _newSigner5 &&\r
_newSigner2 != _newSigner3 && _newSigner2 != _newSigner4 && _newSigner2 != _newSigner5 &&\r
_newSigner3 != _newSigner4 && _newSigner3 != _newSigner5 &&\r
_newSigner4 != _newSigner5,\r
"MultiSig: Duplicate signers not allowed");\r
\r
bytes memory data = abi.encodeWithSignature(\r
"_replaceSigners(address,address,address,address,address)",\r
_newSigner1,\r
_newSigner2,\r
_newSigner3,\r
_newSigner4,\r
_newSigner5\r
);\r
\r
uint256 txId = _createTransaction(\r
address(this),\r
data,\r
string(abi.encodePacked(\r
"Replace signers with: ",\r
_addressToString(_newSigner1), ", ",\r
_addressToString(_newSigner2), ", ",\r
_addressToString(_newSigner3), ", ",\r
_addressToString(_newSigner4), ", ",\r
_addressToString(_newSigner5)\r
))\r
);\r
\r
// Auto-approve from the proposer\r
hasApproved[txId][msg.sender] = true;\r
transactions[txId].approvals++;\r
\r
emit TransactionProposed(\r
txId, \r
address(this), \r
msg.sender, \r
"Replace current signers"\r
);\r
emit TransactionApproved(txId, msg.sender, transactions[txId].approvals);\r
}\r
\r
/**\r
* @dev Internal function to actually replace signers (called after Multi-Sig approval)\r
*/\r
function _replaceSigners(\r
address _newSigner1,\r
address _newSigner2,\r
address _newSigner3,\r
address _newSigner4,\r
address _newSigner5\r
) external {\r
require(msg.sender == address(this), "MultiSig: Only self can call");\r
\r
address[5] memory oldSigners = signers;\r
\r
signers[0] = _newSigner1;\r
signers[1] = _newSigner2;\r
signers[2] = _newSigner3;\r
signers[3] = _newSigner4;\r
signers[4] = _newSigner5;\r
\r
emit SignersUpdated(oldSigners, signers);\r
}\r
\r
// =============================================================\r
// DELEGATION FUNCTIONS\r
// =============================================================\r
\r
/**\r
* @notice Called by authorized contracts to delegate a transaction to Multi-Sig\r
* @param targetContract The contract to call after approval\r
* @param data The function call data\r
* @param description Human readable description of the transaction\r
* @return txId The unique transaction ID for tracking\r
*/\r
function delegateTransaction(\r
address targetContract,\r
bytes calldata data,\r
string calldata description\r
) external onlyAuthorizedContract returns (uint256 txId) {\r
require(targetContract != address(0), "MultiSig: Invalid target contract");\r
require(data.length > 0, "MultiSig: Empty transaction data");\r
require(bytes(description).length > 0, "MultiSig: Empty description");\r
\r
txId = _createTransaction(targetContract, data, description);\r
\r
emit TransactionProposed(txId, targetContract, msg.sender, description);\r
\r
return txId;\r
}\r
\r
// =============================================================\r
// APPROVAL FUNCTIONS\r
// =============================================================\r
\r
/**\r
* @notice Approve a pending transaction\r
* @param txId The transaction ID to approve\r
*/\r
function approveTransaction(uint256 txId) external onlySigner validTransaction(txId) {\r
require(!hasApproved[txId][msg.sender], "MultiSig: Already approved");\r
\r
hasApproved[txId][msg.sender] = true;\r
transactions[txId].approvals++;\r
\r
emit TransactionApproved(txId, msg.sender, transactions[txId].approvals);\r
\r
// Auto-execute if we have enough approvals\r
if (transactions[txId].approvals >= REQUIRED_APPROVALS) {\r
_executeTransaction(txId);\r
}\r
}\r
\r
/**\r
* @notice Execute a transaction that has received sufficient approvals\r
* @param txId The transaction ID to execute\r
*/\r
function executeTransaction(uint256 txId) external onlySigner validTransaction(txId) {\r
require(transactions[txId].approvals >= REQUIRED_APPROVALS, "MultiSig: Insufficient approvals");\r
_executeTransaction(txId);\r
}\r
\r
// =============================================================\r
// INTERNAL FUNCTIONS\r
// =============================================================\r
\r
/**\r
* @dev Internal function to create a new transaction\r
*/\r
function _createTransaction(\r
address targetContract,\r
bytes memory data,\r
string memory description\r
) internal returns (uint256 txId) {\r
txId = nextTransactionId++;\r
\r
transactions[txId] = Transaction({\r
targetContract: targetContract,\r
data: data,\r
approvals: 0,\r
executed: false,\r
proposer: msg.sender,\r
timestamp: block.timestamp,\r
description: description\r
});\r
\r
return txId;\r
}\r
\r
/**\r
* @dev Internal function to check if a contract is authorized\r
* Checks manual authorization, Registry registration, and allows Registry itself\r
*/\r
function _isAuthorizedContract(address contractAddress) internal view returns (bool) {\r
// Check manual authorization first\r
if (authorizedContracts[contractAddress]) {\r
return true;\r
}\r
\r
// Allow Registry itself to call\r
if (registry != address(0) && contractAddress == registry) {\r
return true;\r
}\r
\r
// Check Registry registration if registry is set\r
if (registry != address(0)) {\r
// Call the Registry's isRegistered function\r
(bool success, bytes memory data) = registry.staticcall(\r
abi.encodeWithSignature("isRegistered(address)", contractAddress)\r
);\r
\r
if (success && data.length == 32) {\r
return abi.decode(data, (bool));\r
}\r
}\r
\r
return false;\r
}\r
\r
/**\r
* @dev Internal function to execute a transaction\r
*/\r
function _executeTransaction(uint256 txId) internal {\r
Transaction storage txn = transactions[txId];\r
txn.executed = true;\r
\r
(bool success, bytes memory returnData) = txn.targetContract.call(txn.data);\r
require(success, string(abi.encodePacked("MultiSig: Transaction failed: ", string(returnData))));\r
\r
emit TransactionExecuted(txId, msg.sender, txn.targetContract);\r
}\r
\r
/**\r
* @dev Convert address to string for descriptions\r
*/\r
function _addressToString(address addr) internal pure returns (string memory) {\r
bytes32 value = bytes32(uint256(uint160(addr)));\r
bytes memory alphabet = "0123456789abcdef";\r
bytes memory str = new bytes(42);\r
str[0] = '0';\r
str[1] = 'x';\r
for (uint256 i = 0; i < 20; i++) {\r
str[2+i*2] = alphabet[uint8(value[i + 12] >> 4)];\r
str[3+i*2] = alphabet[uint8(value[i + 12] & 0x0f)];\r
}\r
return string(str);\r
}\r
\r
// =============================================================\r
// READ FUNCTIONS\r
// =============================================================\r
\r
/**\r
* @notice Check if an address is one of the authorized signers\r
* @param _address The address to check\r
* @return True if the address is a signer, false otherwise\r
*/\r
function isSigner(address _address) public view returns (bool) {\r
for (uint256 i = 0; i < 5; i++) {\r
if (signers[i] == _address) {\r
return true;\r
}\r
}\r
return false;\r
}\r
\r
/**\r
* @notice Get transaction details\r
* @param txId The transaction ID\r
* @return Transaction details\r
*/\r
function getTransaction(uint256 txId) external view returns (Transaction memory) {\r
require(txId < nextTransactionId, "MultiSig: Transaction does not exist");\r
return transactions[txId];\r
}\r
\r
/**\r
* @notice Check if a signer has approved a specific transaction\r
* @param txId The transaction ID\r
* @param signer The address of the signer to check\r
* @return True if the signer has approved, false otherwise\r
*/\r
function hasSignerApproved(uint256 txId, address signer) external view returns (bool) {\r
return hasApproved[txId][signer];\r
}\r
\r
/**\r
* @notice Get all pending transactions (not executed)\r
* @return Array of transaction IDs that are pending\r
*/\r
function getPendingTransactions() external view returns (uint256[] memory) {\r
uint256[] memory pending = new uint256[](nextTransactionId - 1);\r
uint256 count = 0;\r
\r
for (uint256 i = 1; i < nextTransactionId; i++) {\r
if (!transactions[i].executed) {\r
pending[count] = i;\r
count++;\r
}\r
}\r
\r
// Resize array to actual count\r
uint256[] memory result = new uint256[](count);\r
for (uint256 i = 0; i < count; i++) {\r
result[i] = pending[i];\r
}\r
\r
return result;\r
}\r
\r
/**\r
* @notice Get all signer addresses\r
* @return Array of the 5 signer addresses\r
*/\r
function getSigners() external view returns (address[5] memory) {\r
return signers;\r
}\r
\r
/**\r
* @notice Check if a contract is authorized to use this Multi-Sig\r
* @param contractAddress The contract address to check\r
* @return True if authorized, false otherwise\r
*/\r
function isAuthorizedContract(address contractAddress) external view returns (bool) {\r
return _isAuthorizedContract(contractAddress);\r
}\r
}"
},
"contracts/utils/Registry.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\r
pragma solidity 0.8.20;\r
\r
import "@openzeppelin/contracts/access/Ownable.sol";\r
import "./MultiSig.sol";\r
\r
/**\r
* @title Registry\r
* @dev The bean registry contract for mapping contract names to addresses and tracking registration status.\r
*/\r
contract Registry is Ownable(msg.sender) {\r
/// @notice Maps contract names to their addresses.\r
mapping(string => address) public registry;\r
/// @notice Tracks whether an address is registered.\r
mapping(address => bool) public registered;\r
\r
// =============================================================\r
// EVENTS\r
// =============================================================\r
\r
/**\r
* @notice Emitted when a contract address is set in the registry.\r
* @param name The name of the contract.\r
* @param contractAddress The address of the contract.\r
* @param setter The address that set the registry entry.\r
*/\r
event RegistryAddressSet(\r
string indexed name,\r
address indexed contractAddress,\r
address indexed setter\r
);\r
\r
\r
/**\r
* @notice Emitted when a transaction is delegated to Multi-Sig\r
* @param txId The transaction ID from Multi-Sig\r
* @param caller The address that initiated the call\r
* @param functionName The function being called\r
*/\r
event TransactionDelegated(\r
uint256 indexed txId,\r
address indexed caller,\r
string functionName\r
);\r
\r
// =============================================================\r
// WRITE FUNCTIONS\r
// =============================================================\r
\r
/**\r
* @notice Gets the MultiSig contract instance from registry\r
* @return The MultiSig contract instance, or address(0) if not set\r
*/\r
function _getMultiSig() internal view returns (MultiSig) {\r
address multiSigAddress = registry["MultiSig"];\r
if (multiSigAddress == address(0)) {\r
return MultiSig(address(0));\r
}\r
return MultiSig(multiSigAddress);\r
}\r
\r
/**\r
* @notice Sets the contract address for a given name.\r
* @dev Delegates to Multi-Sig if called by user, executes directly if called by Multi-Sig.\r
* @param _name The name of the contract.\r
* @param _address The address associated with the contract.\r
*/\r
function setContractAddress(\r
string memory _name,\r
address _address\r
) external {\r
MultiSig multiSig = _getMultiSig();\r
if (address(multiSig) != address(0) && msg.sender != address(multiSig)) {\r
// User called this function - delegate to Multi-Sig\r
bytes memory data = abi.encodeWithSignature("setContractAddress(string,address)", _name, _address);\r
string memory description = string(abi.encodePacked("Set contract address: ", _name));\r
\r
uint256 txId = multiSig.delegateTransaction(address(this), data, description);\r
\r
emit TransactionDelegated(txId, msg.sender, "setContractAddress");\r
return;\r
}\r
\r
if (address(multiSig) == address(0)) {\r
require(msg.sender == owner(), "Registry: Only owner can call when Multi-Sig not set");\r
} else {\r
require(msg.sender == address(multiSig), "Registry: Only Multi-Sig can call this function");\r
}\r
\r
require(_address != address(0), "Registry: Cannot set zero address");\r
require(bytes(_name).length > 0, "Registry: Contract name cannot be empty");\r
\r
address existingAddress = registry[_name];\r
\r
if (existingAddress != address(0) && existingAddress != _address) {\r
registered[existingAddress] = false;\r
}\r
\r
registry[_name] = _address;\r
registered[_address] = true;\r
\r
emit RegistryAddressSet(_name, _address, msg.sender);\r
}\r
\r
/**\r
* @notice Toggles the registration status of an address.\r
* @dev Delegates to Multi-Sig if called by user, executes directly if called by Multi-Sig.\r
* @param _address The address to toggle registration status.\r
*/\r
function toggleRegistration(address _address) external {\r
MultiSig multiSig = _getMultiSig();\r
if (address(multiSig) != address(0) && msg.sender != address(multiSig)) {\r
bytes memory data = abi.encodeWithSignature("toggleRegistration(address)", _address);\r
string memory description = string(abi.encodePacked("Toggle registration for: ", _addressToString(_address)));\r
\r
uint256 txId = multiSig.delegateTransaction(address(this), data, description);\r
\r
emit TransactionDelegated(txId, msg.sender, "toggleRegistration");\r
return;\r
}\r
\r
if (address(multiSig) == address(0)) {\r
require(msg.sender == owner(), "Registry: Only owner can call when Multi-Sig not set");\r
} else {\r
require(msg.sender == address(multiSig), "Registry: Only Multi-Sig can call this function");\r
}\r
\r
require(_address != address(0), "Registry: Cannot toggle registration for zero address");\r
\r
registered[_address] = !registered[_address];\r
}\r
\r
// =============================================================\r
// READ FUNCTIONS\r
// =============================================================\r
\r
/**\r
* @notice Retrieves the contract address associated with a given name.\r
* @param _name The name of the contract.\r
* @return The address associated with the provided name.\r
*/\r
function getContractAddress(\r
string memory _name\r
) external view returns (address) {\r
require(\r
registry[_name] != address(0),\r
string(abi.encodePacked("Registry: Does not exist ", _name))\r
);\r
return registry[_name];\r
}\r
\r
/**\r
* @notice Checks if a given address is registered.\r
* @param _address The address to check.\r
* @return True if the address is registered, false otherwise.\r
*/\r
function isRegistered(address _address) external view returns (bool) {\r
return registered[_address];\r
}\r
\r
/**\r
* @notice Get the Multi-Sig contract address\r
* @return The address of the Multi-Sig contract\r
*/\r
function getMultiSig() external view returns (address) {\r
return registry["MultiSig"];\r
}\r
\r
// =============================================================\r
// UTILITY FUNCTIONS\r
// =============================================================\r
\r
/**\r
* @dev Convert address to string for descriptions\r
*/\r
function _addressToString(address addr) internal pure returns (string memory) {\r
bytes32 value = bytes32(uint256(uint160(addr)));\r
bytes memory alphabet = "0123456789abcdef";\r
bytes memory str = new bytes(42);\r
str[0] = '0';\r
str[1] = 'x';\r
for (uint256 i = 0; i < 20; i++) {\r
str[2+i*2] = alphabet[uint8(value[i + 12] >> 4)];\r
str[3+i*2] = alphabet[uint8(value[i + 12] & 0x0f)];\r
}\r
return string(str);\r
}\r
}"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}
}}
Submitted on: 2025-09-27 12:12:41
Comments
Log in to comment.
No comments yet.