@gooddollar/goodcollective-contracts 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/artifacts/contracts/DirectPayments/DirectPaymentsFactory.sol/DirectPaymentsFactory.dbg.json +4 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsFactory.sol/DirectPaymentsFactory.json +995 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsLibrary.sol/DirectPaymentsLibrary.dbg.json +4 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsLibrary.sol/DirectPaymentsLibrary.json +113 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool.dbg.json +4 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool.json +2210 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsPool.sol/IIdentityV2.dbg.json +4 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsPool.sol/IIdentityV2.json +30 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsPool.sol/IMembersValidator.dbg.json +4 -0
- package/artifacts/contracts/DirectPayments/DirectPaymentsPool.sol/IMembersValidator.json +45 -0
- package/artifacts/contracts/DirectPayments/ProvableNFT.sol/ProvableNFT.dbg.json +4 -0
- package/artifacts/contracts/DirectPayments/ProvableNFT.sol/ProvableNFT.json +1187 -0
- package/artifacts/contracts/GoodCollective/GoodCollectiveSuperApp.sol/GoodCollectiveSuperApp.dbg.json +4 -0
- package/artifacts/contracts/GoodCollective/GoodCollectiveSuperApp.sol/GoodCollectiveSuperApp.json +831 -0
- package/artifacts/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IGoodCollectiveSuperApp.dbg.json +4 -0
- package/artifacts/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IGoodCollectiveSuperApp.json +42 -0
- package/artifacts/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IRegistry.dbg.json +4 -0
- package/artifacts/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IRegistry.json +61 -0
- package/artifacts/contracts/GoodCollective/SuperAppBaseFlow.sol/IRegisterSuperapp.dbg.json +4 -0
- package/artifacts/contracts/GoodCollective/SuperAppBaseFlow.sol/IRegisterSuperapp.json +47 -0
- package/artifacts/contracts/GoodCollective/SuperAppBaseFlow.sol/SuperAppBaseFlow.dbg.json +4 -0
- package/artifacts/contracts/GoodCollective/SuperAppBaseFlow.sol/SuperAppBaseFlow.json +320 -0
- package/artifacts/contracts/Interfaces.sol/IIdentityV2.dbg.json +4 -0
- package/artifacts/contracts/Interfaces.sol/IIdentityV2.json +30 -0
- package/artifacts/contracts/Interfaces.sol/IMembersValidator.dbg.json +4 -0
- package/artifacts/contracts/Interfaces.sol/IMembersValidator.json +45 -0
- package/artifacts/contracts/UBI/UBIPool.sol/UBIPool.dbg.json +4 -0
- package/artifacts/contracts/UBI/UBIPool.sol/UBIPool.json +2078 -0
- package/artifacts/contracts/UBI/UBIPoolFactory.sol/UBIPoolFactory.dbg.json +4 -0
- package/artifacts/contracts/UBI/UBIPoolFactory.sol/UBIPoolFactory.json +1011 -0
- package/artifacts/contracts/test/HelperLibraryTest.sol/HelperLibraryTest.dbg.json +4 -0
- package/artifacts/contracts/test/HelperLibraryTest.sol/HelperLibraryTest.json +90 -0
- package/artifacts/contracts/utils/HelperLibrary.sol/HelperLibrary.dbg.json +4 -0
- package/artifacts/contracts/utils/HelperLibrary.sol/HelperLibrary.json +117 -0
- package/artifacts/contracts/utils/SwapRouterMock.sol/SwapRouterMock.dbg.json +4 -0
- package/artifacts/contracts/utils/SwapRouterMock.sol/SwapRouterMock.json +119 -0
- package/contracts/DirectPayments/DirectPaymentsFactory.sol +32 -6
- package/contracts/DirectPayments/DirectPaymentsLibrary.sol +168 -14
- package/contracts/DirectPayments/DirectPaymentsPool.sol +31 -116
- package/contracts/GoodCollective/GoodCollectiveSuperApp.sol +7 -6
- package/contracts/GoodCollective/IGoodCollectiveSuperApp.sol +4 -0
- package/contracts/GoodCollective/SuperAppBaseFlow.sol +6 -0
- package/contracts/UBI/UBIPool.sol +62 -18
- package/contracts/UBI/UBIPoolFactory.sol +32 -4
- package/contracts/utils/HelperLibrary.sol +10 -0
- package/contracts/utils/Recover.sol +16 -0
- package/package.json +4 -4
- package/releases/deployment.json +7417 -30724
- package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.ts +54 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsLibrary.sol/DirectPayemntsLibrary.ts +77 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsLibrary.sol/DirectPaymentsLibrary.ts +77 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsLibrary.sol/index.ts +5 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsLibrary.ts +146 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool.ts +90 -11
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/IMembersValidator.ts +6 -8
- package/typechain-types/contracts/DirectPayments/index.ts +1 -0
- package/typechain-types/contracts/GoodCollective/GoodCollectiveSuperApp.ts +40 -0
- package/typechain-types/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IGoodCollectiveSuperApp.ts +22 -1
- package/typechain-types/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IRegistry.ts +38 -1
- package/typechain-types/contracts/GoodCollective/SuperAppBaseFlow.sol/IRegisterSuperapp.ts +152 -0
- package/typechain-types/contracts/GoodCollective/SuperAppBaseFlow.sol/SuperAppBaseFlow.ts +523 -0
- package/typechain-types/contracts/GoodCollective/SuperAppBaseFlow.sol/index.ts +5 -0
- package/typechain-types/contracts/GoodCollective/index.ts +2 -1
- package/typechain-types/contracts/UBI/MultiClaimModule.sol/IClaimable.ts +92 -0
- package/typechain-types/contracts/UBI/MultiClaimModule.sol/IModule.ts +196 -0
- package/typechain-types/contracts/UBI/MultiClaimModule.sol/MultiClaimModule.ts +242 -0
- package/typechain-types/contracts/UBI/MultiClaimModule.sol/index.ts +6 -0
- package/typechain-types/contracts/UBI/UBIPool.ts +77 -0
- package/typechain-types/contracts/UBI/UBIPoolFactory.ts +54 -0
- package/typechain-types/contracts/utils/Recover.ts +263 -0
- package/typechain-types/contracts/utils/index.ts +1 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory__factory.ts +38 -1
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsLibrary.sol/DirectPayemntsLibrary__factory.ts +96 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsLibrary.sol/DirectPaymentsLibrary__factory.ts +96 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsLibrary.sol/index.ts +5 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsLibrary__factory.ts +169 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool__factory.ts +53 -2
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/IMembersValidator__factory.ts +1 -1
- package/typechain-types/factories/contracts/DirectPayments/index.ts +1 -0
- package/typechain-types/factories/contracts/GoodCollective/GoodCollectiveSuperApp__factory.ts +18 -0
- package/typechain-types/factories/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IGoodCollectiveSuperApp__factory.ts +13 -0
- package/typechain-types/factories/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IRegistry__factory.ts +24 -0
- package/typechain-types/factories/contracts/GoodCollective/SuperAppBaseFlow.sol/IRegisterSuperapp__factory.ts +62 -0
- package/typechain-types/factories/contracts/GoodCollective/SuperAppBaseFlow.sol/SuperAppBaseFlow__factory.ts +335 -0
- package/typechain-types/factories/contracts/GoodCollective/SuperAppBaseFlow.sol/index.ts +5 -0
- package/typechain-types/factories/contracts/GoodCollective/index.ts +1 -1
- package/typechain-types/factories/contracts/UBI/MultiClaimModule.sol/IClaimable__factory.ts +33 -0
- package/typechain-types/factories/contracts/UBI/MultiClaimModule.sol/IModule__factory.ts +84 -0
- package/typechain-types/factories/contracts/UBI/MultiClaimModule.sol/MultiClaimModule__factory.ts +150 -0
- package/typechain-types/factories/contracts/UBI/MultiClaimModule.sol/index.ts +6 -0
- package/typechain-types/factories/contracts/UBI/UBIPoolFactory__factory.ts +38 -1
- package/typechain-types/factories/contracts/UBI/UBIPool__factory.ts +42 -1
- package/typechain-types/factories/contracts/test/HelperLibraryTest__factory.ts +1 -1
- package/typechain-types/factories/contracts/utils/HelperLibrary__factory.ts +11 -1
- package/typechain-types/factories/contracts/utils/Recover__factory.ts +172 -0
- package/typechain-types/factories/contracts/utils/index.ts +1 -0
- package/typechain-types/hardhat.d.ts +27 -0
- package/typechain-types/index.ts +8 -2
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity >=0.8.0;
|
|
3
3
|
|
|
4
|
+
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
|
|
5
|
+
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
|
6
|
+
|
|
4
7
|
import "./DirectPaymentsPool.sol";
|
|
8
|
+
import "./ProvableNFT.sol";
|
|
5
9
|
|
|
6
|
-
library
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
library DirectPaymentsLibrary {
|
|
11
|
+
using SafeERC20Upgradeable for IERC20Upgradeable;
|
|
12
|
+
event NOT_MEMBER_OR_WHITELISTED_OR_LIMITS(address contributer);
|
|
13
|
+
event EventRewardClaimed(
|
|
14
|
+
uint256 indexed tokenId,
|
|
15
|
+
uint16 eventType,
|
|
16
|
+
uint32 eventTimestamp,
|
|
17
|
+
uint256 eventQuantity,
|
|
18
|
+
string eventUri,
|
|
19
|
+
address[] contributers,
|
|
20
|
+
uint256 rewardPerContributer
|
|
21
|
+
);
|
|
22
|
+
event NFTClaimed(uint256 indexed tokenId, uint256 totalRewards);
|
|
23
|
+
error OVER_MEMBER_LIMITS(address);
|
|
24
|
+
error OVER_GLOBAL_LIMITS();
|
|
25
|
+
error NO_BALANCE();
|
|
26
|
+
|
|
27
|
+
function _updateMemberLimits(DirectPaymentsPool.LimitsData storage memberStats, uint128 reward) public {
|
|
12
28
|
if (memberStats.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
13
29
|
{
|
|
14
30
|
memberStats.daily = reward;
|
|
@@ -16,7 +32,7 @@ library DirectPayemntsLibrary {
|
|
|
16
32
|
memberStats.daily += reward;
|
|
17
33
|
}
|
|
18
34
|
|
|
19
|
-
if (memberStats.lastMonth <
|
|
35
|
+
if (memberStats.lastMonth < _month()) //month switched
|
|
20
36
|
{
|
|
21
37
|
memberStats.monthly = reward;
|
|
22
38
|
} else {
|
|
@@ -25,14 +41,20 @@ library DirectPayemntsLibrary {
|
|
|
25
41
|
|
|
26
42
|
memberStats.total += reward;
|
|
27
43
|
memberStats.lastReward = uint64(block.timestamp);
|
|
28
|
-
memberStats.lastMonth =
|
|
44
|
+
memberStats.lastMonth = _month();
|
|
29
45
|
}
|
|
30
46
|
|
|
31
|
-
|
|
47
|
+
/**
|
|
48
|
+
* @dev Updates the global limits with the new reward.
|
|
49
|
+
* @param globalLimits The global limits data to update.
|
|
50
|
+
* @param limits The safety limits to check against.
|
|
51
|
+
* @param reward The amount of rewards to update.
|
|
52
|
+
*/
|
|
53
|
+
function _enforceAndUpdateGlobalLimits(
|
|
32
54
|
DirectPaymentsPool.LimitsData storage globalLimits,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
55
|
+
DirectPaymentsPool.SafetyLimits memory limits,
|
|
56
|
+
uint128 reward
|
|
57
|
+
) public {
|
|
36
58
|
if (globalLimits.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
37
59
|
{
|
|
38
60
|
globalLimits.daily = reward;
|
|
@@ -40,7 +62,7 @@ library DirectPayemntsLibrary {
|
|
|
40
62
|
globalLimits.daily += reward;
|
|
41
63
|
}
|
|
42
64
|
|
|
43
|
-
if (globalLimits.lastMonth <
|
|
65
|
+
if (globalLimits.lastMonth < _month()) //month switched
|
|
44
66
|
{
|
|
45
67
|
globalLimits.monthly = reward;
|
|
46
68
|
} else {
|
|
@@ -49,6 +71,138 @@ library DirectPayemntsLibrary {
|
|
|
49
71
|
|
|
50
72
|
globalLimits.total += reward;
|
|
51
73
|
globalLimits.lastReward = uint64(block.timestamp);
|
|
52
|
-
globalLimits.lastMonth =
|
|
74
|
+
globalLimits.lastMonth = _month();
|
|
75
|
+
|
|
76
|
+
if (globalLimits.monthly > limits.maxTotalPerMonth) revert OVER_GLOBAL_LIMITS();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @dev Enforces and updates the reward limits for the specified member. if the member is not a valid member, or past limit it returns false and member will not get rewards.
|
|
81
|
+
* @param memberStats The member's limits data to update.
|
|
82
|
+
* @param limits The safety limits to check against.
|
|
83
|
+
* @param member The address of the member to enforce and update limits for.
|
|
84
|
+
* @param reward The amount of rewards to enforce and update limits for.
|
|
85
|
+
*/
|
|
86
|
+
function _enforceAndUpdateMemberLimits(
|
|
87
|
+
DirectPaymentsPool.LimitsData storage memberStats,
|
|
88
|
+
DirectPaymentsPool.SafetyLimits memory limits,
|
|
89
|
+
address member,
|
|
90
|
+
uint128 reward
|
|
91
|
+
) public returns (bool) {
|
|
92
|
+
if (
|
|
93
|
+
DirectPaymentsPool(address(this)).hasRole(DirectPaymentsPool(address(this)).MEMBER_ROLE(), member) == false
|
|
94
|
+
) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
_updateMemberLimits(memberStats, reward);
|
|
98
|
+
|
|
99
|
+
if (memberStats.daily > limits.maxMemberPerDay || memberStats.monthly > limits.maxMemberPerMonth) return false;
|
|
100
|
+
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @dev Sends rewards to the specified recipients.
|
|
106
|
+
* @param recipients The addresses of the recipients to send rewards to.
|
|
107
|
+
* @param reward The total amount of rewards to send.
|
|
108
|
+
*/
|
|
109
|
+
function _sendReward(
|
|
110
|
+
DirectPaymentsPool.LimitsData storage globalLimits,
|
|
111
|
+
DirectPaymentsPool.SafetyLimits memory limits,
|
|
112
|
+
mapping(address => DirectPaymentsPool.LimitsData) storage memberLimits,
|
|
113
|
+
DirectPaymentsPool.PoolSettings memory settings,
|
|
114
|
+
address[] memory recipients,
|
|
115
|
+
uint128 reward
|
|
116
|
+
) public {
|
|
117
|
+
uint128 perReward = uint128(reward / recipients.length);
|
|
118
|
+
uint128 totalSent;
|
|
119
|
+
for (uint i = 0; i < recipients.length; i++) {
|
|
120
|
+
bool valid = _enforceAndUpdateMemberLimits(memberLimits[recipients[i]], limits, recipients[i], perReward);
|
|
121
|
+
if (valid) {
|
|
122
|
+
settings.rewardToken.safeTransfer(recipients[i], perReward);
|
|
123
|
+
totalSent += perReward;
|
|
124
|
+
} else {
|
|
125
|
+
emit NOT_MEMBER_OR_WHITELISTED_OR_LIMITS(recipients[i]);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
_enforceAndUpdateGlobalLimits(globalLimits, limits, totalSent);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @dev Claims rewards for the specified NFT ID.
|
|
133
|
+
* @param globalLimits The global limits data to check against.
|
|
134
|
+
* @param limits The safety limits to check against.
|
|
135
|
+
* @param memberLimits The mapping of member limits to check against.
|
|
136
|
+
* @param settings The pool settings containing the reward token and other configurations.
|
|
137
|
+
* @param _nftId The ID of the NFT to claim rewards for.
|
|
138
|
+
* @param _data The NFTData struct containing data about the NFT.
|
|
139
|
+
*/
|
|
140
|
+
function _claim(
|
|
141
|
+
DirectPaymentsPool.LimitsData storage globalLimits,
|
|
142
|
+
DirectPaymentsPool.SafetyLimits memory limits,
|
|
143
|
+
mapping(address => DirectPaymentsPool.LimitsData) storage memberLimits,
|
|
144
|
+
DirectPaymentsPool.PoolSettings memory settings,
|
|
145
|
+
uint256 _nftId,
|
|
146
|
+
ProvableNFT.NFTData memory _data
|
|
147
|
+
) public {
|
|
148
|
+
uint totalRewards;
|
|
149
|
+
uint rewardsBalance = settings.rewardToken.balanceOf(address(this));
|
|
150
|
+
|
|
151
|
+
bool allowRewardOverride = settings.allowRewardOverride;
|
|
152
|
+
for (uint256 i = 0; i < _data.events.length; i++) {
|
|
153
|
+
uint reward = (
|
|
154
|
+
allowRewardOverride && _data.events[i].rewardOverride > 0
|
|
155
|
+
? _data.events[i].rewardOverride
|
|
156
|
+
: _eventReward(settings, _data.events[i].subtype)
|
|
157
|
+
) * _data.events[i].quantity;
|
|
158
|
+
if (reward > 0) {
|
|
159
|
+
totalRewards += reward;
|
|
160
|
+
if (totalRewards > rewardsBalance) revert NO_BALANCE();
|
|
161
|
+
rewardsBalance -= totalRewards;
|
|
162
|
+
|
|
163
|
+
_sendReward(
|
|
164
|
+
globalLimits,
|
|
165
|
+
limits,
|
|
166
|
+
memberLimits,
|
|
167
|
+
settings,
|
|
168
|
+
_data.events[i].contributers,
|
|
169
|
+
uint128(reward)
|
|
170
|
+
);
|
|
171
|
+
emit EventRewardClaimed(
|
|
172
|
+
_nftId,
|
|
173
|
+
_data.events[i].subtype,
|
|
174
|
+
_data.events[i].timestamp,
|
|
175
|
+
_data.events[i].quantity,
|
|
176
|
+
_data.events[i].eventUri,
|
|
177
|
+
_data.events[i].contributers,
|
|
178
|
+
uint128(reward / _data.events[i].contributers.length)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
emit NFTClaimed(_nftId, totalRewards);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @dev Returns the reward amount for the specified event type.
|
|
188
|
+
* @param _eventType The type of the event to get the reward for.
|
|
189
|
+
* @return reward amount for the specified event type.
|
|
190
|
+
*/
|
|
191
|
+
function _eventReward(
|
|
192
|
+
DirectPaymentsPool.PoolSettings memory settings,
|
|
193
|
+
uint16 _eventType
|
|
194
|
+
) internal pure returns (uint128 reward) {
|
|
195
|
+
for (uint i = 0; i < settings.validEvents.length; i++) {
|
|
196
|
+
if (_eventType == settings.validEvents[i]) return settings.rewardPerEvent[i];
|
|
197
|
+
}
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* @dev Returns the current month.
|
|
203
|
+
* @return month current month as a uint64 value.
|
|
204
|
+
*/
|
|
205
|
+
function _month() internal view returns (uint64 month) {
|
|
206
|
+
return uint64(block.timestamp / (60 * 60 * 24 * 30));
|
|
53
207
|
}
|
|
54
208
|
}
|
|
@@ -9,7 +9,7 @@ import { IERC721ReceiverUpgradeable } from "@openzeppelin/contracts-upgradeable/
|
|
|
9
9
|
|
|
10
10
|
import { ProvableNFT } from "./ProvableNFT.sol";
|
|
11
11
|
import { DirectPaymentsFactory } from "./DirectPaymentsFactory.sol";
|
|
12
|
-
import {
|
|
12
|
+
import { DirectPaymentsLibrary } from "./DirectPaymentsLibrary.sol";
|
|
13
13
|
import "../GoodCollective/GoodCollectiveSuperApp.sol";
|
|
14
14
|
|
|
15
15
|
interface IMembersValidator {
|
|
@@ -18,7 +18,7 @@ interface IMembersValidator {
|
|
|
18
18
|
address operator,
|
|
19
19
|
address member,
|
|
20
20
|
bytes memory extraData
|
|
21
|
-
) external returns (bool);
|
|
21
|
+
) external view returns (bool);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
interface IIdentityV2 {
|
|
@@ -48,6 +48,7 @@ contract DirectPaymentsPool is
|
|
|
48
48
|
error NO_BALANCE();
|
|
49
49
|
error NFTTYPE_CHANGED();
|
|
50
50
|
error EMPTY_MANAGER();
|
|
51
|
+
error LENGTH_MISMATCH();
|
|
51
52
|
|
|
52
53
|
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
|
|
53
54
|
bytes32 public constant MEMBER_ROLE = keccak256("MEMBER_ROLE");
|
|
@@ -74,7 +75,15 @@ contract DirectPaymentsPool is
|
|
|
74
75
|
uint256 rewardPerContributer
|
|
75
76
|
);
|
|
76
77
|
event NFTClaimed(uint256 indexed tokenId, uint256 totalRewards);
|
|
77
|
-
|
|
78
|
+
/**
|
|
79
|
+
* @dev Emitted when a contributor is skipped during reward distribution.
|
|
80
|
+
* This occurs when a contributor is either:
|
|
81
|
+
* - Not a member of the pool (does not have MEMBER_ROLE)
|
|
82
|
+
* - Not whitelisted (uniquenessValidator returns address(0))
|
|
83
|
+
* - Exceeds member limits (daily or monthly limits exceeded)
|
|
84
|
+
* @param contributer The address of the contributor that was skipped
|
|
85
|
+
*/
|
|
86
|
+
event NOT_MEMBER_OR_WHITELISTED_OR_LIMITS(address contributer);
|
|
78
87
|
|
|
79
88
|
// Define functions
|
|
80
89
|
struct PoolSettings {
|
|
@@ -181,127 +190,20 @@ contract DirectPaymentsPool is
|
|
|
181
190
|
function claim(uint256 _nftId, ProvableNFT.NFTData memory _data) public {
|
|
182
191
|
nft.proveNFTData(_nftId, _data);
|
|
183
192
|
if (claimedNfts[_nftId]) revert ALREADY_CLAIMED(_nftId);
|
|
184
|
-
|
|
193
|
+
claimedNfts[_nftId] = true;
|
|
185
194
|
// TODO: should pool own the NFTs?
|
|
186
195
|
// if (settings.collectNfts && nft.ownerOf(_nftId) != address(this)) revert NFT_MISSING(_nftId);
|
|
187
196
|
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* @dev Claims rewards for the specified NFT ID.
|
|
193
|
-
* @param _nftId The ID of the NFT to claim rewards for.
|
|
194
|
-
* @param _data The NFTData struct containing data about the NFT.
|
|
195
|
-
*/
|
|
196
|
-
function _claim(uint256 _nftId, ProvableNFT.NFTData memory _data) internal {
|
|
197
|
-
claimedNfts[_nftId] = true;
|
|
198
|
-
uint totalRewards;
|
|
199
|
-
uint rewardsBalance = settings.rewardToken.balanceOf(address(this));
|
|
200
|
-
|
|
201
|
-
bool allowRewardOverride = settings.allowRewardOverride;
|
|
197
|
+
// Loop through the events in the NFT data and add members
|
|
202
198
|
for (uint256 i = 0; i < _data.events.length; i++) {
|
|
203
|
-
uint
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
: _eventReward(_data.events[i].subtype)
|
|
207
|
-
) * _data.events[i].quantity;
|
|
208
|
-
if (reward > 0) {
|
|
209
|
-
totalRewards += reward;
|
|
210
|
-
if (totalRewards > rewardsBalance) revert NO_BALANCE();
|
|
211
|
-
rewardsBalance -= totalRewards;
|
|
212
|
-
_sendReward(_data.events[i].contributers, uint128(reward));
|
|
213
|
-
emit EventRewardClaimed(
|
|
214
|
-
_nftId,
|
|
215
|
-
_data.events[i].subtype,
|
|
216
|
-
_data.events[i].timestamp,
|
|
217
|
-
_data.events[i].quantity,
|
|
218
|
-
_data.events[i].eventUri,
|
|
219
|
-
_data.events[i].contributers,
|
|
220
|
-
uint128(reward / _data.events[i].contributers.length)
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
emit NFTClaimed(_nftId, totalRewards);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* @dev Returns the reward amount for the specified event type.
|
|
230
|
-
* @param _eventType The type of the event to get the reward for.
|
|
231
|
-
* @return reward amount for the specified event type.
|
|
232
|
-
*/
|
|
233
|
-
function _eventReward(uint16 _eventType) internal view returns (uint128 reward) {
|
|
234
|
-
for (uint i = 0; i < settings.validEvents.length; i++) {
|
|
235
|
-
if (_eventType == settings.validEvents[i]) return settings.rewardPerEvent[i];
|
|
236
|
-
}
|
|
237
|
-
return 0;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* @dev Sends rewards to the specified recipients.
|
|
242
|
-
* @param recipients The addresses of the recipients to send rewards to.
|
|
243
|
-
* @param reward The total amount of rewards to send.
|
|
244
|
-
*/
|
|
245
|
-
function _sendReward(address[] memory recipients, uint128 reward) internal {
|
|
246
|
-
uint128 perReward = uint128(reward / recipients.length);
|
|
247
|
-
uint128 totalSent;
|
|
248
|
-
for (uint i = 0; i < recipients.length; i++) {
|
|
249
|
-
bool valid = _enforceAndUpdateMemberLimits(recipients[i], perReward);
|
|
250
|
-
if (valid) {
|
|
251
|
-
settings.rewardToken.safeTransfer(recipients[i], perReward);
|
|
252
|
-
totalSent += perReward;
|
|
253
|
-
} else {
|
|
254
|
-
emit NOT_MEMBER_OR_WHITELISTED(recipients[i]);
|
|
199
|
+
for (uint j = 0; j < _data.events[i].contributers.length; j++) {
|
|
200
|
+
//dont revert on non valid members, just dont reward them (their reward is lost)
|
|
201
|
+
_addMember(_data.events[i].contributers[j], "");
|
|
255
202
|
}
|
|
256
203
|
}
|
|
257
|
-
|
|
204
|
+
DirectPaymentsLibrary._claim(globalLimits, limits, memberLimits, settings, _nftId, _data);
|
|
258
205
|
}
|
|
259
206
|
|
|
260
|
-
/**
|
|
261
|
-
* @dev Enforces and updates the reward limits for the specified member.
|
|
262
|
-
* @param member The address of the member to enforce and update limits for.
|
|
263
|
-
* @param reward The amount of rewards to enforce and update limits for.
|
|
264
|
-
*/
|
|
265
|
-
function _enforceAndUpdateMemberLimits(address member, uint128 reward) internal returns (bool) {
|
|
266
|
-
//dont revert on non valid members, just dont reward them (their reward is lost)
|
|
267
|
-
if (_addMember(member, "") == false) {
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
DirectPayemntsLibrary._updateMemberLimits(memberLimits[member], reward, _month());
|
|
272
|
-
|
|
273
|
-
if (
|
|
274
|
-
memberLimits[member].daily > limits.maxMemberPerDay ||
|
|
275
|
-
memberLimits[member].monthly > limits.maxMemberPerMonth
|
|
276
|
-
) revert OVER_MEMBER_LIMITS(member);
|
|
277
|
-
|
|
278
|
-
return true;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* @dev Enforces and updates the global reward limits.
|
|
283
|
-
* @param reward The amount of rewards to enforce and update limits for.
|
|
284
|
-
*/
|
|
285
|
-
function _enforceAndUpdateGlobalLimits(uint128 reward) internal {
|
|
286
|
-
DirectPayemntsLibrary._updateGlobalLimits(globalLimits, reward, _month());
|
|
287
|
-
|
|
288
|
-
if (globalLimits.monthly > limits.maxTotalPerMonth) revert OVER_GLOBAL_LIMITS();
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* @dev Returns the current month.
|
|
293
|
-
* @return month current month as a uint64 value.
|
|
294
|
-
*/
|
|
295
|
-
function _month() internal view returns (uint64 month) {
|
|
296
|
-
return uint64(block.timestamp / (60 * 60 * 24 * 30));
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* @dev Adds a member to the contract.
|
|
301
|
-
* @param member The address of the member to add.
|
|
302
|
-
* @param extraData Additional data to validate the member.
|
|
303
|
-
*/
|
|
304
|
-
|
|
305
207
|
function _addMember(address member, bytes memory extraData) internal returns (bool isMember) {
|
|
306
208
|
if (hasRole(MEMBER_ROLE, member)) return true;
|
|
307
209
|
|
|
@@ -321,6 +223,19 @@ contract DirectPaymentsPool is
|
|
|
321
223
|
return true;
|
|
322
224
|
}
|
|
323
225
|
|
|
226
|
+
/**
|
|
227
|
+
* @dev Adds multiple members to the pool in a single transaction.
|
|
228
|
+
* @param members Array of member addresses to add.
|
|
229
|
+
* @param extraData Array of additional validation data for each member.
|
|
230
|
+
*/
|
|
231
|
+
function addMembers(address[] calldata members, bytes[] calldata extraData) external onlyRole(MANAGER_ROLE) {
|
|
232
|
+
if (members.length != extraData.length) revert LENGTH_MISMATCH();
|
|
233
|
+
|
|
234
|
+
for (uint i = 0; i < members.length; i++) {
|
|
235
|
+
_addMember(members[i], extraData[i]);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
324
239
|
function _grantRole(bytes32 role, address account) internal virtual override {
|
|
325
240
|
if (role == MEMBER_ROLE) {
|
|
326
241
|
registry.addMember(account);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
pragma solidity >=0.8.0;
|
|
4
4
|
|
|
5
5
|
import { SuperAppBaseFlow } from "./SuperAppBaseFlow.sol";
|
|
6
|
-
import { ISuperfluid, ISuperToken, SuperAppDefinitions } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
|
|
6
|
+
import { ISuperfluid, ISuperToken, SuperAppDefinitions, ISuperApp } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
|
|
7
7
|
import { ISuperGoodDollar } from "@gooddollar/goodprotocol/contracts/token/superfluid/ISuperGoodDollar.sol";
|
|
8
8
|
import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol";
|
|
9
9
|
import { CFAv1Library, IConstantFlowAgreementV1 } from "@superfluid-finance/ethereum-contracts/contracts/apps/CFAv1Library.sol";
|
|
@@ -90,11 +90,8 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
90
90
|
// Set the super token address
|
|
91
91
|
superToken = _superToken;
|
|
92
92
|
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// Register the app with the host
|
|
97
|
-
host.registerApp(callBackDefinitions);
|
|
93
|
+
// // try to register the app with the host, required for backward compatability with unit tests
|
|
94
|
+
if (host.isApp(this) == false) try host.registerApp(SuperAppDefinitions.APP_LEVEL_FINAL) {} catch {}
|
|
98
95
|
|
|
99
96
|
//initialize InitData struct, and set equal to cfaV1
|
|
100
97
|
cfaV1 = CFAv1Library.InitData(
|
|
@@ -366,6 +363,10 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
366
363
|
TransferHelper.safeTransfer(address(superToken), recipient, fee);
|
|
367
364
|
}
|
|
368
365
|
|
|
366
|
+
function recoverFunds(address _recipient, uint256 amount) external {
|
|
367
|
+
HelperLibrary.recoverFunds(superToken, _recipient, amount);
|
|
368
|
+
}
|
|
369
|
+
|
|
369
370
|
/**
|
|
370
371
|
* for methods that can be called via superfluid batch or directly
|
|
371
372
|
*/
|
|
@@ -5,6 +5,8 @@ interface IRegistry {
|
|
|
5
5
|
function feeRecipient() external view returns (address);
|
|
6
6
|
|
|
7
7
|
function feeBps() external view returns (uint32);
|
|
8
|
+
|
|
9
|
+
function hasRole(bytes32 role, address account) external view returns (bool);
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
interface IGoodCollectiveSuperApp {
|
|
@@ -21,4 +23,6 @@ interface IGoodCollectiveSuperApp {
|
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
function getAdminFee() external view returns (address admin, uint32 feeBps);
|
|
26
|
+
|
|
27
|
+
function getRegistry() external view returns (IRegistry);
|
|
24
28
|
}
|
|
@@ -6,6 +6,12 @@ import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/cont
|
|
|
6
6
|
|
|
7
7
|
// import "hardhat/console.sol";
|
|
8
8
|
|
|
9
|
+
interface IRegisterSuperapp {
|
|
10
|
+
function registerApp(address app, uint256 configWord) external;
|
|
11
|
+
|
|
12
|
+
function registerAppByFactory(address app, uint256 configWord) external;
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
abstract contract SuperAppBaseFlow is ISuperApp {
|
|
10
16
|
using SuperTokenV1Library for ISuperToken;
|
|
11
17
|
|
|
@@ -5,7 +5,6 @@ import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils
|
|
|
5
5
|
import { IERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
|
|
6
6
|
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
|
|
7
7
|
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
|
8
|
-
import { IERC721ReceiverUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol";
|
|
9
8
|
|
|
10
9
|
import "../GoodCollective/GoodCollectiveSuperApp.sol";
|
|
11
10
|
import "./UBIPoolFactory.sol";
|
|
@@ -23,6 +22,7 @@ contract UBIPool is AccessControlUpgradeable, GoodCollectiveSuperApp, UUPSUpgrad
|
|
|
23
22
|
error EMPTY_MANAGER();
|
|
24
23
|
error MAX_MEMBERS_REACHED();
|
|
25
24
|
error MAX_PERIOD_CLAIMERS_REACHED(uint256 claimers);
|
|
25
|
+
error LENGTH_MISMATCH();
|
|
26
26
|
|
|
27
27
|
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
|
|
28
28
|
bytes32 public constant MEMBER_ROLE = keccak256("MEMBER_ROLE");
|
|
@@ -189,10 +189,8 @@ contract UBIPool is AccessControlUpgradeable, GoodCollectiveSuperApp, UUPSUpgrad
|
|
|
189
189
|
|
|
190
190
|
nextPeriodPool = status.dailyCyclePool;
|
|
191
191
|
nextDailyUbi;
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
) //start of cycle or first time
|
|
195
|
-
{
|
|
192
|
+
if ((currentDayInCycle() + 1) >= status.currentCycleLength || shouldStartEarlyCycle) {
|
|
193
|
+
//start of cycle or first time
|
|
196
194
|
nextPeriodPool = currentBalance / ubiSettings.cycleLengthDays;
|
|
197
195
|
newCycle = true;
|
|
198
196
|
}
|
|
@@ -271,38 +269,83 @@ contract UBIPool is AccessControlUpgradeable, GoodCollectiveSuperApp, UUPSUpgrad
|
|
|
271
269
|
}
|
|
272
270
|
|
|
273
271
|
/**
|
|
274
|
-
* @dev
|
|
272
|
+
* @dev Internal function to add a member with validation.
|
|
273
|
+
* Always validates members, even when called by manager.
|
|
275
274
|
* @param member The address of the member to add.
|
|
276
275
|
* @param extraData Additional data to validate the member.
|
|
276
|
+
* @return isMember True if member was added, false if validation failed.
|
|
277
277
|
*/
|
|
278
|
+
function _addMember(address member, bytes memory extraData) internal returns (bool isMember) {
|
|
279
|
+
if (hasRole(MEMBER_ROLE, member)) return true;
|
|
278
280
|
|
|
279
|
-
function addMember(address member, bytes memory extraData) external returns (bool isMember) {
|
|
280
281
|
if (address(settings.uniquenessValidator) != address(0)) {
|
|
281
282
|
address rootAddress = settings.uniquenessValidator.getWhitelistedRoot(member);
|
|
282
|
-
if (rootAddress == address(0))
|
|
283
|
+
if (rootAddress == address(0)) return false;
|
|
283
284
|
}
|
|
284
285
|
|
|
285
|
-
|
|
286
|
+
// Always check membersValidator if it exists, regardless of caller role
|
|
287
|
+
if (address(settings.membersValidator) != address(0)) {
|
|
286
288
|
if (settings.membersValidator.isMemberValid(address(this), msg.sender, member, extraData) == false) {
|
|
287
|
-
|
|
289
|
+
return false;
|
|
288
290
|
}
|
|
289
291
|
}
|
|
290
292
|
// if no members validator then if members only only manager can add members
|
|
291
293
|
else if (ubiSettings.onlyMembers && hasRole(MANAGER_ROLE, msg.sender) == false) {
|
|
292
|
-
|
|
294
|
+
return false;
|
|
293
295
|
}
|
|
294
296
|
|
|
295
297
|
_grantRole(MEMBER_ROLE, member);
|
|
296
298
|
return true;
|
|
297
299
|
}
|
|
298
300
|
|
|
301
|
+
/**
|
|
302
|
+
* @dev Adds a member to the contract.
|
|
303
|
+
* @param member The address of the member to add.
|
|
304
|
+
* @param extraData Additional data to validate the member.
|
|
305
|
+
*/
|
|
306
|
+
function addMember(address member, bytes memory extraData) public returns (bool isMember) {
|
|
307
|
+
bool success = _addMember(member, extraData);
|
|
308
|
+
|
|
309
|
+
if (!success) {
|
|
310
|
+
// Determine the specific error to revert with
|
|
311
|
+
if (address(settings.uniquenessValidator) != address(0)) {
|
|
312
|
+
address rootAddress = settings.uniquenessValidator.getWhitelistedRoot(member);
|
|
313
|
+
if (rootAddress == address(0)) revert NOT_WHITELISTED(member);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (address(settings.membersValidator) != address(0) && hasRole(MANAGER_ROLE, msg.sender) == false) {
|
|
317
|
+
revert NOT_MEMBER(member);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (ubiSettings.onlyMembers && hasRole(MANAGER_ROLE, msg.sender) == false) {
|
|
321
|
+
revert NOT_MANAGER(member);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return success;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* @dev Adds multiple members to the pool in a single transaction.
|
|
330
|
+
* Invalid members are skipped instead of causing the transaction to revert.
|
|
331
|
+
* @param members Array of member addresses to add.
|
|
332
|
+
* @param extraData Array of additional validation data for each member.
|
|
333
|
+
*/
|
|
334
|
+
function addMembers(address[] calldata members, bytes[] calldata extraData) external onlyRole(MANAGER_ROLE) {
|
|
335
|
+
if (members.length != extraData.length) revert LENGTH_MISMATCH();
|
|
336
|
+
|
|
337
|
+
for (uint i = 0; i < members.length; i++) {
|
|
338
|
+
_addMember(members[i], extraData[i]);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
299
342
|
function removeMember(address member) external onlyRole(MANAGER_ROLE) {
|
|
300
343
|
_revokeRole(MEMBER_ROLE, member);
|
|
301
344
|
}
|
|
302
345
|
|
|
303
346
|
function _grantRole(bytes32 role, address account) internal virtual override {
|
|
304
347
|
if (role == MEMBER_ROLE && hasRole(MEMBER_ROLE, account) == false) {
|
|
305
|
-
if (ubiSettings.maxMembers > 0 && status.membersCount
|
|
348
|
+
if (ubiSettings.maxMembers > 0 && status.membersCount >= ubiSettings.maxMembers)
|
|
306
349
|
revert MAX_MEMBERS_REACHED();
|
|
307
350
|
registry.addMember(account);
|
|
308
351
|
status.membersCount += 1;
|
|
@@ -357,11 +400,8 @@ contract UBIPool is AccessControlUpgradeable, GoodCollectiveSuperApp, UUPSUpgrad
|
|
|
357
400
|
}
|
|
358
401
|
|
|
359
402
|
function _verifyPoolSettings(PoolSettings memory _poolSettings) internal pure {
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
address(_poolSettings.uniquenessValidator) == address(0) ||
|
|
363
|
-
address(_poolSettings.rewardToken) == address(0)
|
|
364
|
-
) revert INVALID_0_VALUE();
|
|
403
|
+
if (_poolSettings.manager == address(0) || address(_poolSettings.rewardToken) == address(0))
|
|
404
|
+
revert INVALID_0_VALUE();
|
|
365
405
|
}
|
|
366
406
|
|
|
367
407
|
function estimateNextDailyUBI() public view returns (uint256 nextDailyUbi) {
|
|
@@ -391,7 +431,11 @@ contract UBIPool is AccessControlUpgradeable, GoodCollectiveSuperApp, UUPSUpgrad
|
|
|
391
431
|
}
|
|
392
432
|
|
|
393
433
|
function hasClaimed(address _member) public view returns (bool) {
|
|
394
|
-
address whitelistedRoot =
|
|
434
|
+
address whitelistedRoot = _member;
|
|
435
|
+
if (address(settings.uniquenessValidator) != address(0)) {
|
|
436
|
+
whitelistedRoot = IIdentityV2(settings.uniquenessValidator).getWhitelistedRoot(_member);
|
|
437
|
+
}
|
|
438
|
+
whitelistedRoot = IIdentityV2(settings.uniquenessValidator).getWhitelistedRoot(_member);
|
|
395
439
|
return status.lastClaimed[whitelistedRoot] == getCurrentDay();
|
|
396
440
|
}
|
|
397
441
|
|