-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMultisig.sol
109 lines (94 loc) · 3.23 KB
/
Multisig.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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Multisig {
event Deposit(address indexed sender, uint indexed amount);
event Submit(uint indexed txnId);
event Approve(address indexed owner, uint indexed txnId);
event Revoke(address indexed owner, uint indexed txnId);
event Execute(uint indexed txnId);
mapping(address => bool) public isOwner;
uint public minOwners;
address[] public owners;
struct Transaction {
address to;
uint value;
bytes data;
bool executed;
}
Transaction[] public transactions;
// which owner approved which transaction
mapping(uint => mapping(address => bool)) public approved;
modifier onlyOwner(){
require(isOwner[msg.sender], "Only owner can call this function");
_;
}
modifier txnExist(uint _txnId){
require(_txnId < transactions.length, "Txn does not exist");
_;
}
modifier notApproved(uint _txnId){
require(!approved[_txnId][msg.sender], "Txn already approved");
_;
}
modifier notExec(uint _txnId){
require(!transactions[_txnId].executed, "Txn already executed");
_;
}
constructor(address[] memory _owners, uint _required){
require(_owners.length > 0, "Required atleast 1 owner");
require( _required > 0 && _required <= _owners.length, "Invalid minimum owners condition");
for(uint i; i < _owners.length; i++){
address owner = _owners[i];
require(owner != address(0), "Invalid owner address");
require(!isOwner[owner], "Duplicate owner address");
isOwner[owner] = true;
owners.push(owner);
}
minOwners = _required;
}
receive() external payable {
emit Deposit(msg.sender, msg.value);
}
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 approve(uint _txnId)
external
onlyOwner
txnExist(_txnId)
notApproved(_txnId)
notExec(_txnId)
{
approved[_txnId][msg.sender] = true;
emit Approve(msg.sender, _txnId);
}
function _getApprovalCount(uint _txnId) private view returns (uint count) {
uint ownerCount = owners.length;
for(uint i; i < ownerCount; i++){
if(approved[_txnId][owners[i]]){
count += 1;
}
}
}
function execute(uint _txnId) external txnExist(_txnId) notExec(_txnId) {
require(_getApprovalCount(_txnId) >= minOwners, "Minimum approvals required");
Transaction storage txn = transactions[_txnId];
txn.executed = true;
(bool success, ) = txn.to.call{value: txn.value}(
txn.data
);
require(success, "txn failed");
emit Execute(_txnId);
}
function revoke(uint _txnId) external onlyOwner txnExist(_txnId) notExec(_txnId) {
require(approved[_txnId][msg.sender], "Txn not even approved");
approved[_txnId][msg.sender] = false;
emit Revoke(msg.sender, _txnId);
}
}