@gooddollar/goodcollective-contracts 1.0.4 → 1.0.6-beta.0b8171a
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 +40 -12
- package/contracts/DirectPayments/DirectPaymentsPool.sol +92 -37
- package/contracts/DirectPayments/ProvableNFT.sol +17 -11
- package/contracts/GoodCollective/GoodCollectiveSuperApp.sol +9 -66
- package/contracts/GoodCollective/IGoodCollectiveSuperApp.sol +12 -0
- package/contracts/utils/HelperLibrary.sol +83 -0
- package/package.json +13 -7
- package/releases/deployment.json +11286 -1911
- package/typechain-types/@gooddollar/goodprotocol/contracts/token/IFeesFormula.ts +115 -0
- package/typechain-types/@gooddollar/goodprotocol/contracts/token/index.ts +1 -0
- package/typechain-types/@openzeppelin/contracts/access/Ownable.ts +176 -0
- package/typechain-types/@openzeppelin/contracts/access/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts/index.ts +2 -0
- package/typechain-types/@openzeppelin/contracts/proxy/beacon/BeaconProxy.ts +115 -0
- package/typechain-types/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.ts +247 -0
- package/typechain-types/@openzeppelin/contracts/proxy/beacon/index.ts +2 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.ts +29 -13
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool.ts +244 -197
- package/typechain-types/contracts/DirectPayments/ProvableNFT.ts +32 -3
- package/typechain-types/contracts/GoodCollective/GoodCollectiveSuperApp.ts +7 -7
- package/typechain-types/contracts/utils/HelperLibrary.ts +154 -0
- package/typechain-types/contracts/utils/index.ts +1 -0
- package/typechain-types/factories/@gooddollar/goodprotocol/contracts/token/IFeesFormula__factory.ts +60 -0
- package/typechain-types/factories/@gooddollar/goodprotocol/contracts/token/index.ts +1 -0
- package/typechain-types/factories/@openzeppelin/contracts/access/Ownable__factory.ts +78 -0
- package/typechain-types/factories/@openzeppelin/contracts/access/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts/index.ts +1 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/beacon/BeaconProxy__factory.ts +143 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon__factory.ts +170 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/beacon/index.ts +2 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory__factory.ts +85 -4
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool__factory.ts +298 -115
- package/typechain-types/factories/contracts/DirectPayments/ProvableNFT__factory.ts +56 -1
- package/typechain-types/factories/contracts/GoodCollective/GoodCollectiveSuperApp__factory.ts +1 -1
- package/typechain-types/factories/contracts/utils/HelperLibrary__factory.ts +129 -0
- package/typechain-types/factories/contracts/utils/index.ts +1 -0
- package/typechain-types/hardhat.d.ts +45 -0
- package/typechain-types/index.ts +8 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/INameService.ts +0 -102
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/INameService__factory.ts +0 -45
|
@@ -5,6 +5,9 @@ pragma solidity >=0.8.0;
|
|
|
5
5
|
import "./DirectPaymentsPool.sol";
|
|
6
6
|
import "./ProvableNFT.sol";
|
|
7
7
|
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
|
8
|
+
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
|
|
9
|
+
import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
|
|
10
|
+
|
|
8
11
|
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
9
12
|
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
10
13
|
|
|
@@ -13,7 +16,15 @@ import "hardhat/console.sol";
|
|
|
13
16
|
contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
14
17
|
error NOT_PROJECT_OWNER();
|
|
15
18
|
|
|
16
|
-
event PoolCreated(
|
|
19
|
+
event PoolCreated(
|
|
20
|
+
address indexed pool,
|
|
21
|
+
string indexed projectId,
|
|
22
|
+
string ipfs,
|
|
23
|
+
uint32 indexed nftType,
|
|
24
|
+
DirectPaymentsPool.PoolSettings poolSettings,
|
|
25
|
+
DirectPaymentsPool.SafetyLimits poolLimits
|
|
26
|
+
);
|
|
27
|
+
|
|
17
28
|
event PoolDetailsChanged(address indexed pool, string ipfs);
|
|
18
29
|
event PoolVerifiedChanged(address indexed pool, bool isVerified);
|
|
19
30
|
event UpdatedImpl(address indexed impl);
|
|
@@ -24,7 +35,7 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
24
35
|
string projectId;
|
|
25
36
|
}
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
UpgradeableBeacon public impl;
|
|
28
39
|
ProvableNFT public nft;
|
|
29
40
|
uint32 public nextNftType;
|
|
30
41
|
|
|
@@ -60,18 +71,16 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
60
71
|
function initialize(
|
|
61
72
|
address _owner,
|
|
62
73
|
address _dpimpl,
|
|
63
|
-
|
|
74
|
+
ProvableNFT _nft,
|
|
64
75
|
address _feeRecipient,
|
|
65
76
|
uint32 _feeBps
|
|
66
77
|
) external initializer {
|
|
67
78
|
nextNftType = 1;
|
|
68
|
-
impl = _dpimpl;
|
|
69
|
-
|
|
70
|
-
nft = ProvableNFT(address(new ERC1967Proxy(_nftimpl, initCall)));
|
|
79
|
+
impl = new UpgradeableBeacon(_dpimpl);
|
|
80
|
+
nft = _nft;
|
|
71
81
|
feeRecipient = _feeRecipient;
|
|
72
82
|
feeBps = _feeBps;
|
|
73
83
|
|
|
74
|
-
nft.grantRole(DEFAULT_ADMIN_ROLE, _owner);
|
|
75
84
|
_setupRole(DEFAULT_ADMIN_ROLE, _owner);
|
|
76
85
|
}
|
|
77
86
|
|
|
@@ -81,7 +90,9 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
81
90
|
string memory _ipfs,
|
|
82
91
|
DirectPaymentsPool.PoolSettings memory _settings,
|
|
83
92
|
DirectPaymentsPool.SafetyLimits memory _limits
|
|
84
|
-
) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) {
|
|
93
|
+
) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) {
|
|
94
|
+
return _createPool(_projectId, _ipfs, _settings, _limits, true);
|
|
95
|
+
}
|
|
85
96
|
|
|
86
97
|
function createPool(
|
|
87
98
|
string memory _projectId,
|
|
@@ -89,6 +100,16 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
89
100
|
DirectPaymentsPool.PoolSettings memory _settings,
|
|
90
101
|
DirectPaymentsPool.SafetyLimits memory _limits
|
|
91
102
|
) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) {
|
|
103
|
+
return _createPool(_projectId, _ipfs, _settings, _limits, false);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function _createPool(
|
|
107
|
+
string memory _projectId,
|
|
108
|
+
string memory _ipfs,
|
|
109
|
+
DirectPaymentsPool.PoolSettings memory _settings,
|
|
110
|
+
DirectPaymentsPool.SafetyLimits memory _limits,
|
|
111
|
+
bool useBeacon
|
|
112
|
+
) internal returns (DirectPaymentsPool pool) {
|
|
92
113
|
//TODO: add check if msg.sender is whitelisted
|
|
93
114
|
|
|
94
115
|
_settings.nftType = nextNftType;
|
|
@@ -99,18 +120,25 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
99
120
|
_limits,
|
|
100
121
|
address(this)
|
|
101
122
|
);
|
|
102
|
-
|
|
123
|
+
|
|
124
|
+
if (useBeacon) {
|
|
125
|
+
pool = DirectPaymentsPool(address(new BeaconProxy(address(impl), initCall)));
|
|
126
|
+
} else {
|
|
127
|
+
pool = DirectPaymentsPool(address(new ERC1967Proxy(impl.implementation(), initCall)));
|
|
128
|
+
}
|
|
103
129
|
|
|
104
130
|
nft.grantRole(nft.getManagerRole(nextNftType), _settings.manager);
|
|
105
131
|
nft.grantRole(nft.getManagerRole(nextNftType), address(pool));
|
|
106
132
|
pool.grantRole(pool.MINTER_ROLE(), _settings.manager);
|
|
107
133
|
|
|
108
|
-
|
|
134
|
+
//access control to project is determinted by the first pool access control rules
|
|
135
|
+
if (address(projectIdToControlPool[keccak256(bytes(_projectId))]) == address(0))
|
|
136
|
+
projectIdToControlPool[keccak256(bytes(_projectId))] = pool;
|
|
109
137
|
registry[address(pool)].ipfs = _ipfs;
|
|
110
138
|
registry[address(pool)].projectId = _projectId;
|
|
111
139
|
|
|
112
140
|
pool.renounceRole(DEFAULT_ADMIN_ROLE, address(this));
|
|
113
|
-
emit PoolCreated(address(pool), _projectId, _ipfs, nextNftType);
|
|
141
|
+
emit PoolCreated(address(pool), _projectId, _ipfs, nextNftType, _settings, _limits);
|
|
114
142
|
|
|
115
143
|
nextNftType++;
|
|
116
144
|
}
|
|
@@ -126,7 +154,7 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
|
126
154
|
}
|
|
127
155
|
|
|
128
156
|
function updateImpl(address _impl) external onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
129
|
-
impl
|
|
157
|
+
impl.upgradeTo(_impl);
|
|
130
158
|
emit UpdatedImpl(_impl);
|
|
131
159
|
}
|
|
132
160
|
|
|
@@ -41,22 +41,39 @@ contract DirectPaymentsPool is
|
|
|
41
41
|
error NOT_MANAGER();
|
|
42
42
|
error ALREADY_CLAIMED(uint256);
|
|
43
43
|
error NFT_MISSING(uint256);
|
|
44
|
-
error NOT_MEMBER(address);
|
|
45
|
-
error NOT_WHITELISTED(address);
|
|
46
44
|
error OVER_MEMBER_LIMITS(address);
|
|
47
45
|
error OVER_GLOBAL_LIMITS();
|
|
48
46
|
error UNSUPPORTED_NFT();
|
|
49
47
|
error NO_BALANCE();
|
|
48
|
+
error NFTTYPE_CHANGED();
|
|
49
|
+
error EMPTY_MANAGER();
|
|
50
50
|
|
|
51
51
|
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
|
|
52
|
+
bytes32 public constant MEMBER_ROLE = keccak256("MEMBER_ROLE");
|
|
52
53
|
bytes32 public constant MINTER_ROLE = keccak256("MINTER");
|
|
53
54
|
|
|
55
|
+
event PoolCreated(
|
|
56
|
+
address indexed pool,
|
|
57
|
+
string indexed projectId,
|
|
58
|
+
string ipfs,
|
|
59
|
+
uint32 indexed nftType,
|
|
60
|
+
DirectPaymentsPool.PoolSettings poolSettings,
|
|
61
|
+
DirectPaymentsPool.SafetyLimits poolLimits
|
|
62
|
+
);
|
|
63
|
+
|
|
54
64
|
event PoolSettingsChanged(PoolSettings settings);
|
|
55
65
|
event PoolLimitsChanged(SafetyLimits limits);
|
|
56
|
-
event
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
event EventRewardClaimed(
|
|
67
|
+
uint256 indexed tokenId,
|
|
68
|
+
uint16 eventType,
|
|
69
|
+
uint32 eventTimestamp,
|
|
70
|
+
uint256 eventQuantity,
|
|
71
|
+
string eventUri,
|
|
72
|
+
address[] contributers,
|
|
73
|
+
uint256 rewardPerContributer
|
|
74
|
+
);
|
|
59
75
|
event NFTClaimed(uint256 indexed tokenId, uint256 totalRewards);
|
|
76
|
+
event NOT_MEMBER_OR_WHITELISTED(address contributer);
|
|
60
77
|
|
|
61
78
|
// Define functions
|
|
62
79
|
struct PoolSettings {
|
|
@@ -67,6 +84,7 @@ contract DirectPaymentsPool is
|
|
|
67
84
|
IMembersValidator membersValidator;
|
|
68
85
|
IIdentityV2 uniquenessValidator;
|
|
69
86
|
IERC20Upgradeable rewardToken;
|
|
87
|
+
bool allowRewardOverride;
|
|
70
88
|
}
|
|
71
89
|
|
|
72
90
|
struct SafetyLimits {
|
|
@@ -88,7 +106,7 @@ contract DirectPaymentsPool is
|
|
|
88
106
|
ProvableNFT public nft;
|
|
89
107
|
|
|
90
108
|
mapping(uint256 => bool) public claimedNfts;
|
|
91
|
-
mapping(address => bool)
|
|
109
|
+
mapping(address => bool) private members_unused; // using access control instead
|
|
92
110
|
mapping(address => LimitsData) public memberLimits;
|
|
93
111
|
LimitsData public globalLimits;
|
|
94
112
|
DirectPaymentsFactory public registry;
|
|
@@ -100,7 +118,7 @@ contract DirectPaymentsPool is
|
|
|
100
118
|
* @dev Authorizes an upgrade for the implementation contract.
|
|
101
119
|
* @param impl The address of the new implementation contract.
|
|
102
120
|
*/
|
|
103
|
-
function _authorizeUpgrade(address impl) internal virtual override {}
|
|
121
|
+
function _authorizeUpgrade(address impl) internal virtual override onlyRole(DEFAULT_ADMIN_ROLE) {}
|
|
104
122
|
|
|
105
123
|
function getRegistry() public view override returns (DirectPaymentsFactory) {
|
|
106
124
|
return DirectPaymentsFactory(registry);
|
|
@@ -124,12 +142,11 @@ contract DirectPaymentsPool is
|
|
|
124
142
|
nft = _nft;
|
|
125
143
|
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
126
144
|
_setupRole(DEFAULT_ADMIN_ROLE, _settings.manager);
|
|
127
|
-
|
|
128
145
|
setSuperToken(ISuperToken(address(settings.rewardToken)));
|
|
129
146
|
}
|
|
130
147
|
|
|
131
|
-
function upgradeToLatest(bytes memory data) external payable virtual
|
|
132
|
-
address impl = DirectPaymentsFactory(registry).impl();
|
|
148
|
+
function upgradeToLatest(bytes memory data) external payable virtual {
|
|
149
|
+
address impl = address(DirectPaymentsFactory(registry).impl());
|
|
133
150
|
_authorizeUpgrade(impl);
|
|
134
151
|
_upgradeToAndCallUUPS(impl, data, false);
|
|
135
152
|
}
|
|
@@ -170,14 +187,27 @@ contract DirectPaymentsPool is
|
|
|
170
187
|
uint totalRewards;
|
|
171
188
|
uint rewardsBalance = settings.rewardToken.balanceOf(address(this));
|
|
172
189
|
|
|
190
|
+
bool allowRewardOverride = settings.allowRewardOverride;
|
|
173
191
|
for (uint256 i = 0; i < _data.events.length; i++) {
|
|
174
|
-
|
|
192
|
+
uint reward = (
|
|
193
|
+
allowRewardOverride && _data.events[i].rewardOverride > 0
|
|
194
|
+
? _data.events[i].rewardOverride
|
|
195
|
+
: _eventReward(_data.events[i].subtype)
|
|
196
|
+
) * _data.events[i].quantity;
|
|
175
197
|
if (reward > 0) {
|
|
176
|
-
totalRewards += reward
|
|
198
|
+
totalRewards += reward;
|
|
177
199
|
if (totalRewards > rewardsBalance) revert NO_BALANCE();
|
|
178
200
|
rewardsBalance -= totalRewards;
|
|
179
|
-
_sendReward(_data.events[i].contributers, uint128(reward
|
|
180
|
-
emit EventRewardClaimed(
|
|
201
|
+
_sendReward(_data.events[i].contributers, uint128(reward));
|
|
202
|
+
emit EventRewardClaimed(
|
|
203
|
+
_nftId,
|
|
204
|
+
_data.events[i].subtype,
|
|
205
|
+
_data.events[i].timestamp,
|
|
206
|
+
_data.events[i].quantity,
|
|
207
|
+
_data.events[i].eventUri,
|
|
208
|
+
_data.events[i].contributers,
|
|
209
|
+
uint128(reward / _data.events[i].contributers.length)
|
|
210
|
+
);
|
|
181
211
|
}
|
|
182
212
|
}
|
|
183
213
|
|
|
@@ -203,11 +233,17 @@ contract DirectPaymentsPool is
|
|
|
203
233
|
*/
|
|
204
234
|
function _sendReward(address[] memory recipients, uint128 reward) internal {
|
|
205
235
|
uint128 perReward = uint128(reward / recipients.length);
|
|
236
|
+
uint128 totalSent;
|
|
206
237
|
for (uint i = 0; i < recipients.length; i++) {
|
|
207
|
-
_enforceAndUpdateMemberLimits(recipients[i], perReward);
|
|
208
|
-
|
|
238
|
+
bool valid = _enforceAndUpdateMemberLimits(recipients[i], perReward);
|
|
239
|
+
if (valid) {
|
|
240
|
+
settings.rewardToken.safeTransfer(recipients[i], perReward);
|
|
241
|
+
totalSent += perReward;
|
|
242
|
+
} else {
|
|
243
|
+
emit NOT_MEMBER_OR_WHITELISTED(recipients[i]);
|
|
244
|
+
}
|
|
209
245
|
}
|
|
210
|
-
_enforceAndUpdateGlobalLimits(
|
|
246
|
+
_enforceAndUpdateGlobalLimits(totalSent);
|
|
211
247
|
}
|
|
212
248
|
|
|
213
249
|
/**
|
|
@@ -215,8 +251,11 @@ contract DirectPaymentsPool is
|
|
|
215
251
|
* @param member The address of the member to enforce and update limits for.
|
|
216
252
|
* @param reward The amount of rewards to enforce and update limits for.
|
|
217
253
|
*/
|
|
218
|
-
function _enforceAndUpdateMemberLimits(address member, uint128 reward) internal {
|
|
219
|
-
|
|
254
|
+
function _enforceAndUpdateMemberLimits(address member, uint128 reward) internal returns (bool) {
|
|
255
|
+
//dont revert on non valid members, just dont reward them (their reward is lost)
|
|
256
|
+
if (_addMember(member, "") == false) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
220
259
|
|
|
221
260
|
uint64 curMonth = _month();
|
|
222
261
|
if (memberLimits[member].lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
@@ -241,6 +280,8 @@ contract DirectPaymentsPool is
|
|
|
241
280
|
memberLimits[member].daily > limits.maxMemberPerDay ||
|
|
242
281
|
memberLimits[member].monthly > limits.maxMemberPerMonth
|
|
243
282
|
) revert OVER_MEMBER_LIMITS(member);
|
|
283
|
+
|
|
284
|
+
return true;
|
|
244
285
|
}
|
|
245
286
|
|
|
246
287
|
/**
|
|
@@ -285,32 +326,23 @@ contract DirectPaymentsPool is
|
|
|
285
326
|
* @param extraData Additional data to validate the member.
|
|
286
327
|
*/
|
|
287
328
|
|
|
288
|
-
function
|
|
329
|
+
function _addMember(address member, bytes memory extraData) internal returns (bool isMember) {
|
|
330
|
+
if (hasRole(MEMBER_ROLE, member)) return true;
|
|
331
|
+
|
|
289
332
|
if (address(settings.uniquenessValidator) != address(0)) {
|
|
290
333
|
address rootAddress = settings.uniquenessValidator.getWhitelistedRoot(member);
|
|
291
|
-
if (rootAddress == address(0))
|
|
334
|
+
if (rootAddress == address(0)) return false;
|
|
292
335
|
}
|
|
293
336
|
|
|
337
|
+
// if no members validator then anyone can join the pool
|
|
294
338
|
if (address(settings.membersValidator) != address(0)) {
|
|
295
339
|
if (settings.membersValidator.isMemberValid(address(this), msg.sender, member, extraData) == false) {
|
|
296
|
-
|
|
340
|
+
return false;
|
|
297
341
|
}
|
|
298
|
-
} else {
|
|
299
|
-
// if no members validator then only admin can add members
|
|
300
|
-
if (hasRole(DEFAULT_ADMIN_ROLE, msg.sender) == false) revert NOT_MANAGER();
|
|
301
342
|
}
|
|
302
343
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* @dev Removes a member from the contract.
|
|
309
|
-
* @param member The address of the member to remove.
|
|
310
|
-
*/
|
|
311
|
-
function removeMember(address member) external onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
312
|
-
members[member] = false;
|
|
313
|
-
emit MemberRemoved(member);
|
|
344
|
+
_setupRole(MEMBER_ROLE, member);
|
|
345
|
+
return true;
|
|
314
346
|
}
|
|
315
347
|
|
|
316
348
|
function mintNFT(address _to, ProvableNFT.NFTData memory _nftData, bool withClaim) external onlyRole(MINTER_ROLE) {
|
|
@@ -321,7 +353,7 @@ contract DirectPaymentsPool is
|
|
|
321
353
|
}
|
|
322
354
|
|
|
323
355
|
/**
|
|
324
|
-
* @dev Receives an ERC721 token
|
|
356
|
+
* @dev Receives an ERC721 token
|
|
325
357
|
* @param operator The address of the operator that sent the token.
|
|
326
358
|
* @param from The address of the sender that sent the token.
|
|
327
359
|
* @param tokenId The ID of the token received.
|
|
@@ -347,4 +379,27 @@ contract DirectPaymentsPool is
|
|
|
347
379
|
if (nftData.nftType != settings.nftType) revert UNSUPPORTED_NFT();
|
|
348
380
|
return DirectPaymentsPool.onERC721Received.selector;
|
|
349
381
|
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @dev Sets the safety limits for the pool.
|
|
385
|
+
* @param _limits The new safety limits.
|
|
386
|
+
*/
|
|
387
|
+
function setPoolLimits(SafetyLimits memory _limits) public onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
388
|
+
limits = _limits;
|
|
389
|
+
emit PoolLimitsChanged(_limits);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @dev Sets the settings for the pool.
|
|
394
|
+
* @param _settings The new pool settings.
|
|
395
|
+
*/
|
|
396
|
+
function setPoolSettings(PoolSettings memory _settings) public onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
397
|
+
if (_settings.nftType != settings.nftType) revert NFTTYPE_CHANGED();
|
|
398
|
+
if (_settings.manager == address(0)) revert EMPTY_MANAGER();
|
|
399
|
+
|
|
400
|
+
_revokeRole(DEFAULT_ADMIN_ROLE, settings.manager);
|
|
401
|
+
settings = _settings;
|
|
402
|
+
_setupRole(DEFAULT_ADMIN_ROLE, _settings.manager);
|
|
403
|
+
emit PoolSettingsChanged(_settings);
|
|
404
|
+
}
|
|
350
405
|
}
|
|
@@ -19,12 +19,15 @@ contract ProvableNFT is ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgrade
|
|
|
19
19
|
bytes32 public constant MINTER_ROLE = keccak256(abi.encodePacked("MINTER"));
|
|
20
20
|
bytes16 private constant _SYMBOLS = "0123456789abcdef";
|
|
21
21
|
|
|
22
|
+
event ProvableNftMinted(uint256 tokenId, address to, bytes32 nftDataHash);
|
|
23
|
+
|
|
22
24
|
struct EventData {
|
|
23
25
|
uint16 subtype;
|
|
24
26
|
uint32 timestamp;
|
|
25
27
|
uint256 quantity;
|
|
26
28
|
string eventUri; //extra data related to event
|
|
27
29
|
address[] contributers;
|
|
30
|
+
uint128 rewardOverride; //override reward defined per 1 quantity of event, pool will use this instead of its own reward if allowRewardOverride is true
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
struct NFTData {
|
|
@@ -41,7 +44,9 @@ contract ProvableNFT is ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgrade
|
|
|
41
44
|
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
function _authorizeUpgrade(address newimpl) internal virtual override
|
|
47
|
+
function _authorizeUpgrade(address /*newimpl*/) internal virtual override {
|
|
48
|
+
_onlyManager(0);
|
|
49
|
+
}
|
|
45
50
|
|
|
46
51
|
function supportsInterface(
|
|
47
52
|
bytes4 interfaceId
|
|
@@ -49,14 +54,13 @@ contract ProvableNFT is ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgrade
|
|
|
49
54
|
return super.supportsInterface(interfaceId);
|
|
50
55
|
}
|
|
51
56
|
|
|
52
|
-
|
|
57
|
+
function _onlyManager(uint32 nftType) internal view {
|
|
53
58
|
if (
|
|
54
59
|
((nftType > 0 && hasRole(getManagerRole(nftType), msg.sender)) ||
|
|
55
60
|
hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) == false
|
|
56
61
|
) {
|
|
57
62
|
revert NOT_MANAGER(nftType);
|
|
58
63
|
}
|
|
59
|
-
_;
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
/**
|
|
@@ -72,23 +76,24 @@ contract ProvableNFT is ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgrade
|
|
|
72
76
|
* @param _nftDataHash The hash of the NFT's data.
|
|
73
77
|
* @return tokenId ID of the newly minted NFT.
|
|
74
78
|
*/
|
|
75
|
-
function mint(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return _mint(_to, _uri, _nftDataHash, ""); //send false in calldata, assuming default receiver is a directpaymentspool. without nft data on chain it will fail.
|
|
79
|
+
function mint(address _to, string memory _uri, bytes32 _nftDataHash) public returns (uint256 tokenId) {
|
|
80
|
+
_onlyManager(0);
|
|
81
|
+
NFTData memory nftData;
|
|
82
|
+
|
|
83
|
+
return _mint(_to, _uri, _nftDataHash, nftData, ""); //send false in calldata, assuming default receiver is a directpaymentspool. without nft data on chain it will fail.
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
function _mint(
|
|
84
87
|
address _to,
|
|
85
88
|
string memory _uri,
|
|
86
89
|
bytes32 _nftDataHash,
|
|
90
|
+
NFTData memory /*_nftData*/,
|
|
87
91
|
bytes memory _callData
|
|
88
92
|
) internal returns (uint256 tokenId) {
|
|
89
93
|
tokenId = uint256(_nftDataHash);
|
|
90
94
|
nftDatas[tokenId].nftUri = _uri;
|
|
91
95
|
_safeMint(_to, tokenId, _callData);
|
|
96
|
+
emit ProvableNftMinted(tokenId, _to, _nftDataHash);
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
/**
|
|
@@ -109,7 +114,8 @@ contract ProvableNFT is ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgrade
|
|
|
109
114
|
NFTData memory _nftData,
|
|
110
115
|
bool _withStore,
|
|
111
116
|
bytes memory _callData
|
|
112
|
-
) external
|
|
117
|
+
) external returns (uint256 tokenId) {
|
|
118
|
+
_onlyManager(_nftData.nftType);
|
|
113
119
|
if (_nftData.nftType == 0) revert BAD_NFTTYPE();
|
|
114
120
|
|
|
115
121
|
bytes32 dataHash = keccak256(abi.encode(_nftData));
|
|
@@ -123,7 +129,7 @@ contract ProvableNFT is ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgrade
|
|
|
123
129
|
store.events.push(_nftData.events[i]);
|
|
124
130
|
}
|
|
125
131
|
}
|
|
126
|
-
_mint(_to, _nftData.nftUri, dataHash, _callData);
|
|
132
|
+
_mint(_to, _nftData.nftUri, dataHash, _nftData, _callData);
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
function proveNFTData(uint256 _tokenId, NFTData memory _nftData) public view returns (NFTData memory data) {
|
|
@@ -12,6 +12,7 @@ import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
|
|
|
12
12
|
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
|
|
13
13
|
|
|
14
14
|
import "../DirectPayments/DirectPaymentsFactory.sol";
|
|
15
|
+
import "../utils/HelperLibrary.sol";
|
|
15
16
|
|
|
16
17
|
// import "hardhat/console.sol";
|
|
17
18
|
|
|
@@ -46,42 +47,18 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
46
47
|
bool isFlowUpdate
|
|
47
48
|
);
|
|
48
49
|
|
|
49
|
-
//TODO:
|
|
50
|
+
//TODO:
|
|
50
51
|
// ask about "receiver" can it be different then app?
|
|
51
52
|
|
|
52
53
|
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
53
54
|
ISwapRouter public immutable swapRouter;
|
|
54
55
|
|
|
55
|
-
/**
|
|
56
|
-
* @dev A struct containing information about a token swap
|
|
57
|
-
* @param swapFrom The address of the token being swapped
|
|
58
|
-
* @param amount The amount of tokens being swapped
|
|
59
|
-
* @param minReturn The minimum amount of tokens to be received in the swap
|
|
60
|
-
* @param timestamp The deadline for the swap to occur
|
|
61
|
-
* @param path The path of tokens to take in a uniswap v3 multi-hop swap, encoded as bytes
|
|
62
|
-
*/
|
|
63
|
-
struct SwapData {
|
|
64
|
-
address swapFrom;
|
|
65
|
-
uint256 amount;
|
|
66
|
-
uint256 minReturn;
|
|
67
|
-
uint256 deadline;
|
|
68
|
-
bytes path;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
56
|
struct SupporterData {
|
|
72
57
|
uint256 contribution;
|
|
73
58
|
int96 flowRate;
|
|
74
59
|
uint128 lastUpdated;
|
|
75
60
|
}
|
|
76
61
|
|
|
77
|
-
struct Stats {
|
|
78
|
-
uint256 netIncome; //without fees
|
|
79
|
-
uint256 totalFees;
|
|
80
|
-
uint256 lastUpdate;
|
|
81
|
-
address lastFeeRecipient;
|
|
82
|
-
int96 lastIncomeRate;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
62
|
ISuperToken public superToken;
|
|
86
63
|
|
|
87
64
|
mapping(address => SupporterData) public supporters;
|
|
@@ -89,7 +66,7 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
89
66
|
//initialize cfaV1 variable
|
|
90
67
|
CFAv1Library.InitData public cfaV1;
|
|
91
68
|
|
|
92
|
-
Stats public stats;
|
|
69
|
+
IGoodCollectiveSuperApp.Stats public stats;
|
|
93
70
|
|
|
94
71
|
uint256[48] private _reserved;
|
|
95
72
|
|
|
@@ -141,13 +118,7 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
141
118
|
view
|
|
142
119
|
returns (uint256 netIncome, uint256 totalFees, int96 incomeFlowRate, int96 feeRate)
|
|
143
120
|
{
|
|
144
|
-
|
|
145
|
-
netIncome = stats.netIncome + uint96(stats.lastIncomeRate) * (block.timestamp - stats.lastUpdate);
|
|
146
|
-
feeRate = superToken.getFlowRate(address(this), stats.lastFeeRecipient);
|
|
147
|
-
totalFees =
|
|
148
|
-
stats.totalFees +
|
|
149
|
-
uint96(superToken.getFlowRate(address(this), stats.lastFeeRecipient)) *
|
|
150
|
-
(block.timestamp - stats.lastUpdate);
|
|
121
|
+
return HelperLibrary.getRealtimeStats(stats, superToken);
|
|
151
122
|
}
|
|
152
123
|
|
|
153
124
|
/**
|
|
@@ -197,42 +168,11 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
197
168
|
* @return Returns the context of the transaction
|
|
198
169
|
*/
|
|
199
170
|
function handleSwap(
|
|
200
|
-
SwapData memory _customData,
|
|
171
|
+
HelperLibrary.SwapData memory _customData,
|
|
201
172
|
address _sender,
|
|
202
173
|
bytes memory _ctx
|
|
203
174
|
) external onlyHostOrSender(_sender) returns (bytes memory) {
|
|
204
|
-
|
|
205
|
-
TransferHelper.safeTransferFrom(_customData.swapFrom, _sender, address(this), _customData.amount);
|
|
206
|
-
|
|
207
|
-
// Approve the router to spend the tokens
|
|
208
|
-
TransferHelper.safeApprove(_customData.swapFrom, address(swapRouter), _customData.amount);
|
|
209
|
-
|
|
210
|
-
if (_customData.path.length > 0) {
|
|
211
|
-
// If a path is provided, execute a multi-hop swap
|
|
212
|
-
ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({
|
|
213
|
-
path: _customData.path,
|
|
214
|
-
recipient: _sender,
|
|
215
|
-
deadline: _customData.deadline,
|
|
216
|
-
amountIn: _customData.amount,
|
|
217
|
-
amountOutMinimum: _customData.minReturn
|
|
218
|
-
});
|
|
219
|
-
swapRouter.exactInput(params);
|
|
220
|
-
} else {
|
|
221
|
-
// If no path is provided, execute a single-hop swap
|
|
222
|
-
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
|
|
223
|
-
tokenIn: _customData.swapFrom,
|
|
224
|
-
tokenOut: address(superToken),
|
|
225
|
-
fee: 10000,
|
|
226
|
-
recipient: _sender,
|
|
227
|
-
deadline: _customData.deadline,
|
|
228
|
-
amountIn: _customData.amount,
|
|
229
|
-
amountOutMinimum: _customData.minReturn,
|
|
230
|
-
sqrtPriceLimitX96: 0
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Execute the swap using `exactInputSingle`
|
|
234
|
-
swapRouter.exactInputSingle(params);
|
|
235
|
-
}
|
|
175
|
+
HelperLibrary.handleSwap(swapRouter, _customData, address(superToken), _sender);
|
|
236
176
|
|
|
237
177
|
// Return the context of the transaction
|
|
238
178
|
return _ctx;
|
|
@@ -392,6 +332,9 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
|
|
|
392
332
|
TransferHelper.safeTransfer(address(superToken), recipient, fee);
|
|
393
333
|
}
|
|
394
334
|
|
|
335
|
+
/**
|
|
336
|
+
* for methods that can be called via superfluid batch or directly
|
|
337
|
+
*/
|
|
395
338
|
modifier onlyHostOrSender(address _sender) {
|
|
396
339
|
if (msg.sender != _sender && msg.sender != address(host)) revert ONLY_HOST_OR_SENDER(msg.sender);
|
|
397
340
|
_;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity >=0.8.0;
|
|
3
|
+
|
|
4
|
+
interface IGoodCollectiveSuperApp {
|
|
5
|
+
struct Stats {
|
|
6
|
+
uint256 netIncome; //without fees
|
|
7
|
+
uint256 totalFees;
|
|
8
|
+
uint256 lastUpdate;
|
|
9
|
+
address lastFeeRecipient;
|
|
10
|
+
int96 lastIncomeRate;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
|
|
6
|
+
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
|
|
7
|
+
import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
|
|
8
|
+
import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol";
|
|
9
|
+
|
|
10
|
+
import "../GoodCollective/IGoodCollectiveSuperApp.sol";
|
|
11
|
+
|
|
12
|
+
library HelperLibrary {
|
|
13
|
+
using SuperTokenV1Library for ISuperToken;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @dev A struct containing information about a token swap
|
|
17
|
+
* @param swapFrom The address of the token being swapped
|
|
18
|
+
* @param amount The amount of tokens being swapped
|
|
19
|
+
* @param minReturn The minimum amount of tokens to be received in the swap
|
|
20
|
+
* @param timestamp The deadline for the swap to occur
|
|
21
|
+
* @param path The path of tokens to take in a uniswap v3 multi-hop swap, encoded as bytes
|
|
22
|
+
*/
|
|
23
|
+
struct SwapData {
|
|
24
|
+
address swapFrom;
|
|
25
|
+
uint256 amount;
|
|
26
|
+
uint256 minReturn;
|
|
27
|
+
uint256 deadline;
|
|
28
|
+
bytes path;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function handleSwap(
|
|
32
|
+
ISwapRouter swapRouter,
|
|
33
|
+
SwapData memory _customData,
|
|
34
|
+
address outTokenIfNoPath,
|
|
35
|
+
address _sender
|
|
36
|
+
) external {
|
|
37
|
+
// Transfer the tokens from the sender to this contract
|
|
38
|
+
TransferHelper.safeTransferFrom(_customData.swapFrom, _sender, address(this), _customData.amount);
|
|
39
|
+
|
|
40
|
+
// Approve the router to spend the tokens
|
|
41
|
+
TransferHelper.safeApprove(_customData.swapFrom, address(swapRouter), _customData.amount);
|
|
42
|
+
|
|
43
|
+
if (_customData.path.length > 0) {
|
|
44
|
+
// If a path is provided, execute a multi-hop swap
|
|
45
|
+
ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({
|
|
46
|
+
path: _customData.path,
|
|
47
|
+
recipient: _sender,
|
|
48
|
+
deadline: _customData.deadline,
|
|
49
|
+
amountIn: _customData.amount,
|
|
50
|
+
amountOutMinimum: _customData.minReturn
|
|
51
|
+
});
|
|
52
|
+
swapRouter.exactInput(params);
|
|
53
|
+
} else {
|
|
54
|
+
// If no path is provided, execute a single-hop swap
|
|
55
|
+
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
|
|
56
|
+
tokenIn: _customData.swapFrom,
|
|
57
|
+
tokenOut: outTokenIfNoPath,
|
|
58
|
+
fee: 10000,
|
|
59
|
+
recipient: _sender,
|
|
60
|
+
deadline: _customData.deadline,
|
|
61
|
+
amountIn: _customData.amount,
|
|
62
|
+
amountOutMinimum: _customData.minReturn,
|
|
63
|
+
sqrtPriceLimitX96: 0
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Execute the swap using `exactInputSingle`
|
|
67
|
+
swapRouter.exactInputSingle(params);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getRealtimeStats(
|
|
72
|
+
IGoodCollectiveSuperApp.Stats memory stats,
|
|
73
|
+
ISuperToken superToken
|
|
74
|
+
) external view returns (uint256 netIncome, uint256 totalFees, int96 incomeFlowRate, int96 feeRate) {
|
|
75
|
+
incomeFlowRate = stats.lastIncomeRate;
|
|
76
|
+
netIncome = stats.netIncome + uint96(stats.lastIncomeRate) * (block.timestamp - stats.lastUpdate);
|
|
77
|
+
feeRate = superToken.getFlowRate(address(this), stats.lastFeeRecipient);
|
|
78
|
+
totalFees =
|
|
79
|
+
stats.totalFees +
|
|
80
|
+
uint96(superToken.getFlowRate(address(this), stats.lastFeeRecipient)) *
|
|
81
|
+
(block.timestamp - stats.lastUpdate);
|
|
82
|
+
}
|
|
83
|
+
}
|