@gooddollar/goodcollective-contracts 1.2.0 → 1.3.1
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/contracts/DirectPayments/DirectPaymentsFactory.sol +31 -12
- package/contracts/DirectPayments/DirectPaymentsLibrary.sol +208 -0
- package/contracts/DirectPayments/DirectPaymentsPool.sol +19 -151
- package/contracts/GoodCollective/GoodCollectiveSuperApp.sol +72 -19
- package/contracts/GoodCollective/IGoodCollectiveSuperApp.sol +10 -0
- package/contracts/GoodCollective/SuperAppBaseFlow.sol +6 -0
- package/contracts/Interfaces.sol +25 -0
- package/contracts/UBI/UBIPool.sol +76 -75
- package/contracts/UBI/UBIPoolFactory.sol +34 -13
- package/contracts/utils/HelperLibrary.sol +66 -23
- package/package.json +3 -3
- package/releases/deployment.json +8486 -30703
- package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.ts +16 -4
- package/typechain-types/contracts/DirectPayments/DirectPaymentsLibrary.ts +146 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool.ts +191 -20
- 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 +141 -6
- package/typechain-types/contracts/{DirectPayments/DirectPaymentsFactory.sol/IRegistry.ts → GoodCollective/IGoodCollectiveSuperApp.sol/IGoodCollectiveSuperApp.ts} +32 -20
- package/typechain-types/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IRegistry.ts +38 -1
- package/typechain-types/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/index.ts +1 -0
- 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/UBIPool.sol → Interfaces.sol}/IIdentityV2.ts +1 -1
- package/typechain-types/contracts/{UBI/UBIPool.sol → Interfaces.sol}/IMembersValidator.ts +1 -1
- package/typechain-types/contracts/{UBI/UBIPool.sol → Interfaces.sol}/index.ts +0 -1
- package/typechain-types/contracts/UBI/{UBIPool.sol/UBIPool.ts → UBIPool.ts} +279 -47
- package/typechain-types/contracts/UBI/UBIPoolFactory.ts +58 -34
- package/typechain-types/contracts/UBI/index.ts +1 -2
- package/typechain-types/contracts/index.ts +2 -0
- package/typechain-types/contracts/utils/HelperLibrary.ts +46 -4
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory__factory.ts +16 -1
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsLibrary__factory.ts +169 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool__factory.ts +101 -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 +66 -0
- package/typechain-types/factories/contracts/{DirectPayments/DirectPaymentsFactory.sol/IRegistry__factory.ts → GoodCollective/IGoodCollectiveSuperApp.sol/IGoodCollectiveSuperApp__factory.ts} +21 -12
- package/typechain-types/factories/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IRegistry__factory.ts +24 -0
- package/typechain-types/factories/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/index.ts +1 -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/UBIPool.sol → Interfaces.sol}/IIdentityV2__factory.ts +1 -1
- package/typechain-types/factories/contracts/{UBI/UBIPool.sol → Interfaces.sol}/IMembersValidator__factory.ts +1 -1
- package/typechain-types/factories/contracts/{UBI/UBIPool.sol → Interfaces.sol}/index.ts +0 -1
- package/typechain-types/factories/contracts/UBI/UBIPoolFactory__factory.ts +56 -7
- package/typechain-types/factories/contracts/UBI/UBIPool__factory.ts +2070 -0
- package/typechain-types/factories/contracts/UBI/index.ts +1 -1
- package/typechain-types/factories/contracts/index.ts +1 -0
- package/typechain-types/factories/contracts/test/HelperLibraryTest__factory.ts +1 -1
- package/typechain-types/factories/contracts/utils/HelperLibrary__factory.ts +41 -1
- package/typechain-types/hardhat.d.ts +35 -8
- package/typechain-types/index.ts +10 -4
- package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.sol/DirectPaymentsFactory.ts +0 -1327
- package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.sol/index.ts +0 -5
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory.sol/DirectPaymentsFactory__factory.ts +0 -1004
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory.sol/index.ts +0 -5
- package/typechain-types/factories/contracts/UBI/UBIPool.sol/UBIPool__factory.ts +0 -1916
|
@@ -4,17 +4,18 @@ pragma solidity >=0.8.0;
|
|
|
4
4
|
// import the DirectPayments contract
|
|
5
5
|
import "./DirectPaymentsPool.sol";
|
|
6
6
|
import "./ProvableNFT.sol";
|
|
7
|
+
import "../GoodCollective/SuperAppBaseFlow.sol";
|
|
7
8
|
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
|
8
9
|
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
|
|
9
10
|
import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
|
|
10
|
-
|
|
11
11
|
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
12
12
|
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
13
13
|
|
|
14
|
-
import "hardhat/console.sol";
|
|
14
|
+
// import "hardhat/console.sol";
|
|
15
15
|
|
|
16
16
|
contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
17
17
|
error NOT_PROJECT_OWNER();
|
|
18
|
+
error NOT_PROJECT_MANAGER();
|
|
18
19
|
error NOT_POOL();
|
|
19
20
|
|
|
20
21
|
event PoolCreated(
|
|
@@ -60,9 +61,9 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
60
61
|
_;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
modifier
|
|
64
|
-
if (pool.hasRole(pool.
|
|
65
|
-
revert
|
|
64
|
+
modifier onlyPoolManager(DirectPaymentsPool pool) {
|
|
65
|
+
if (pool.hasRole(pool.MANAGER_ROLE(), msg.sender) == false) {
|
|
66
|
+
revert NOT_PROJECT_MANAGER();
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
_;
|
|
@@ -98,18 +99,20 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
98
99
|
string memory _projectId,
|
|
99
100
|
string memory _ipfs,
|
|
100
101
|
DirectPaymentsPool.PoolSettings memory _settings,
|
|
101
|
-
DirectPaymentsPool.SafetyLimits memory _limits
|
|
102
|
+
DirectPaymentsPool.SafetyLimits memory _limits,
|
|
103
|
+
uint32 _managerFeeBps
|
|
102
104
|
) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) {
|
|
103
|
-
return _createPool(_projectId, _ipfs, _settings, _limits, true);
|
|
105
|
+
return _createPool(_projectId, _ipfs, _settings, _limits, _managerFeeBps, true);
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
function createPool(
|
|
107
109
|
string memory _projectId,
|
|
108
110
|
string memory _ipfs,
|
|
109
111
|
DirectPaymentsPool.PoolSettings memory _settings,
|
|
110
|
-
DirectPaymentsPool.SafetyLimits memory _limits
|
|
112
|
+
DirectPaymentsPool.SafetyLimits memory _limits,
|
|
113
|
+
uint32 _managerFeeBps
|
|
111
114
|
) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) {
|
|
112
|
-
return _createPool(_projectId, _ipfs, _settings, _limits, false);
|
|
115
|
+
return _createPool(_projectId, _ipfs, _settings, _limits, _managerFeeBps, false);
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
function _createPool(
|
|
@@ -117,12 +120,16 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
117
120
|
string memory _ipfs,
|
|
118
121
|
DirectPaymentsPool.PoolSettings memory _settings,
|
|
119
122
|
DirectPaymentsPool.SafetyLimits memory _limits,
|
|
123
|
+
uint32 _managerFeeBps,
|
|
120
124
|
bool useBeacon
|
|
121
125
|
) internal returns (DirectPaymentsPool pool) {
|
|
122
126
|
//TODO: add check if msg.sender is whitelisted
|
|
123
127
|
|
|
124
128
|
_settings.nftType = nextNftType;
|
|
125
|
-
bytes memory initCall = abi.encodeCall(
|
|
129
|
+
bytes memory initCall = abi.encodeCall(
|
|
130
|
+
DirectPaymentsPool.initialize,
|
|
131
|
+
(nft, _settings, _limits, _managerFeeBps, this)
|
|
132
|
+
);
|
|
126
133
|
|
|
127
134
|
if (useBeacon) {
|
|
128
135
|
pool = DirectPaymentsPool(address(new BeaconProxy(address(impl), initCall)));
|
|
@@ -130,7 +137,19 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
130
137
|
pool = DirectPaymentsPool(address(new ERC1967Proxy(impl.implementation(), initCall)));
|
|
131
138
|
}
|
|
132
139
|
|
|
133
|
-
|
|
140
|
+
// Register the app with the host
|
|
141
|
+
if (pool.host().isApp(pool) == false) {
|
|
142
|
+
try
|
|
143
|
+
IRegisterSuperapp(address(pool.host())).registerApp(address(pool), SuperAppDefinitions.APP_LEVEL_FINAL)
|
|
144
|
+
{} catch {
|
|
145
|
+
//fallback for older versions of superfluid used in unit tests
|
|
146
|
+
IRegisterSuperapp(address(pool.host())).registerAppByFactory(
|
|
147
|
+
address(pool),
|
|
148
|
+
SuperAppDefinitions.APP_LEVEL_FINAL
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
134
153
|
nft.grantRole(nft.getManagerRole(nextNftType), address(pool));
|
|
135
154
|
|
|
136
155
|
//access control to project is determinted by the first pool access control rules
|
|
@@ -148,7 +167,7 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
148
167
|
nextNftType++;
|
|
149
168
|
}
|
|
150
169
|
|
|
151
|
-
function changePoolDetails(DirectPaymentsPool _pool, string memory _ipfs) external
|
|
170
|
+
function changePoolDetails(DirectPaymentsPool _pool, string memory _ipfs) external onlyPoolManager(_pool) {
|
|
152
171
|
registry[address(_pool)].ipfs = _ipfs;
|
|
153
172
|
emit PoolDetailsChanged(address(_pool), _ipfs);
|
|
154
173
|
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity >=0.8.0;
|
|
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
|
+
|
|
7
|
+
import "./DirectPaymentsPool.sol";
|
|
8
|
+
import "./ProvableNFT.sol";
|
|
9
|
+
|
|
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 {
|
|
28
|
+
if (memberStats.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
29
|
+
{
|
|
30
|
+
memberStats.daily = reward;
|
|
31
|
+
} else {
|
|
32
|
+
memberStats.daily += reward;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (memberStats.lastMonth < _month()) //month switched
|
|
36
|
+
{
|
|
37
|
+
memberStats.monthly = reward;
|
|
38
|
+
} else {
|
|
39
|
+
memberStats.monthly += reward;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
memberStats.total += reward;
|
|
43
|
+
memberStats.lastReward = uint64(block.timestamp);
|
|
44
|
+
memberStats.lastMonth = _month();
|
|
45
|
+
}
|
|
46
|
+
|
|
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(
|
|
54
|
+
DirectPaymentsPool.LimitsData storage globalLimits,
|
|
55
|
+
DirectPaymentsPool.SafetyLimits memory limits,
|
|
56
|
+
uint128 reward
|
|
57
|
+
) public {
|
|
58
|
+
if (globalLimits.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
59
|
+
{
|
|
60
|
+
globalLimits.daily = reward;
|
|
61
|
+
} else {
|
|
62
|
+
globalLimits.daily += reward;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (globalLimits.lastMonth < _month()) //month switched
|
|
66
|
+
{
|
|
67
|
+
globalLimits.monthly = reward;
|
|
68
|
+
} else {
|
|
69
|
+
globalLimits.monthly += reward;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
globalLimits.total += reward;
|
|
73
|
+
globalLimits.lastReward = uint64(block.timestamp);
|
|
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));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -9,6 +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 { DirectPaymentsLibrary } from "./DirectPaymentsLibrary.sol";
|
|
12
13
|
import "../GoodCollective/GoodCollectiveSuperApp.sol";
|
|
13
14
|
|
|
14
15
|
interface IMembersValidator {
|
|
@@ -17,7 +18,7 @@ interface IMembersValidator {
|
|
|
17
18
|
address operator,
|
|
18
19
|
address member,
|
|
19
20
|
bytes memory extraData
|
|
20
|
-
) external returns (bool);
|
|
21
|
+
) external view returns (bool);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
interface IIdentityV2 {
|
|
@@ -73,7 +74,7 @@ contract DirectPaymentsPool is
|
|
|
73
74
|
uint256 rewardPerContributer
|
|
74
75
|
);
|
|
75
76
|
event NFTClaimed(uint256 indexed tokenId, uint256 totalRewards);
|
|
76
|
-
event
|
|
77
|
+
event NOT_MEMBER_OR_WHITELISTED_OR_LIMITS(address contributer);
|
|
77
78
|
|
|
78
79
|
// Define functions
|
|
79
80
|
struct PoolSettings {
|
|
@@ -111,6 +112,8 @@ contract DirectPaymentsPool is
|
|
|
111
112
|
LimitsData public globalLimits;
|
|
112
113
|
DirectPaymentsFactory public registry;
|
|
113
114
|
|
|
115
|
+
uint32 public managerFeeBps;
|
|
116
|
+
|
|
114
117
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
115
118
|
constructor(ISuperfluid _host, IV3SwapRouter _swapRouter) GoodCollectiveSuperApp(_host, _swapRouter) {}
|
|
116
119
|
|
|
@@ -124,6 +127,10 @@ contract DirectPaymentsPool is
|
|
|
124
127
|
return IRegistry(address(registry));
|
|
125
128
|
}
|
|
126
129
|
|
|
130
|
+
function getManagerFee() public view override returns (address feeRecipient, uint32 feeBps) {
|
|
131
|
+
return (settings.manager, managerFeeBps);
|
|
132
|
+
}
|
|
133
|
+
|
|
127
134
|
/**
|
|
128
135
|
* @dev Initializes the contract with the given settings and limits.
|
|
129
136
|
* @param _nft The ProvableNFT contract address.
|
|
@@ -134,12 +141,14 @@ contract DirectPaymentsPool is
|
|
|
134
141
|
ProvableNFT _nft,
|
|
135
142
|
PoolSettings memory _settings,
|
|
136
143
|
SafetyLimits memory _limits,
|
|
144
|
+
uint32 _managerFeeBps,
|
|
137
145
|
DirectPaymentsFactory _registry
|
|
138
146
|
) external initializer {
|
|
139
147
|
registry = _registry;
|
|
140
148
|
settings = _settings;
|
|
141
149
|
limits = _limits;
|
|
142
150
|
nft = _nft;
|
|
151
|
+
managerFeeBps = _managerFeeBps;
|
|
143
152
|
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender); // when using factory this gives factory role which then set role to the real msg.sender
|
|
144
153
|
_setupRole(MANAGER_ROLE, _settings.manager);
|
|
145
154
|
_setupRole(MINTER_ROLE, _settings.manager);
|
|
@@ -172,162 +181,20 @@ contract DirectPaymentsPool is
|
|
|
172
181
|
function claim(uint256 _nftId, ProvableNFT.NFTData memory _data) public {
|
|
173
182
|
nft.proveNFTData(_nftId, _data);
|
|
174
183
|
if (claimedNfts[_nftId]) revert ALREADY_CLAIMED(_nftId);
|
|
175
|
-
|
|
184
|
+
claimedNfts[_nftId] = true;
|
|
176
185
|
// TODO: should pool own the NFTs?
|
|
177
186
|
// if (settings.collectNfts && nft.ownerOf(_nftId) != address(this)) revert NFT_MISSING(_nftId);
|
|
178
187
|
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* @dev Claims rewards for the specified NFT ID.
|
|
184
|
-
* @param _nftId The ID of the NFT to claim rewards for.
|
|
185
|
-
* @param _data The NFTData struct containing data about the NFT.
|
|
186
|
-
*/
|
|
187
|
-
function _claim(uint256 _nftId, ProvableNFT.NFTData memory _data) internal {
|
|
188
|
-
claimedNfts[_nftId] = true;
|
|
189
|
-
uint totalRewards;
|
|
190
|
-
uint rewardsBalance = settings.rewardToken.balanceOf(address(this));
|
|
191
|
-
|
|
192
|
-
bool allowRewardOverride = settings.allowRewardOverride;
|
|
188
|
+
// Loop through the events in the NFT data and add members
|
|
193
189
|
for (uint256 i = 0; i < _data.events.length; i++) {
|
|
194
|
-
uint
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
: _eventReward(_data.events[i].subtype)
|
|
198
|
-
) * _data.events[i].quantity;
|
|
199
|
-
if (reward > 0) {
|
|
200
|
-
totalRewards += reward;
|
|
201
|
-
if (totalRewards > rewardsBalance) revert NO_BALANCE();
|
|
202
|
-
rewardsBalance -= totalRewards;
|
|
203
|
-
_sendReward(_data.events[i].contributers, uint128(reward));
|
|
204
|
-
emit EventRewardClaimed(
|
|
205
|
-
_nftId,
|
|
206
|
-
_data.events[i].subtype,
|
|
207
|
-
_data.events[i].timestamp,
|
|
208
|
-
_data.events[i].quantity,
|
|
209
|
-
_data.events[i].eventUri,
|
|
210
|
-
_data.events[i].contributers,
|
|
211
|
-
uint128(reward / _data.events[i].contributers.length)
|
|
212
|
-
);
|
|
190
|
+
for (uint j = 0; j < _data.events[i].contributers.length; j++) {
|
|
191
|
+
//dont revert on non valid members, just dont reward them (their reward is lost)
|
|
192
|
+
_addMember(_data.events[i].contributers[j], "");
|
|
213
193
|
}
|
|
214
194
|
}
|
|
215
|
-
|
|
216
|
-
emit NFTClaimed(_nftId, totalRewards);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* @dev Returns the reward amount for the specified event type.
|
|
221
|
-
* @param _eventType The type of the event to get the reward for.
|
|
222
|
-
* @return reward amount for the specified event type.
|
|
223
|
-
*/
|
|
224
|
-
function _eventReward(uint16 _eventType) internal view returns (uint128 reward) {
|
|
225
|
-
for (uint i = 0; i < settings.validEvents.length; i++) {
|
|
226
|
-
if (_eventType == settings.validEvents[i]) return settings.rewardPerEvent[i];
|
|
227
|
-
}
|
|
228
|
-
return 0;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* @dev Sends rewards to the specified recipients.
|
|
233
|
-
* @param recipients The addresses of the recipients to send rewards to.
|
|
234
|
-
* @param reward The total amount of rewards to send.
|
|
235
|
-
*/
|
|
236
|
-
function _sendReward(address[] memory recipients, uint128 reward) internal {
|
|
237
|
-
uint128 perReward = uint128(reward / recipients.length);
|
|
238
|
-
uint128 totalSent;
|
|
239
|
-
for (uint i = 0; i < recipients.length; i++) {
|
|
240
|
-
bool valid = _enforceAndUpdateMemberLimits(recipients[i], perReward);
|
|
241
|
-
if (valid) {
|
|
242
|
-
settings.rewardToken.safeTransfer(recipients[i], perReward);
|
|
243
|
-
totalSent += perReward;
|
|
244
|
-
} else {
|
|
245
|
-
emit NOT_MEMBER_OR_WHITELISTED(recipients[i]);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
_enforceAndUpdateGlobalLimits(totalSent);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* @dev Enforces and updates the reward limits for the specified member.
|
|
253
|
-
* @param member The address of the member to enforce and update limits for.
|
|
254
|
-
* @param reward The amount of rewards to enforce and update limits for.
|
|
255
|
-
*/
|
|
256
|
-
function _enforceAndUpdateMemberLimits(address member, uint128 reward) internal returns (bool) {
|
|
257
|
-
//dont revert on non valid members, just dont reward them (their reward is lost)
|
|
258
|
-
if (_addMember(member, "") == false) {
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
uint64 curMonth = _month();
|
|
263
|
-
if (memberLimits[member].lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
264
|
-
{
|
|
265
|
-
memberLimits[member].daily = reward;
|
|
266
|
-
} else {
|
|
267
|
-
memberLimits[member].daily += reward;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (memberLimits[member].lastMonth < curMonth) //month switched
|
|
271
|
-
{
|
|
272
|
-
memberLimits[member].monthly = reward;
|
|
273
|
-
} else {
|
|
274
|
-
memberLimits[member].monthly += reward;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
memberLimits[member].total += reward;
|
|
278
|
-
memberLimits[member].lastReward = uint64(block.timestamp);
|
|
279
|
-
memberLimits[member].lastMonth = curMonth;
|
|
280
|
-
|
|
281
|
-
if (
|
|
282
|
-
memberLimits[member].daily > limits.maxMemberPerDay ||
|
|
283
|
-
memberLimits[member].monthly > limits.maxMemberPerMonth
|
|
284
|
-
) revert OVER_MEMBER_LIMITS(member);
|
|
285
|
-
|
|
286
|
-
return true;
|
|
195
|
+
DirectPaymentsLibrary._claim(globalLimits, limits, memberLimits, settings, _nftId, _data);
|
|
287
196
|
}
|
|
288
197
|
|
|
289
|
-
/**
|
|
290
|
-
* @dev Enforces and updates the global reward limits.
|
|
291
|
-
* @param reward The amount of rewards to enforce and update limits for.
|
|
292
|
-
*/
|
|
293
|
-
function _enforceAndUpdateGlobalLimits(uint128 reward) internal {
|
|
294
|
-
uint64 curMonth = _month();
|
|
295
|
-
|
|
296
|
-
if (globalLimits.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
297
|
-
{
|
|
298
|
-
globalLimits.daily = reward;
|
|
299
|
-
} else {
|
|
300
|
-
globalLimits.daily += reward;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (globalLimits.lastMonth < curMonth) //month switched
|
|
304
|
-
{
|
|
305
|
-
globalLimits.monthly = reward;
|
|
306
|
-
} else {
|
|
307
|
-
globalLimits.monthly += reward;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
globalLimits.total += reward;
|
|
311
|
-
globalLimits.lastReward = uint64(block.timestamp);
|
|
312
|
-
globalLimits.lastMonth = curMonth;
|
|
313
|
-
|
|
314
|
-
if (globalLimits.monthly > limits.maxTotalPerMonth) revert OVER_GLOBAL_LIMITS();
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* @dev Returns the current month.
|
|
319
|
-
* @return month current month as a uint64 value.
|
|
320
|
-
*/
|
|
321
|
-
function _month() internal view returns (uint64 month) {
|
|
322
|
-
return uint64(block.timestamp / (60 * 60 * 24 * 30));
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* @dev Adds a member to the contract.
|
|
327
|
-
* @param member The address of the member to add.
|
|
328
|
-
* @param extraData Additional data to validate the member.
|
|
329
|
-
*/
|
|
330
|
-
|
|
331
198
|
function _addMember(address member, bytes memory extraData) internal returns (bool isMember) {
|
|
332
199
|
if (hasRole(MEMBER_ROLE, member)) return true;
|
|
333
200
|
|
|
@@ -409,7 +276,8 @@ contract DirectPaymentsPool is
|
|
|
409
276
|
* @dev Sets the settings for the pool.
|
|
410
277
|
* @param _settings The new pool settings.
|
|
411
278
|
*/
|
|
412
|
-
function setPoolSettings(PoolSettings memory _settings) public onlyRole(MANAGER_ROLE) {
|
|
279
|
+
function setPoolSettings(PoolSettings memory _settings, uint32 _managerFeeBps) public onlyRole(MANAGER_ROLE) {
|
|
280
|
+
managerFeeBps = _managerFeeBps;
|
|
413
281
|
if (_settings.nftType != settings.nftType) revert NFTTYPE_CHANGED();
|
|
414
282
|
if (_settings.manager == address(0)) revert EMPTY_MANAGER();
|
|
415
283
|
|