-
Notifications
You must be signed in to change notification settings - Fork 17
/
Claimer.sol
212 lines (190 loc) · 7.63 KB
/
Claimer.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { SD59x18 } from "prb-math/SD59x18.sol";
import { UD2x18 } from "prb-math/UD2x18.sol";
import { UD60x18 } from "prb-math/UD60x18.sol";
import { PrizePool } from "v5-prize-pool/PrizePool.sol";
import { Multicall } from "openzeppelin/utils/Multicall.sol";
import { LinearVRGDALib } from "./libraries/LinearVRGDALib.sol";
import { Vault } from "v5-vault/Vault.sol";
/// @title Variable Rate Gradual Dutch Auction (VRGDA) Claimer
/// @author PoolTogether Inc. Team
/// @notice This contract uses a variable rate gradual dutch auction to inventivize prize claims on behalf of others
contract Claimer is Multicall {
/// @notice The Prize Pool that this Claimer is claiming prizes for
PrizePool public immutable prizePool;
/// @notice The maximum fee that can be charged as a portion of the smallest prize size. Fixed point 18 number
UD2x18 public immutable maxFeePortionOfPrize;
/// @notice The VRGDA decay constant computed in the constructor
SD59x18 public immutable decayConstant;
/// @notice The minimum fee that will be charged
uint256 public immutable minimumFee;
uint256 public immutable timeToReachMaxFee;
/// @notice Constructs a new Claimer
/// @param _prizePool The prize pool to claim for
/// @param _minimumFee The minimum fee that should be charged
/// @param _maximumFee The maximum fee that should be charged
/// @param _timeToReachMaxFee The time it should take to reach the maximum fee (for example should be the draw period in seconds)
/// @param _maxFeePortionOfPrize The maximum fee that can be charged as a portion of the smallest prize size. Fixed point 18 number
constructor(
PrizePool _prizePool,
uint256 _minimumFee,
uint256 _maximumFee,
uint256 _timeToReachMaxFee,
UD2x18 _maxFeePortionOfPrize
) {
prizePool = _prizePool;
maxFeePortionOfPrize = _maxFeePortionOfPrize;
decayConstant = LinearVRGDALib.getDecayConstant(
LinearVRGDALib.getMaximumPriceDeltaScale(_minimumFee, _maximumFee, _timeToReachMaxFee)
);
minimumFee = _minimumFee;
timeToReachMaxFee = _timeToReachMaxFee;
}
/// @notice Allows the call to claim prizes on behalf of others.
/// @param vault The vault to claim from
/// @param tier The tier to claim for
/// @param winners The array of winners to claim for
/// @param prizeIndices The array of prize indices to claim for each winner (length should match winners)
/// @param _feeRecipient The address to receive the claim fees
/// @return totalFees The total fees collected across all successful claims
function claimPrizes(
Vault vault,
uint8 tier,
address[] calldata winners,
uint32[][] calldata prizeIndices,
address _feeRecipient
) external returns (uint256 totalFees) {
uint256 claimCount;
for (uint i = 0; i < winners.length; i++) {
claimCount += prizeIndices[i].length;
}
uint96 feePerClaim = uint96(
_computeFeePerClaim(
_computeMaxFee(tier, prizePool.numberOfTiers()),
claimCount,
prizePool.claimCount()
)
);
vault.claimPrizes(tier, winners, prizeIndices, feePerClaim, _feeRecipient);
return feePerClaim * claimCount;
}
/// @notice Computes the total fees for the given number of claims.
/// @param _tier The tier to claim prizes from
/// @param _claimCount The number of claims
/// @return The total fees for those claims
function computeTotalFees(uint8 _tier, uint _claimCount) external view returns (uint256) {
return
_computeFeePerClaim(
_computeMaxFee(_tier, prizePool.numberOfTiers()),
_claimCount,
prizePool.claimCount()
) * _claimCount;
}
/// @notice Computes the total fees for the given number of claims if a number of claims have already been made.
/// @param _tier The tier to claim prizes from
/// @param _claimCount The number of claims
/// @param _claimedCount The number of prizes already claimed
/// @return The total fees for those claims
function computeTotalFees(
uint8 _tier,
uint _claimCount,
uint _claimedCount
) external view returns (uint256) {
return
_computeFeePerClaim(
_computeMaxFee(_tier, prizePool.numberOfTiers()),
_claimCount,
_claimedCount
) * _claimCount;
}
/// @notice Computes the fees for several claims.
/// @param _maxFee the maximum fee that can be charged
/// @param _claimCount the number of claims to check
/// @return The fees for the claims
function computeFeePerClaim(uint256 _maxFee, uint _claimCount) external view returns (uint256) {
return _computeFeePerClaim(_maxFee, _claimCount, prizePool.claimCount());
}
/// @notice Computes the total fees for the given number of claims.
/// @param _maxFee The maximum fee
/// @param _claimCount The number of claims to check
/// @param _claimedCount The number of prizes already claimed
/// @return The total fees for the claims
function _computeFeePerClaim(
uint256 _maxFee,
uint _claimCount,
uint _claimedCount
) internal view returns (uint256) {
if (_claimCount == 0) {
return 0;
}
SD59x18 perTimeUnit = LinearVRGDALib.getPerTimeUnit(
prizePool.estimatedPrizeCount(),
timeToReachMaxFee
);
uint256 elapsed = block.timestamp - (prizePool.lastClosedDrawAwardedAt());
uint256 fee;
for (uint i = 0; i < _claimCount; i++) {
fee += _computeFeeForNextClaim(
minimumFee,
decayConstant,
perTimeUnit,
elapsed,
_claimedCount + i,
_maxFee
);
}
return fee / _claimCount;
}
/// @notice Computes the maximum fee that can be charged.
/// @param _tier The tier to compute the max fee for
/// @return The maximum fee that can be charged
function computeMaxFee(uint8 _tier) public view returns (uint256) {
return _computeMaxFee(_tier, prizePool.numberOfTiers());
}
/// @notice Computes the max fee given the tier and number of tiers.
/// @param _tier The tier to compute the max fee for
/// @param _numTiers The total number of tiers
/// @return The maximum fee that will be charged for a prize claim for the given tier
function _computeMaxFee(uint8 _tier, uint8 _numTiers) internal view returns (uint256) {
uint8 _canaryTier = _numTiers - 1;
if (_tier != _canaryTier) {
// canary tier
return _computeMaxFee(prizePool.getTierPrizeSize(_canaryTier - 1));
} else {
return _computeMaxFee(prizePool.getTierPrizeSize(_canaryTier));
}
}
/// @notice Computes the maximum fee that can be charged.
/// @param _prize The prize to compute the max fee for
/// @return The maximum fee that can be charged
function _computeMaxFee(uint256 _prize) internal view returns (uint256) {
// compute the maximum fee that can be charged
return UD60x18.unwrap(maxFeePortionOfPrize.intoUD60x18().mul(UD60x18.wrap(_prize)));
}
/// @notice Computes the fee for the next claim.
/// @param _minimumFee The minimum fee that should be charged
/// @param _decayConstant The VRGDA decay constant
/// @param _perTimeUnit The num to be claimed per second
/// @param _elapsed The number of seconds that have elapsed
/// @param _sold The number of prizes that were claimed
/// @param _maxFee The maximum fee that can be charged
/// @return The fee to charge for the next claim
function _computeFeeForNextClaim(
uint256 _minimumFee,
SD59x18 _decayConstant,
SD59x18 _perTimeUnit,
uint256 _elapsed,
uint256 _sold,
uint256 _maxFee
) internal pure returns (uint256) {
uint256 fee = LinearVRGDALib.getVRGDAPrice(
_minimumFee,
_elapsed,
_sold,
_perTimeUnit,
_decayConstant
);
return fee > _maxFee ? _maxFee : fee;
}
}