-
Notifications
You must be signed in to change notification settings - Fork 0
/
streamtide.sol
167 lines (137 loc) · 4.99 KB
/
streamtide.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
struct Donation {
address receiver;
uint256 amount;
}
contract MVPCLR is Ownable {
uint256 public roundStart;
uint256 public roundDuration;
uint256 public patronCount = 0;
uint256 public id = 0;
address[] public admins;
address[] public blacklisted;
mapping(address => bool) public isAdmin;
mapping(uint256 => address) public patrons;
Donation[] public donations;
int256 index_of_last_processed_donation = -1;
event RoundStarted(uint256 roundStart, uint256 roundDuration);
event PatronAdded(
address addr,
bytes32 data,
string link,
string ipfsHash,
uint256 index
);
event Donate(
address origin,
address sender,
uint256 value,
uint256 index,
uint256 id
);
event MatchingPoolDonation(address sender, uint256 value);
event Distribute(address to, uint256 amount);
function openRound() public onlyAdmin {
require(roundDuration == 0, "Round is already open");
roundDuration = 30*24*60*60; // 1 month
roundStart = getBlockTimestamp();
emit RoundStarted(roundStart, roundDuration);
}
function closeRound() public onlyAdmin {
roundDuration = 0;
}
function roundIsClosed() public view returns (bool) {
return roundDuration != 0 && roundStart + roundDuration <= getBlockTimestamp();
}
function startRound(uint256 _roundDuration) public onlyAdmin {
id = id +1;
require(_roundDuration < 31536000, "MVPCLR: round duration too long");
roundDuration = _roundDuration;
roundStart = getBlockTimestamp();
emit RoundStarted(roundStart, roundDuration);
}
function addAdmin(address _admin) public onlyOwner {
admins.push(_admin);
isAdmin[_admin] = true;
}
function removeAdmin(address _admin) public onlyOwner {
require(isAdmin[_admin], "Admin not found"); // check if the address is an admin
uint256 adminIndex;
for (uint256 i = 0; i < admins.length; i++) {
if (admins[i] == _admin) {
adminIndex = i;
break;
}
}
delete admins[adminIndex];
delete isAdmin[_admin];
}
function getBlockTimestamp() public view returns (uint256) {
return block.timestamp;
}
function addToBlacklist(address _address) public onlyAdmin {
blacklisted.push(_address);
}
function removeFromBlacklist(address _address) public onlyAdmin {
uint256 index;
for (uint256 i = 0; i < blacklisted.length; i++) {
if (blacklisted[i] == _address) {
index = i;
break;
}
}
delete blacklisted[index];
}
function addPatron(
address payable addr,
bytes32 data,
string memory link,
string memory ipfsHash
) public onlyAdmin {
for (uint256 i = 0; i < blacklisted.length; i++) {
require(blacklisted[i] != addr, "Patron address is blacklisted");
}
patrons[patronCount] = addr;
emit PatronAdded(addr, data, link, ipfsHash, patronCount);
patronCount = patronCount + 1;
}
function donate(uint256[] memory patron_indexes, uint256[] memory amounts) public payable {
for (uint256 i = 0; i < blacklisted.length; i++) {
require(blacklisted[i] != _msgSender(), "Sender address is blacklisted");
}
uint256 total_amount = 0;
for(uint256 i = 0; i < patron_indexes.length; i++) {
uint256 patron_index = patron_indexes[i];
uint256 amount = amounts[i];
total_amount = total_amount + amount;
require(patron_index < patronCount, "CLR:donate - Not a valid recipient");
donations.push(Donation(patrons[patron_index], amount));
emit Donate(tx.origin, _msgSender(), amount, patron_index, id);
}
}
function distribute(uint256 _maxProcess) external onlyAdmin {
require(roundIsClosed(), "Round is still open");
uint256 processed = 0;
while(index_of_last_processed_donation + int256(processed) < int256(donations.length)-1 && processed < _maxProcess) {
Donation memory donation = donations[uint256(index_of_last_processed_donation+1)+processed];
payable(donation.receiver).transfer(donation.amount);
emit Distribute(donation.receiver, donation.amount);
processed = processed + 1;
}
index_of_last_processed_donation += int256(processed);
}
// receive donation for the matching pool
receive() external payable {
require(
roundStart == 0 || getBlockTimestamp() < roundStart + roundDuration,
"CLR:receive closed"
);
emit MatchingPoolDonation(_msgSender(), msg.value);
}
modifier onlyAdmin() {
require(isAdmin[msg.sender] == true, "Not an admin");
_;
}
}