@gooddollar/goodcollective-contracts 1.1.0 → 1.3.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/README.md +14 -1
- package/contracts/DirectPayments/DirectPaymentsFactory.sol +23 -15
- package/contracts/DirectPayments/DirectPaymentsLibrary.sol +54 -0
- package/contracts/DirectPayments/DirectPaymentsPool.sol +25 -41
- package/contracts/GoodCollective/GoodCollectiveSuperApp.sol +89 -61
- package/contracts/GoodCollective/IGoodCollectiveSuperApp.sol +12 -0
- package/contracts/Interfaces.sol +25 -0
- package/contracts/UBI/UBIPool.sol +103 -90
- package/contracts/UBI/UBIPoolFactory.sol +24 -10
- package/contracts/test/HelperLibraryTest.sol +16 -0
- package/contracts/utils/HelperLibrary.sol +109 -8
- package/package.json +4 -3
- package/releases/deployment.json +22797 -431
- package/typechain-types/@uniswap/index.ts +0 -2
- package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.ts +56 -9
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool.ts +187 -9
- package/typechain-types/contracts/GoodCollective/GoodCollectiveSuperApp.ts +150 -6
- package/typechain-types/contracts/{UBI/MultiClaimModule.sol/IClaimable.ts → GoodCollective/IGoodCollectiveSuperApp.sol/IGoodCollectiveSuperApp.ts} +24 -23
- package/typechain-types/contracts/GoodCollective/{GoodCollectiveSuperApp.sol → IGoodCollectiveSuperApp.sol}/index.ts +1 -1
- package/typechain-types/contracts/GoodCollective/index.ts +3 -2
- 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} +325 -78
- package/typechain-types/contracts/UBI/UBIPoolFactory.ts +95 -33
- package/typechain-types/contracts/UBI/index.ts +1 -4
- package/typechain-types/contracts/index.ts +4 -0
- package/typechain-types/contracts/test/HelperLibraryTest.ts +147 -0
- package/typechain-types/{@uniswap/v3-periphery/contracts/interfaces → contracts/test}/index.ts +1 -1
- package/typechain-types/contracts/utils/HelperLibrary.ts +46 -4
- package/typechain-types/factories/@uniswap/index.ts +0 -1
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory__factory.ts +25 -2
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool__factory.ts +128 -1
- package/typechain-types/factories/contracts/GoodCollective/GoodCollectiveSuperApp__factory.ts +105 -1
- package/typechain-types/factories/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IGoodCollectiveSuperApp__factory.ts +48 -0
- package/typechain-types/factories/contracts/GoodCollective/{GoodCollectiveSuperApp.sol → IGoodCollectiveSuperApp.sol}/IRegistry__factory.ts +1 -1
- package/typechain-types/factories/contracts/GoodCollective/{GoodCollectiveSuperApp.sol → IGoodCollectiveSuperApp.sol}/index.ts +1 -1
- package/typechain-types/factories/contracts/GoodCollective/index.ts +2 -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 +76 -4
- package/typechain-types/factories/contracts/UBI/UBIPool__factory.ts +2052 -0
- package/typechain-types/factories/contracts/UBI/index.ts +1 -2
- package/typechain-types/factories/contracts/index.ts +2 -0
- package/typechain-types/factories/contracts/test/HelperLibraryTest__factory.ts +154 -0
- package/typechain-types/{@uniswap/v3-periphery → factories/contracts/test}/index.ts +1 -2
- package/typechain-types/factories/contracts/utils/HelperLibrary__factory.ts +31 -1
- package/typechain-types/hardhat.d.ts +18 -36
- package/typechain-types/index.ts +10 -14
- package/contracts/UBI/MultiClaimModule.sol +0 -78
- package/typechain-types/@gooddollar/goodprotocol/contracts/token/FeesFormula.sol/IFeesFormula.ts +0 -115
- package/typechain-types/@gooddollar/goodprotocol/contracts/token/FeesFormula.sol/index.ts +0 -4
- package/typechain-types/@uniswap/v3-periphery/contracts/index.ts +0 -5
- package/typechain-types/@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.ts +0 -369
- package/typechain-types/contracts/GoodCollective/GoodCollectiveSuperApp.sol/GoodCollectiveSuperApp.ts +0 -1000
- package/typechain-types/contracts/UBI/MultiClaimModule.sol/IModule.ts +0 -196
- package/typechain-types/contracts/UBI/MultiClaimModule.sol/MultiClaimModule.ts +0 -242
- package/typechain-types/contracts/UBI/MultiClaimModule.sol/index.ts +0 -6
- package/typechain-types/factories/@gooddollar/goodprotocol/contracts/token/FeesFormula.sol/IFeesFormula__factory.ts +0 -60
- package/typechain-types/factories/@gooddollar/goodprotocol/contracts/token/FeesFormula.sol/index.ts +0 -4
- package/typechain-types/factories/@uniswap/v3-periphery/contracts/index.ts +0 -4
- package/typechain-types/factories/@uniswap/v3-periphery/contracts/interfaces/ISwapRouter__factory.ts +0 -263
- package/typechain-types/factories/@uniswap/v3-periphery/contracts/interfaces/index.ts +0 -4
- package/typechain-types/factories/@uniswap/v3-periphery/index.ts +0 -4
- package/typechain-types/factories/contracts/GoodCollective/GoodCollectiveSuperApp.sol/GoodCollectiveSuperApp__factory.ts +0 -728
- package/typechain-types/factories/contracts/UBI/MultiClaimModule.sol/IClaimable__factory.ts +0 -33
- package/typechain-types/factories/contracts/UBI/MultiClaimModule.sol/IModule__factory.ts +0 -84
- package/typechain-types/factories/contracts/UBI/MultiClaimModule.sol/MultiClaimModule__factory.ts +0 -150
- package/typechain-types/factories/contracts/UBI/MultiClaimModule.sol/index.ts +0 -6
- package/typechain-types/factories/contracts/UBI/UBIPool.sol/UBIPool__factory.ts +0 -1835
- /package/typechain-types/contracts/GoodCollective/{GoodCollectiveSuperApp.sol → IGoodCollectiveSuperApp.sol}/IRegistry.ts +0 -0
package/README.md
CHANGED
|
@@ -1 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Contracts
|
|
2
|
+
|
|
3
|
+
## Structs
|
|
4
|
+
|
|
5
|
+
### Pool Settings
|
|
6
|
+
|
|
7
|
+
- `nftType`: 1, // when you update the settings with setPoolSettings, `nftType` should always match what has been set when creating the pool
|
|
8
|
+
- `uniquenessValidator`: `ethers.constants.AddressZero`,
|
|
9
|
+
- `rewardPerEvent`: `[100, 300]`,
|
|
10
|
+
- `validEvents`: `[1, 2]`, // to be defined
|
|
11
|
+
- `manager`: `<address of the owner/creator of the pool>`,
|
|
12
|
+
- `membersValidator`: `ethers.constants.AddressZero`, // used to only accept certain members (address zero for anyone can join)
|
|
13
|
+
- `rewardToken`: `'0x62B8B11039FcfE5aB0C56E502b1C372A3d2a9c7A'`, // what token will a steward/member receive. currently only supports production G$'s
|
|
14
|
+
- `allowRewardOverride`: `false`,
|
|
@@ -11,7 +11,7 @@ import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
|
|
|
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();
|
|
@@ -98,18 +98,20 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
98
98
|
string memory _projectId,
|
|
99
99
|
string memory _ipfs,
|
|
100
100
|
DirectPaymentsPool.PoolSettings memory _settings,
|
|
101
|
-
DirectPaymentsPool.SafetyLimits memory _limits
|
|
101
|
+
DirectPaymentsPool.SafetyLimits memory _limits,
|
|
102
|
+
uint32 _managerFeeBps
|
|
102
103
|
) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) {
|
|
103
|
-
return _createPool(_projectId, _ipfs, _settings, _limits, true);
|
|
104
|
+
return _createPool(_projectId, _ipfs, _settings, _limits, _managerFeeBps, true);
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
function createPool(
|
|
107
108
|
string memory _projectId,
|
|
108
109
|
string memory _ipfs,
|
|
109
110
|
DirectPaymentsPool.PoolSettings memory _settings,
|
|
110
|
-
DirectPaymentsPool.SafetyLimits memory _limits
|
|
111
|
+
DirectPaymentsPool.SafetyLimits memory _limits,
|
|
112
|
+
uint32 _managerFeeBps
|
|
111
113
|
) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) {
|
|
112
|
-
return _createPool(_projectId, _ipfs, _settings, _limits, false);
|
|
114
|
+
return _createPool(_projectId, _ipfs, _settings, _limits, _managerFeeBps, false);
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
function _createPool(
|
|
@@ -117,17 +119,15 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
117
119
|
string memory _ipfs,
|
|
118
120
|
DirectPaymentsPool.PoolSettings memory _settings,
|
|
119
121
|
DirectPaymentsPool.SafetyLimits memory _limits,
|
|
122
|
+
uint32 _managerFeeBps,
|
|
120
123
|
bool useBeacon
|
|
121
124
|
) internal returns (DirectPaymentsPool pool) {
|
|
122
125
|
//TODO: add check if msg.sender is whitelisted
|
|
123
126
|
|
|
124
127
|
_settings.nftType = nextNftType;
|
|
125
|
-
bytes memory initCall = abi.
|
|
126
|
-
DirectPaymentsPool.initialize
|
|
127
|
-
nft,
|
|
128
|
-
_settings,
|
|
129
|
-
_limits,
|
|
130
|
-
address(this)
|
|
128
|
+
bytes memory initCall = abi.encodeCall(
|
|
129
|
+
DirectPaymentsPool.initialize,
|
|
130
|
+
(nft, _settings, _limits, _managerFeeBps, this)
|
|
131
131
|
);
|
|
132
132
|
|
|
133
133
|
if (useBeacon) {
|
|
@@ -136,9 +136,7 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
136
136
|
pool = DirectPaymentsPool(address(new ERC1967Proxy(impl.implementation(), initCall)));
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
nft.grantRole(nft.getManagerRole(nextNftType), _settings.manager);
|
|
140
139
|
nft.grantRole(nft.getManagerRole(nextNftType), address(pool));
|
|
141
|
-
pool.grantRole(pool.MINTER_ROLE(), _settings.manager);
|
|
142
140
|
|
|
143
141
|
//access control to project is determinted by the first pool access control rules
|
|
144
142
|
if (address(projectIdToControlPool[keccak256(bytes(_projectId))]) == address(0))
|
|
@@ -146,6 +144,7 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
146
144
|
registry[address(pool)].ipfs = _ipfs;
|
|
147
145
|
registry[address(pool)].projectId = _projectId;
|
|
148
146
|
|
|
147
|
+
pool.grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
149
148
|
pool.renounceRole(DEFAULT_ADMIN_ROLE, address(this));
|
|
150
149
|
pools.push(address(pool));
|
|
151
150
|
|
|
@@ -174,7 +173,16 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
174
173
|
feeRecipient = _feeRecipient;
|
|
175
174
|
}
|
|
176
175
|
|
|
177
|
-
function addMember(address
|
|
178
|
-
memberPools[
|
|
176
|
+
function addMember(address member) external onlyPool {
|
|
177
|
+
memberPools[member].push(msg.sender);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function removeMember(address member) external onlyPool {
|
|
181
|
+
for (uint i = 0; i < memberPools[member].length; i++) {
|
|
182
|
+
if (memberPools[member][i] == msg.sender) {
|
|
183
|
+
memberPools[member][i] = memberPools[member][memberPools[member].length - 1];
|
|
184
|
+
memberPools[member].pop();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
179
187
|
}
|
|
180
188
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity >=0.8.0;
|
|
3
|
+
|
|
4
|
+
import "./DirectPaymentsPool.sol";
|
|
5
|
+
|
|
6
|
+
library DirectPayemntsLibrary {
|
|
7
|
+
function _updateMemberLimits(
|
|
8
|
+
DirectPaymentsPool.LimitsData storage memberStats,
|
|
9
|
+
uint128 reward,
|
|
10
|
+
uint64 curMonth
|
|
11
|
+
) internal {
|
|
12
|
+
if (memberStats.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
13
|
+
{
|
|
14
|
+
memberStats.daily = reward;
|
|
15
|
+
} else {
|
|
16
|
+
memberStats.daily += reward;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (memberStats.lastMonth < curMonth) //month switched
|
|
20
|
+
{
|
|
21
|
+
memberStats.monthly = reward;
|
|
22
|
+
} else {
|
|
23
|
+
memberStats.monthly += reward;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
memberStats.total += reward;
|
|
27
|
+
memberStats.lastReward = uint64(block.timestamp);
|
|
28
|
+
memberStats.lastMonth = curMonth;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function _updateGlobalLimits(
|
|
32
|
+
DirectPaymentsPool.LimitsData storage globalLimits,
|
|
33
|
+
uint128 reward,
|
|
34
|
+
uint64 curMonth
|
|
35
|
+
) internal {
|
|
36
|
+
if (globalLimits.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
37
|
+
{
|
|
38
|
+
globalLimits.daily = reward;
|
|
39
|
+
} else {
|
|
40
|
+
globalLimits.daily += reward;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (globalLimits.lastMonth < curMonth) //month switched
|
|
44
|
+
{
|
|
45
|
+
globalLimits.monthly = reward;
|
|
46
|
+
} else {
|
|
47
|
+
globalLimits.monthly += reward;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
globalLimits.total += reward;
|
|
51
|
+
globalLimits.lastReward = uint64(block.timestamp);
|
|
52
|
+
globalLimits.lastMonth = curMonth;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -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 { DirectPayemntsLibrary } from "./DirectPaymentsLibrary.sol";
|
|
12
13
|
import "../GoodCollective/GoodCollectiveSuperApp.sol";
|
|
13
14
|
|
|
14
15
|
interface IMembersValidator {
|
|
@@ -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,14 +141,18 @@ 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;
|
|
143
|
-
|
|
144
|
-
_setupRole(DEFAULT_ADMIN_ROLE,
|
|
151
|
+
managerFeeBps = _managerFeeBps;
|
|
152
|
+
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender); // when using factory this gives factory role which then set role to the real msg.sender
|
|
153
|
+
_setupRole(MANAGER_ROLE, _settings.manager);
|
|
154
|
+
_setupRole(MINTER_ROLE, _settings.manager);
|
|
155
|
+
|
|
145
156
|
setSuperToken(ISuperToken(address(settings.rewardToken)));
|
|
146
157
|
}
|
|
147
158
|
|
|
@@ -257,24 +268,7 @@ contract DirectPaymentsPool is
|
|
|
257
268
|
return false;
|
|
258
269
|
}
|
|
259
270
|
|
|
260
|
-
|
|
261
|
-
if (memberLimits[member].lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
262
|
-
{
|
|
263
|
-
memberLimits[member].daily = reward;
|
|
264
|
-
} else {
|
|
265
|
-
memberLimits[member].daily += reward;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (memberLimits[member].lastMonth < curMonth) //month switched
|
|
269
|
-
{
|
|
270
|
-
memberLimits[member].monthly = reward;
|
|
271
|
-
} else {
|
|
272
|
-
memberLimits[member].monthly += reward;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
memberLimits[member].total += reward;
|
|
276
|
-
memberLimits[member].lastReward = uint64(block.timestamp);
|
|
277
|
-
memberLimits[member].lastMonth = curMonth;
|
|
271
|
+
DirectPayemntsLibrary._updateMemberLimits(memberLimits[member], reward, _month());
|
|
278
272
|
|
|
279
273
|
if (
|
|
280
274
|
memberLimits[member].daily > limits.maxMemberPerDay ||
|
|
@@ -289,25 +283,7 @@ contract DirectPaymentsPool is
|
|
|
289
283
|
* @param reward The amount of rewards to enforce and update limits for.
|
|
290
284
|
*/
|
|
291
285
|
function _enforceAndUpdateGlobalLimits(uint128 reward) internal {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (globalLimits.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
295
|
-
{
|
|
296
|
-
globalLimits.daily = reward;
|
|
297
|
-
} else {
|
|
298
|
-
globalLimits.daily += reward;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (globalLimits.lastMonth < curMonth) //month switched
|
|
302
|
-
{
|
|
303
|
-
globalLimits.monthly = reward;
|
|
304
|
-
} else {
|
|
305
|
-
globalLimits.monthly += reward;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
globalLimits.total += reward;
|
|
309
|
-
globalLimits.lastReward = uint64(block.timestamp);
|
|
310
|
-
globalLimits.lastMonth = curMonth;
|
|
286
|
+
DirectPayemntsLibrary._updateGlobalLimits(globalLimits, reward, _month());
|
|
311
287
|
|
|
312
288
|
if (globalLimits.monthly > limits.maxTotalPerMonth) revert OVER_GLOBAL_LIMITS();
|
|
313
289
|
}
|
|
@@ -352,6 +328,13 @@ contract DirectPaymentsPool is
|
|
|
352
328
|
super._grantRole(role, account);
|
|
353
329
|
}
|
|
354
330
|
|
|
331
|
+
function _revokeRole(bytes32 role, address account) internal virtual override {
|
|
332
|
+
if (role == MEMBER_ROLE) {
|
|
333
|
+
registry.removeMember(account);
|
|
334
|
+
}
|
|
335
|
+
super._revokeRole(role, account);
|
|
336
|
+
}
|
|
337
|
+
|
|
355
338
|
function mintNFT(address _to, ProvableNFT.NFTData memory _nftData, bool withClaim) external onlyRole(MINTER_ROLE) {
|
|
356
339
|
uint nftId = nft.mintPermissioned(_to, _nftData, true, "");
|
|
357
340
|
if (withClaim) {
|
|
@@ -391,7 +374,7 @@ contract DirectPaymentsPool is
|
|
|
391
374
|
* @dev Sets the safety limits for the pool.
|
|
392
375
|
* @param _limits The new safety limits.
|
|
393
376
|
*/
|
|
394
|
-
function setPoolLimits(SafetyLimits memory _limits) public onlyRole(
|
|
377
|
+
function setPoolLimits(SafetyLimits memory _limits) public onlyRole(MANAGER_ROLE) {
|
|
395
378
|
limits = _limits;
|
|
396
379
|
emit PoolLimitsChanged(_limits);
|
|
397
380
|
}
|
|
@@ -400,7 +383,8 @@ contract DirectPaymentsPool is
|
|
|
400
383
|
* @dev Sets the settings for the pool.
|
|
401
384
|
* @param _settings The new pool settings.
|
|
402
385
|
*/
|
|
403
|
-
function setPoolSettings(PoolSettings memory _settings) public onlyRole(
|
|
386
|
+
function setPoolSettings(PoolSettings memory _settings, uint32 _managerFeeBps) public onlyRole(MANAGER_ROLE) {
|
|
387
|
+
managerFeeBps = _managerFeeBps;
|
|
404
388
|
if (_settings.nftType != settings.nftType) revert NFTTYPE_CHANGED();
|
|
405
389
|
if (_settings.manager == address(0)) revert EMPTY_MANAGER();
|
|
406
390
|
|
|
@@ -16,12 +16,6 @@ import "../utils/HelperLibrary.sol";
|
|
|
16
16
|
|
|
17
17
|
// import "hardhat/console.sol";
|
|
18
18
|
|
|
19
|
-
interface IRegistry {
|
|
20
|
-
function feeRecipient() external view returns (address);
|
|
21
|
-
|
|
22
|
-
function feeBps() external view returns (uint32);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
19
|
abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
26
20
|
int96 public constant MIN_FLOW_RATE = 386e9;
|
|
27
21
|
|
|
@@ -74,7 +68,7 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
74
68
|
|
|
75
69
|
IGoodCollectiveSuperApp.Stats public stats;
|
|
76
70
|
|
|
77
|
-
uint256[
|
|
71
|
+
uint256[45] private _reserved;
|
|
78
72
|
|
|
79
73
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
80
74
|
constructor(ISuperfluid _host, IV3SwapRouter _swapRouter) SuperAppBaseFlow(_host) {
|
|
@@ -84,6 +78,8 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
84
78
|
|
|
85
79
|
function getRegistry() public view virtual returns (IRegistry);
|
|
86
80
|
|
|
81
|
+
function getManagerFee() public view virtual returns (address admin, uint32 feeBps);
|
|
82
|
+
|
|
87
83
|
/**
|
|
88
84
|
* @dev Sets the address of the super token and registers the app with the host
|
|
89
85
|
* @param _superToken The address of the super token contract
|
|
@@ -122,7 +118,15 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
122
118
|
function getRealtimeStats()
|
|
123
119
|
public
|
|
124
120
|
view
|
|
125
|
-
returns (
|
|
121
|
+
returns (
|
|
122
|
+
uint256 netIncome,
|
|
123
|
+
uint256 totalFees,
|
|
124
|
+
uint256 protocolFees,
|
|
125
|
+
uint256 managerFees,
|
|
126
|
+
int96 incomeFlowRate,
|
|
127
|
+
int96 feeRate,
|
|
128
|
+
int96 managerFeeRate
|
|
129
|
+
)
|
|
126
130
|
{
|
|
127
131
|
return HelperLibrary.getRealtimeStats(stats, superToken);
|
|
128
132
|
}
|
|
@@ -166,6 +170,28 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
166
170
|
return _ctx;
|
|
167
171
|
}
|
|
168
172
|
|
|
173
|
+
/**
|
|
174
|
+
* @dev allow single contribution. user needs to approve tokens first. can be used in superfluid batch actions.
|
|
175
|
+
* @param _sender The address of the sender who is contributing tokens.
|
|
176
|
+
* @param _customData The SwapData struct containing information about the swap
|
|
177
|
+
* @param _ctx The context of the transaction for superfluid in case this was used in superfluid batch. otherwise can be empty.
|
|
178
|
+
* @return Returns the context of the transaction.
|
|
179
|
+
*/
|
|
180
|
+
function supportWithSwap(
|
|
181
|
+
address _sender,
|
|
182
|
+
HelperLibrary.SwapData memory _customData,
|
|
183
|
+
bytes memory _ctx
|
|
184
|
+
) external onlyHostOrSender(_sender) returns (bytes memory) {
|
|
185
|
+
uint256 balance = superToken.balanceOf(address(this));
|
|
186
|
+
HelperLibrary.handleSwap(swapRouter, _customData, address(superToken), _sender, address(this));
|
|
187
|
+
uint256 amountReceived = superToken.balanceOf(address(this)) - balance;
|
|
188
|
+
if (amountReceived == 0) revert ZERO_AMOUNT();
|
|
189
|
+
|
|
190
|
+
// Update the contribution amount for the sender in the supporters mapping
|
|
191
|
+
_updateSupporter(_sender, int256(amountReceived), 0, ""); //we pass empty ctx since this is not a flow but a single donation
|
|
192
|
+
return _ctx;
|
|
193
|
+
}
|
|
194
|
+
|
|
169
195
|
/**
|
|
170
196
|
* @dev Handles the swap of tokens using the SwapData struct
|
|
171
197
|
* @param _customData The SwapData struct containing information about the swap
|
|
@@ -235,6 +261,7 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
235
261
|
bytes calldata _ctx
|
|
236
262
|
) internal virtual override returns (bytes memory /*newCtx*/) {
|
|
237
263
|
// Update the supporter's information
|
|
264
|
+
|
|
238
265
|
return _updateSupporter(_sender, _previousFlowRate, _lastUpdated, _ctx);
|
|
239
266
|
}
|
|
240
267
|
|
|
@@ -253,10 +280,18 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
253
280
|
) internal returns (bytes memory newCtx) {
|
|
254
281
|
newCtx = _ctx;
|
|
255
282
|
bool _isFlow = _ctx.length > 0;
|
|
256
|
-
|
|
283
|
+
(address feeRecipient, uint32 feeBps) = getManagerFee();
|
|
284
|
+
HelperLibrary.updateStats(
|
|
285
|
+
stats,
|
|
286
|
+
superToken,
|
|
287
|
+
getRegistry(),
|
|
288
|
+
feeBps,
|
|
289
|
+
_isFlow ? 0 : uint256(_previousFlowRateOrAmount)
|
|
290
|
+
);
|
|
257
291
|
// Get the current flow rate for the supporter
|
|
258
292
|
int96 flowRate = superToken.getFlowRate(_supporter, address(this));
|
|
259
293
|
uint256 prevContribution = supporters[_supporter].contribution;
|
|
294
|
+
|
|
260
295
|
if (_isFlow) {
|
|
261
296
|
//enforce minimal flow rate
|
|
262
297
|
if (flowRate > 0 && flowRate < MIN_FLOW_RATE) revert MIN_FLOWRATE(flowRate);
|
|
@@ -264,14 +299,54 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
264
299
|
supporters[_supporter].lastUpdated = uint128(block.timestamp);
|
|
265
300
|
supporters[_supporter].flowRate = flowRate;
|
|
266
301
|
supporters[_supporter].contribution +=
|
|
267
|
-
|
|
302
|
+
uint256(_previousFlowRateOrAmount) *
|
|
268
303
|
(block.timestamp - _lastUpdated);
|
|
269
|
-
|
|
304
|
+
|
|
305
|
+
// address feeRecipient;
|
|
306
|
+
// uint32 feeBps;
|
|
307
|
+
if (address(getRegistry()) != address(0)) {
|
|
308
|
+
feeRecipient = getRegistry().feeRecipient();
|
|
309
|
+
feeBps = getRegistry().feeBps();
|
|
310
|
+
// console.log("taking fees %s %s", feeRecipient, feeBps);
|
|
311
|
+
|
|
312
|
+
newCtx = HelperLibrary.takeFeeFlow(
|
|
313
|
+
cfaV1,
|
|
314
|
+
superToken,
|
|
315
|
+
stats.lastFeeRecipient,
|
|
316
|
+
feeRecipient,
|
|
317
|
+
feeBps,
|
|
318
|
+
flowRate - int96(_previousFlowRateOrAmount), // we use diff, because manager takes fee from many streams not just this one
|
|
319
|
+
newCtx
|
|
320
|
+
);
|
|
321
|
+
stats.lastFeeRecipient = feeRecipient;
|
|
322
|
+
}
|
|
323
|
+
// console.log("protocol fee stream ok");
|
|
324
|
+
(feeRecipient, feeBps) = getManagerFee();
|
|
325
|
+
|
|
326
|
+
newCtx = HelperLibrary.takeFeeFlow(
|
|
327
|
+
cfaV1,
|
|
328
|
+
superToken,
|
|
329
|
+
stats.lastManagerFeeRecipient,
|
|
330
|
+
feeRecipient,
|
|
331
|
+
feeBps,
|
|
332
|
+
flowRate - int96(_previousFlowRateOrAmount), // we use diff, because manager takes fee from many streams not just this one
|
|
333
|
+
newCtx
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
stats.lastManagerFeeRecipient = feeRecipient;
|
|
337
|
+
// console.log("admin fee stream ok");
|
|
270
338
|
// we update the last rate after we do all changes to our own flows
|
|
271
339
|
stats.lastIncomeRate = superToken.getNetFlowRate(address(this));
|
|
272
340
|
} else {
|
|
341
|
+
if (address(getRegistry()) != address(0)) {
|
|
342
|
+
feeRecipient = getRegistry().feeRecipient();
|
|
343
|
+
feeBps = getRegistry().feeBps();
|
|
344
|
+
_takeFeeSingle(feeRecipient, feeBps, uint256(_previousFlowRateOrAmount));
|
|
345
|
+
}
|
|
346
|
+
(feeRecipient, feeBps) = getManagerFee();
|
|
347
|
+
_takeFeeSingle(feeRecipient, feeBps, uint256(_previousFlowRateOrAmount));
|
|
348
|
+
|
|
273
349
|
supporters[_supporter].contribution += uint256(_previousFlowRateOrAmount);
|
|
274
|
-
_takeFeeSingle(uint256(_previousFlowRateOrAmount));
|
|
275
350
|
}
|
|
276
351
|
|
|
277
352
|
emit SupporterUpdated(
|
|
@@ -284,57 +359,10 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
284
359
|
);
|
|
285
360
|
}
|
|
286
361
|
|
|
287
|
-
|
|
288
|
-
function _updateStats(uint256 _amount) internal {
|
|
289
|
-
//use last rate before the current possible rate update
|
|
290
|
-
stats.netIncome += uint96(stats.lastIncomeRate) * (block.timestamp - stats.lastUpdate);
|
|
291
|
-
uint feeBps;
|
|
292
|
-
if (address(getRegistry()) != address(0)) {
|
|
293
|
-
feeBps = getRegistry().feeBps();
|
|
294
|
-
//fees sent to last recipient, the flowRate to recipient still wasnt updated.
|
|
295
|
-
stats.totalFees +=
|
|
296
|
-
uint96(superToken.getFlowRate(address(this), stats.lastFeeRecipient)) *
|
|
297
|
-
(block.timestamp - stats.lastUpdate);
|
|
298
|
-
}
|
|
299
|
-
if (_amount > 0) {
|
|
300
|
-
stats.netIncome += (_amount * (10000 - feeBps)) / 10000;
|
|
301
|
-
stats.totalFees += (_amount * feeBps) / 10000;
|
|
302
|
-
}
|
|
303
|
-
stats.lastUpdate = block.timestamp;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function _takeFeeFlow(int96 _diffRate, bytes memory _ctx) internal returns (bytes memory newCtx) {
|
|
307
|
-
newCtx = _ctx;
|
|
308
|
-
if (address(getRegistry()) == address(0)) return newCtx;
|
|
309
|
-
address recipient = getRegistry().feeRecipient();
|
|
310
|
-
int96 curFeeRate = superToken.getFlowRate(address(this), stats.lastFeeRecipient);
|
|
311
|
-
bool newRecipient;
|
|
312
|
-
if (recipient != stats.lastFeeRecipient) {
|
|
313
|
-
newRecipient = true;
|
|
314
|
-
if (stats.lastFeeRecipient != address(0)) {
|
|
315
|
-
//delete old recipient flow
|
|
316
|
-
if (curFeeRate > 0)
|
|
317
|
-
newCtx = cfaV1.deleteFlowWithCtx(newCtx, address(this), stats.lastFeeRecipient, superToken); //passing in the ctx which is sent to the callback here
|
|
318
|
-
}
|
|
319
|
-
stats.lastFeeRecipient = recipient;
|
|
320
|
-
}
|
|
321
|
-
if (recipient == address(0)) return newCtx;
|
|
322
|
-
|
|
323
|
-
int96 feeRateChange = (_diffRate * int32(getRegistry().feeBps())) / 10000;
|
|
324
|
-
int96 newFeeRate = curFeeRate + feeRateChange;
|
|
325
|
-
if (newFeeRate <= 0 && newRecipient == false) {
|
|
326
|
-
newCtx = cfaV1.deleteFlowWithCtx(newCtx, address(this), recipient, superToken); //passing in the ctx which is sent to the callback here
|
|
327
|
-
} else if (curFeeRate > 0 && newRecipient == false) {
|
|
328
|
-
newCtx = cfaV1.updateFlowWithCtx(newCtx, recipient, superToken, newFeeRate); //passing in the ctx which is sent to the callback here
|
|
329
|
-
} else if (newFeeRate > 0) newCtx = cfaV1.createFlowWithCtx(newCtx, recipient, superToken, newFeeRate); //passing in the ctx which is sent to the callback here
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function _takeFeeSingle(uint256 _amount) internal {
|
|
333
|
-
if (address(getRegistry()) == address(0)) return;
|
|
334
|
-
address recipient = getRegistry().feeRecipient();
|
|
362
|
+
function _takeFeeSingle(address recipient, uint32 feeBps, uint256 _amount) internal {
|
|
335
363
|
if (recipient == address(0)) return;
|
|
336
364
|
|
|
337
|
-
uint256 fee = (_amount *
|
|
365
|
+
uint256 fee = (_amount * feeBps) / 10000;
|
|
338
366
|
TransferHelper.safeTransfer(address(superToken), recipient, fee);
|
|
339
367
|
}
|
|
340
368
|
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity >=0.8.0;
|
|
3
3
|
|
|
4
|
+
interface IRegistry {
|
|
5
|
+
function feeRecipient() external view returns (address);
|
|
6
|
+
|
|
7
|
+
function feeBps() external view returns (uint32);
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
interface IGoodCollectiveSuperApp {
|
|
5
11
|
struct Stats {
|
|
6
12
|
uint256 netIncome; //without fees
|
|
@@ -8,5 +14,11 @@ interface IGoodCollectiveSuperApp {
|
|
|
8
14
|
uint256 lastUpdate;
|
|
9
15
|
address lastFeeRecipient;
|
|
10
16
|
int96 lastIncomeRate;
|
|
17
|
+
address lastManagerFeeRecipient;
|
|
18
|
+
uint256 protocolFees;
|
|
19
|
+
uint256 managerFees;
|
|
20
|
+
// adding fields MUST update GoodCollectiveSuperApp storage layout
|
|
11
21
|
}
|
|
22
|
+
|
|
23
|
+
function getAdminFee() external view returns (address admin, uint32 feeBps);
|
|
12
24
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
|
6
|
+
|
|
7
|
+
interface IMembersValidator {
|
|
8
|
+
function isMemberValid(
|
|
9
|
+
address pool,
|
|
10
|
+
address operator,
|
|
11
|
+
address member,
|
|
12
|
+
bytes memory extraData
|
|
13
|
+
) external returns (bool);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface IIdentityV2 {
|
|
17
|
+
function getWhitelistedRoot(address member) external view returns (address);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
struct PoolSettings {
|
|
21
|
+
address manager;
|
|
22
|
+
IMembersValidator membersValidator;
|
|
23
|
+
IIdentityV2 uniquenessValidator;
|
|
24
|
+
IERC20Upgradeable rewardToken;
|
|
25
|
+
}
|