forked from filterswap/filterswap-contracts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFilterTreasury.sol
More file actions
112 lines (81 loc) · 3.51 KB
/
Copy pathFilterTreasury.sol
File metadata and controls
112 lines (81 loc) · 3.51 KB
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
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8;
contract FilterTreasury {
uint public totalNumSignatories;
mapping(address => bool) public isSignatory;
mapping(uint => mapping(address => bool)) public isConfirmed;
uint public approvalsRequired;
struct Transaction {
address to;
uint value;
bytes data;
bool executed;
uint numApprovals;
}
Transaction[] public transactions;
// **** CONTRUCTOR, FALLBACK & MODIFIER FUNCTIONS ****
constructor(address[] memory _initialSignatories) {
require(_initialSignatories.length >= 2);
for (uint i = 0; i < _initialSignatories.length; i++) {
address initialSignatory = _initialSignatories[i];
isSignatory[initialSignatory] = true;
totalNumSignatories += 1;
}
approvalsRequired = (_initialSignatories.length / 2) + 1;
}
receive() external payable {}
modifier onlySignatories() {
require(isSignatory[msg.sender], "FilterTreasury: FORBIDDEN");
_;
}
modifier onlyInternal() {
require(msg.sender == address(this), "FilterTreasury: FORBIDDEN");
_;
}
// **** EVENTS ****
event newProposal(uint, address, uint, bytes);
event proposalAccepted(address, uint);
event proposalExecuted(uint);
// **** SIGNATORY FUNCTIONS ****
function proposeTransaction(address _to, uint _value, bytes calldata _data) external onlySignatories {
transactions.push(Transaction({
to: _to,
value: _value,
data: _data,
executed: false,
numApprovals: 0
}));
emit newProposal(transactions.length - 1, _to, _value, _data);
}
function approveTransaction(uint _proposalID) external onlySignatories {
require(_proposalID < transactions.length, "FilterTreasury: PROPOSAL_DOESNT_EXIST");
require(!isConfirmed[_proposalID][msg.sender], "FilterTreasury: PROPOSAL_ALREADY_CONFIRMED");
require(!transactions[_proposalID].executed, "FilterTreasury: PROPOSAL_ALREADY_EXECUTED");
Transaction storage transaction = transactions[_proposalID];
transaction.numApprovals += 1;
isConfirmed[_proposalID][msg.sender] = true;
emit proposalAccepted(msg.sender, _proposalID);
}
function executeTransaction(uint _proposalID) external onlySignatories {
require(_proposalID < transactions.length, "FilterTreasury: PROPOSAL_DOESNT_EXIST");
require(!transactions[_proposalID].executed, "FilterTreasury: PROPOSAL_ALREADY_EXECUTED");
Transaction storage transaction = transactions[_proposalID];
require(transaction.numApprovals >= approvalsRequired, "FilterTreasury: NOT_ENOUGH_APPROVALS");
transaction.executed = true;
(bool success, ) = transaction.to.call{value: transaction.value}(transaction.data);
require(success, "FilterTreasury: TX_FAILED");
emit proposalExecuted(_proposalID);
}
// **** INTERNAL FUNCTIONS ****
function addSignatory(address _signatoryAddress) public onlyInternal {
isSignatory[_signatoryAddress] = true;
totalNumSignatories += 1;
approvalsRequired = (totalNumSignatories / 2) + 1;
}
function removeSignatory(address _signatoryAddress) public onlyInternal {
require(isSignatory[_signatoryAddress]);
isSignatory[_signatoryAddress] = false;
totalNumSignatories -= 1;
approvalsRequired = (totalNumSignatories / 2) + 1;
}
}