-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMultiSigWallet.sol
145 lines (126 loc) · 4.76 KB
/
MultiSigWallet.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
pragma solidity >=0.4.22 <0.9.0;
contract MultiSigWallet {
event Deposit(address indexed sender, uint amount, uint balance);
event SubmitTransaction(
address indexed owner,
uint indexed txIndex,
address indexed to,
uint value,
bytes data
);
event ConfirmTransaction(address indexed owner, uint indexed txIndex);
event RevokeConfirmation(address indexed owner, uint indexed txIndex);
event ExecuteTransaction(address indexed owner, uint indexed txIndex);
address[] public owners;
uint public numConfirmationsRequired;
struct Transaction {
address to;
uint value;
bytes data;
bool executed;
mapping(address => bool) isConfirmed;
uint numConfirmations;
}
Transaction[] public transactions;
constructor(address[] memory _owners, uint _numConfirmationsRequired) {
require(_owners.length > 0, "Owners required");
require(
_numConfirmationsRequired > 0 && _numConfirmationsRequired <= _owners.length,
"Invalid number of required confirmations"
);
for (uint i = 0; i < _owners.length; i++) {
address owner = _owners[i];
require(owner != address(0), "Invalid owner");
require(!isOwner(owner), "Owner not unique");
owners.push(owner);
}
numConfirmationsRequired = _numConfirmationsRequired;
}
receive() external payable {
emit Deposit(msg.sender, msg.value, address(this).balance);
}
function submitTransaction(address _to, uint _value, bytes memory _data) public returns (uint) {
require(isOwner(msg.sender), "Not an owner");
uint txIndex = transactions.length;
transactions.push(Transaction({
to: _to,
value: _value,
data: _data,
executed: false,
numConfirmations: 0
}));
emit SubmitTransaction(msg.sender, txIndex, _to, _value, _data);
return txIndex;
}
function confirmTransaction(uint _txIndex) public {
require(isOwner(msg.sender), "Not an owner");
Transaction storage transaction = transactions[_txIndex];
require(!transaction.executed, "Transaction already executed");
require(!transaction.isConfirmed[msg.sender], "Confirmation already submitted");
transaction.isConfirmed[msg.sender] = true;
transaction.numConfirmations += 1;
emit ConfirmTransaction(msg.sender, _txIndex);
}
function revokeConfirmation(uint _txIndex) public {
require(isOwner(msg.sender), "Not an owner");
Transaction storage transaction = transactions[_txIndex];
require(!transaction.executed, "Transaction already executed");
require(transaction.isConfirmed[msg.sender], "Confirmation not found");
transaction.isConfirmed[msg.sender] = false;
transaction.numConfirmations -= 1;
emit RevokeConfirmation(msg.sender, _txIndex);
}
function executeTransaction(uint _txIndex) public {
require(isOwner(msg.sender), "Not an owner");
Transaction storage transaction = transactions[_txIndex];
require(!transaction.executed, "Transaction already executed");
require(transaction.numConfirmations >= numConfirmationsRequired, "Not enough confirmations");
transaction.executed = true;
(bool success, ) = transaction.to.call{value: transaction.value}(
transaction.data
);
require(success, "Transaction failed");
emit ExecuteTransaction(msg.sender, _txIndex);
}
function isOwner(address _owner) public view returns (bool) {
for (uint i = 0; i < owners.length; i++) {
if (owners[i] == _owner) {
return true;
}
}
return false;
}
function getTransactionCount() public view returns (uint) {
return transactions.length;
}
function getTransaction(uint _txIndex) public view returns (
address to,
uint value,
bytes memory data,
bool executed,
uint numConfirmations
) {
Transaction storage transaction = transactions[_txIndex];
return (
transaction.to,
transaction.value,
transaction.data,
transaction.executed,
transaction.numConfirmations
);
}
function getConfirmations(uint _txIndex) public view returns (address[] memory) {
Transaction storage transaction = transactions[_txIndex];
address[] memory confirmations = new address[](owners.length);
uint count = 0;
for (uint i = 0; i < owners.length; i++) {
if (transaction.isConfirmed[owners[i]]) {
confirmations[count] = owners[i];
count += 1;
}
}
return confirmations;
}
function getOwners() public view returns (address[] memory) {
return owners;
}