Skip to content

Commit d44e0af

Browse files
authored
Merge pull request #303 from GoodDollar/contracts-size-recoverfunds
Contracts size recoverfunds
2 parents f4b5118 + 48236e1 commit d44e0af

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+37227
-31394
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ yarn-error.log*
7373
# misc
7474
.DS_Store
7575
*.pem
76-
packages/contracts/deployments
7776
**/types
7877
packages/sdk-js/.yarn/install-state.gz
7978
.vercel
8079
.vscode/settings.json
80+
packages/contracts/deployments/*/solcInputs

packages/contracts/contracts/DirectPayments/DirectPaymentsFactory.sol

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,17 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
138138
}
139139

140140
// Register the app with the host
141-
IRegisterSuperapp(address(pool.host())).registerApp(address(pool), SuperAppDefinitions.APP_LEVEL_FINAL);
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+
}
142152

143153
nft.grantRole(nft.getManagerRole(nextNftType), address(pool));
144154

Lines changed: 168 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity >=0.8.0;
33

4+
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
5+
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
6+
47
import "./DirectPaymentsPool.sol";
8+
import "./ProvableNFT.sol";
59

6-
library DirectPayemntsLibrary {
7-
function _updateMemberLimits(
8-
DirectPaymentsPool.LimitsData storage memberStats,
9-
uint128 reward,
10-
uint64 curMonth
11-
) internal {
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 {
1228
if (memberStats.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
1329
{
1430
memberStats.daily = reward;
1531
} else {
1632
memberStats.daily += reward;
1733
}
1834

19-
if (memberStats.lastMonth < curMonth) //month switched
35+
if (memberStats.lastMonth < _month()) //month switched
2036
{
2137
memberStats.monthly = reward;
2238
} else {
@@ -25,22 +41,28 @@ library DirectPayemntsLibrary {
2541

2642
memberStats.total += reward;
2743
memberStats.lastReward = uint64(block.timestamp);
28-
memberStats.lastMonth = curMonth;
44+
memberStats.lastMonth = _month();
2945
}
3046

31-
function _updateGlobalLimits(
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(
3254
DirectPaymentsPool.LimitsData storage globalLimits,
33-
uint128 reward,
34-
uint64 curMonth
35-
) internal {
55+
DirectPaymentsPool.SafetyLimits memory limits,
56+
uint128 reward
57+
) public {
3658
if (globalLimits.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
3759
{
3860
globalLimits.daily = reward;
3961
} else {
4062
globalLimits.daily += reward;
4163
}
4264

43-
if (globalLimits.lastMonth < curMonth) //month switched
65+
if (globalLimits.lastMonth < _month()) //month switched
4466
{
4567
globalLimits.monthly = reward;
4668
} else {
@@ -49,6 +71,138 @@ library DirectPayemntsLibrary {
4971

5072
globalLimits.total += reward;
5173
globalLimits.lastReward = uint64(block.timestamp);
52-
globalLimits.lastMonth = curMonth;
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));
53207
}
54208
}

0 commit comments

Comments
 (0)