-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMultiSigWallet.sol
141 lines (119 loc) · 3.93 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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract MultiSigWallet {
event Deposit(address indexed sender, uint amount);
event Submit(uint indexed txId);
event Approve(address owner, uint indexed txId);
event Revoke(address indexed owner, uint indexed txId);
event Execute(uint indexed txId);
// Structure of transaction
struct Transaction {
address to;
uint value;
bytes data;
bool executed;
}
// Storing owners
address[] public owners;
// Checking owners
mapping(address => bool) public isOwner;
// no. approvels required for txn to execute
uint public required;
// Storing those transactions
Transaction[] public transactions;
// Storing approvel of each txn from each owners
mapping(uint => mapping(address => bool)) public approved;
// Owners
modifier onlyOwner() {
require(isOwner[msg.sender], "not owner");
_;
}
// Checking the txns
modifier txExists(uint _txId) {
require(_txId < transactions.length, "tx does not exist");
_;
}
// Checking the approval was already done
modifier notApproved(uint _txId) {
require(!approved[_txId][msg.sender], "tx already approved");
_;
}
// Checking whether the txn is already executed
modifier notExecuted(uint _txId) {
require(!transactions[_txId].executed, "tx already executed");
_;
}
constructor(address[] memory _owners, uint _required) {
require(_owners.length > 0, "owners required");
require(_required > 0 && _required <= _owners.length,
"invalid required number of owners"
);
// Stating _owners to state variable owner
for (uint i; i < _owners.length; i++) {
address owner = _owners[i];
require(owner != address(0), "invalid owner");
// Checking for duplicate owners
require( !isOwner[owner], "owner is not unique");
isOwner[owner] = true;
owners.push(owner);
}
required = _required;
}
receive() external payable {
emit Deposit(msg.sender, msg.value);
}
// Function to submit transactions for approval
function submit( address _to, uint _value, bytes calldata _data)
external
onlyOwner
{
transactions.push(Transaction({
to: _to,
value: _value,
data: _data,
executed: false
}));
emit Submit(transactions.length - 1);
}
// Function for each approval
function approve(uint _txId)
external
onlyOwner
txExists(_txId)
notApproved(_txId)
notExecuted(_txId)
{
approved[_txId][msg.sender] = true;
emit Approve(msg.sender, _txId);
}
// Counting the number of approvals
function _getApprovalCount(uint _txId) private view returns (uint count) {
for (uint i; i < owners.length; i++) {
if (approved[_txId][owners[i]]) {
count += 1;
}
}
}
// Function to execute transaction
function execute(uint _txId) external txExists(_txId) notExecuted(_txId) {
require(_getApprovalCount(_txId) >= required, "approvals count < required count");
Transaction storage transaction = transactions[_txId];
transaction.executed = true;
(bool success, ) = transaction.to.call{value: transaction.value}(
transaction.data
);
require(success, "tx failed");
emit Execute(_txId);
}
// Function to revoke the txn
function revoke(uint _txId)
external
onlyOwner
txExists(_txId)
notExecuted(_txId)
{
require(approved[_txId][msg.sender], "tx not approved");
approved[_txId][msg.sender] = false;
emit Revoke(msg.sender, _txId);
}
}