// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MSW is Ownable, ReentrancyGuard { uint256 public requiredConfirmations; mapping(address => bool) public isOwner; address[] public owners; struct Transaction { address to; uint256 value; bytes data; bool executed; mapping(address => bool) confirmations; uint256 confirmationCount; } mapping(uint256 => Transaction) public transactions; uint256 public transactionCount; event OwnershipAdded(address indexed newOwner); event OwnershipRemoved(address indexed removedOwner); event TransactionCreated(uint256 indexed transactionId, address indexed to, uint256 value, bytes data); event TransactionConfirmed(uint256 indexed transactionId, address indexed confirmer); event TransactionExecuted(uint256 indexed transactionId); modifier onlyOwnerOrConfirmed(uint256 transactionId) { require(isOwner[msg.sender] || transactions[transactionId].executed, "Not authorized"); _; } modifier validTransaction(uint256 transactionId) { require(transactionId < transactionCount, "Invalid transaction ID"); _; } constructor(address[] memory _owners, uint256 _requiredConfirmations) { require(_owners.length > 0, "Owners required"); require(_requiredConfirmations > 0 && _requiredConfirmations <= _owners.length, "Invalid required confirmations"); for (uint256 i = 0; i < _owners.length; i++) { address owner = _owners[i]; require(owner != address(0) && !isOwner[owner], "Invalid owner address"); isOwner[owner] = true; owners.push(owner); emit OwnershipAdded(owner); } requiredConfirmations = _requiredConfirmations; } function addOwner(address newOwner) external onlyOwner nonReentrant { require(newOwner != address(0) && !isOwner[newOwner], "Invalid new owner"); isOwner[newOwner] = true; owners.push(newOwner); emit OwnershipAdded(newOwner); } function removeOwner(address removedOwner) external onlyOwner nonReentrant { require(isOwner[removedOwner], "Invalid owner to remove"); require(owners.length - 1 >= requiredConfirmations, "Cannot remove owner, not enough owners for confirmations"); isOwner[removedOwner] = false; for (uint256 i = 0; i < owners.length; i++) { if (owners[i] == removedOwner) { owners[i] = owners[owners.length - 1]; owners.pop(); emit OwnershipRemoved(removedOwner); break; } } } function createTransaction(address to, uint256 value, bytes memory data) external onlyOwner nonReentrant { uint256 transactionId = transactionCount; transactions[transactionId] = Transaction({ to: to, value: value, data: data, executed: false, confirmationCount: 0 }); transactionCount++; emit TransactionCreated(transactionId, to, value, data); } function confirmTransaction(uint256 transactionId) external onlyOwnerOrConfirmed(transactionId) validTransaction(transactionId) nonReentrant { require(!transactions[transactionId].executed, "Transaction already executed"); require(!transactions[transactionId].confirmations[msg.sender], "Already confirmed"); transactions[transactionId].confirmations[msg.sender] = true; transactions[transactionId].confirmationCount++; emit TransactionConfirmed(transactionId, msg.sender); if (transactions[transactionId].confirmationCount >= requiredConfirmations) { executeTransaction(transactionId); } } function executeTransaction(uint256 transactionId) public onlyOwner validTransaction(transactionId) nonReentrant { require(!transactions[transactionId].executed, "Transaction already executed"); require(transactions[transactionId].confirmationCount >= requiredConfirmations, "Not enough confirmations"); address to = transactions[transactionId].to; uint256 value = transactions[transactionId].value; bytes memory data = transactions[transactionId].data; transactions[transactionId].executed = true; (bool success, ) = to.call{value: value}(data); emit TransactionExecuted(transactionId); require(success, "Transaction execution failed"); } }