- Integrated ECDSA for signature verification in ComboHandler. - Updated event emissions to include additional parameters for better tracking. - Improved gas tracking during execution of combo plans. - Enhanced database interactions for storing and retrieving plans, including conflict resolution and status updates. - Added new dependencies for security and database management in orchestrator.
130 lines
4.1 KiB
Solidity
130 lines
4.1 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
/**
|
|
* @title MultiSigWallet
|
|
* @notice Multi-signature wallet for admin functions
|
|
* @dev Requires multiple signatures for critical operations
|
|
*/
|
|
contract MultiSigWallet {
|
|
address[] public owners;
|
|
uint256 public required;
|
|
|
|
mapping(bytes32 => bool) public executed;
|
|
|
|
event Deposit(address indexed sender, uint256 amount);
|
|
event SubmitTransaction(uint256 indexed txIndex, address indexed owner, address indexed to, uint256 value, bytes data);
|
|
event ConfirmTransaction(uint256 indexed txIndex, address indexed owner);
|
|
event RevokeConfirmation(uint256 indexed txIndex, address indexed owner);
|
|
event ExecuteTransaction(uint256 indexed txIndex, address indexed owner);
|
|
|
|
modifier onlyOwner() {
|
|
require(isOwner(msg.sender), "Not owner");
|
|
_;
|
|
}
|
|
|
|
modifier txExists(uint256 _txIndex) {
|
|
require(_txIndex < transactions.length, "Transaction does not exist");
|
|
_;
|
|
}
|
|
|
|
modifier notExecuted(uint256 _txIndex) {
|
|
require(!transactions[_txIndex].executed, "Transaction already executed");
|
|
_;
|
|
}
|
|
|
|
modifier notConfirmed(uint256 _txIndex) {
|
|
require(!confirmations[_txIndex][msg.sender], "Transaction already confirmed");
|
|
_;
|
|
}
|
|
|
|
struct Transaction {
|
|
address to;
|
|
uint256 value;
|
|
bytes data;
|
|
bool executed;
|
|
}
|
|
|
|
Transaction[] public transactions;
|
|
mapping(uint256 => mapping(address => bool)) public confirmations;
|
|
|
|
constructor(address[] memory _owners, uint256 _required) {
|
|
require(_owners.length > 0, "Owners required");
|
|
require(_required > 0 && _required <= _owners.length, "Invalid required");
|
|
|
|
owners = _owners;
|
|
required = _required;
|
|
}
|
|
|
|
receive() external payable {
|
|
emit Deposit(msg.sender, msg.value);
|
|
}
|
|
|
|
function isOwner(address addr) public view returns (bool) {
|
|
for (uint256 i = 0; i < owners.length; i++) {
|
|
if (owners[i] == addr) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function submitTransaction(address _to, uint256 _value, bytes memory _data) public onlyOwner returns (uint256) {
|
|
uint256 txIndex = transactions.length;
|
|
transactions.push(Transaction({
|
|
to: _to,
|
|
value: _value,
|
|
data: _data,
|
|
executed: false
|
|
}));
|
|
|
|
emit SubmitTransaction(txIndex, msg.sender, _to, _value, _data);
|
|
confirmTransaction(txIndex);
|
|
return txIndex;
|
|
}
|
|
|
|
function confirmTransaction(uint256 _txIndex) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) notConfirmed(_txIndex) {
|
|
confirmations[_txIndex][msg.sender] = true;
|
|
emit ConfirmTransaction(_txIndex, msg.sender);
|
|
|
|
if (isConfirmed(_txIndex)) {
|
|
executeTransaction(_txIndex);
|
|
}
|
|
}
|
|
|
|
function revokeConfirmation(uint256 _txIndex) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
|
|
require(confirmations[_txIndex][msg.sender], "Transaction not confirmed");
|
|
|
|
confirmations[_txIndex][msg.sender] = false;
|
|
emit RevokeConfirmation(_txIndex, msg.sender);
|
|
}
|
|
|
|
function executeTransaction(uint256 _txIndex) public txExists(_txIndex) notExecuted(_txIndex) {
|
|
require(isConfirmed(_txIndex), "Transaction not confirmed");
|
|
|
|
Transaction storage transaction = transactions[_txIndex];
|
|
transaction.executed = true;
|
|
|
|
(bool success, ) = transaction.to.call{value: transaction.value}(transaction.data);
|
|
require(success, "Transaction execution failed");
|
|
|
|
emit ExecuteTransaction(_txIndex, msg.sender);
|
|
}
|
|
|
|
function isConfirmed(uint256 _txIndex) public view returns (bool) {
|
|
uint256 count = 0;
|
|
for (uint256 i = 0; i < owners.length; i++) {
|
|
if (confirmations[_txIndex][owners[i]]) count++;
|
|
if (count == required) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function getTransactionCount() public view returns (uint256) {
|
|
return transactions.length;
|
|
}
|
|
|
|
function getOwners() public view returns (address[] memory) {
|
|
return owners;
|
|
}
|
|
}
|
|
|