@@ -10,6 +10,7 @@ import {IERC20} from "../../lib/openzeppelin-contracts/contracts/interfaces/IERC
10
10
import {ISafe} from "./interfaces/ISafe.sol " ;
11
11
import {ILocker} from "../lockers/interfaces/ILocker.sol " ;
12
12
import {Ownable} from "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol " ;
13
+ import {ReentrancyGuard} from "../../lib/solmate/src/utils/ReentrancyGuard.sol " ;
13
14
import {SafeERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol " ;
14
15
import {Storage} from "./Storage.sol " ;
15
16
@@ -22,6 +23,7 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
22
23
////////////////////////////////////////////////////////////// */
23
24
24
25
error IsNotALocker ();
26
+ error IsActiveLocker ();
25
27
error LengthMismatch ();
26
28
error LockerNotPrivate ();
27
29
error MaxCommissionsDepth ();
@@ -40,6 +42,16 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
40
42
MODIFIERS
41
43
////////////////////////////////////////////////////////////// */
42
44
45
+ modifier nonReentrant () {
46
+ require (locked == 1 , "REENTRANCY " );
47
+
48
+ locked = 2 ;
49
+
50
+ _;
51
+
52
+ locked = 1 ;
53
+ }
54
+
43
55
/* //////////////////////////////////////////////////////////////
44
56
CONSTRUCTOR
45
57
////////////////////////////////////////////////////////////// */
@@ -115,8 +127,12 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
115
127
YIELD LOCKERS LOGIC
116
128
////////////////////////////////////////////////////////////// */
117
129
118
- function syncAll () external {
130
+ /**
131
+ * @notice Synchronizes all yield lockers by adjusting balances based on weights and idle ratio.
132
+ */
133
+ function syncAll () external nonReentrant {
119
134
if (block .timestamp < lastSyncTime + 1 days) revert SyncIntervalNotMet ();
135
+ lastSyncTime = block .timestamp ;
120
136
121
137
// Cache values.
122
138
uint256 BIPS_ = BIPS;
@@ -154,7 +170,6 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
154
170
}
155
171
156
172
// Get total amount that should be deposited in lockers (non-idle).
157
- // Note : check if ok to keep same totalSupply here (think should be ok)
158
173
uint256 totalToInvest = totalSupplyExclPrivate.mulDivDown (BIPS_ - idleRatio, BIPS_);
159
174
160
175
// We use weights.length as those should always sum to BIPS (see setWeights()).
@@ -164,7 +179,6 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
164
179
uint256 currentBalance = ILocker (lockers[i]).totalDeposited ();
165
180
166
181
if (currentBalance < targetBalance) {
167
- // Note : use batchApprove.
168
182
uint256 toDeposit = targetBalance - currentBalance;
169
183
IERC20 (underlying_).approve (lockers[i], toDeposit);
170
184
// Don't revert if the call fails, continue.
@@ -180,7 +194,10 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
180
194
}
181
195
}
182
196
183
- // Note : It should mint the yield in underlying token and distribute to treasury
197
+ /**
198
+ * @notice Collects yield from all yield lockers and mints it to the treasury.
199
+ * @return yield The total yield collected.
200
+ */
184
201
function collectYield () external returns (uint256 yield ) {
185
202
if (block .timestamp - lastYieldClaim < yieldInterval) revert YieldIntervalNotMet ();
186
203
@@ -209,11 +226,19 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
209
226
treasury = treasury_;
210
227
}
211
228
229
+ /**
230
+ * @notice Adds a new yield locker to the system.
231
+ * @param locker The address of the locker to add.
232
+ */
212
233
function addYieldLocker (address locker ) external onlyOwner {
213
234
if (yieldLockers.length == MAX_YIELD_LOCKERS) revert MaxYieldLockers ();
214
235
yieldLockers.push (locker);
215
236
}
216
237
238
+ /**
239
+ * @notice Removes a yield locker from the system, withdrawing its balance.
240
+ * @param locker The address of the locker to remove.
241
+ */
217
242
function removeYieldLocker (address locker ) external onlyOwner {
218
243
// Cache values
219
244
address [] memory yieldLockers_ = yieldLockers;
@@ -248,6 +273,10 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
248
273
lockersWeights.pop ();
249
274
}
250
275
276
+ /**
277
+ * @notice Sets the weights for yield lockers.
278
+ * @param newLockersWeights The new weights for each locker.
279
+ */
251
280
// Note : Double check no issue if idle set to max vs lockers
252
281
function setWeights (uint256 [] memory newLockersWeights ) external onlyOwner {
253
282
if (newLockersWeights.length != yieldLockers.length ) revert LengthMismatch ();
@@ -259,11 +288,19 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
259
288
lockersWeights = newLockersWeights;
260
289
}
261
290
291
+ /**
292
+ * @notice Sets a new idle ratio for the system.
293
+ * @param newRatio The new idle ratio.
294
+ */
262
295
function setIdleRatio (uint256 newRatio ) external onlyOwner {
263
296
if (newRatio > BIPS) revert MaxRatio ();
264
297
idleRatio = newRatio;
265
298
}
266
299
300
+ /**
301
+ * @notice Sets the interval for yield collection.
302
+ * @param yieldInterval_ The new yield interval in seconds.
303
+ */
267
304
function setYieldInterval (uint256 yieldInterval_ ) external onlyOwner {
268
305
if (yieldInterval_ > 30 days) revert MaxYieldInterval ();
269
306
yieldInterval = yieldInterval_;
@@ -273,10 +310,22 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
273
310
PRIVATE YIELD LOCKERS LOGIC
274
311
////////////////////////////////////////////////////////////// */
275
312
313
+ /**
314
+ * @notice Marks an address as a private locker.
315
+ * @param locker The address of the locker to mark as private.
316
+ */
276
317
function addPrivateLocker (address locker ) external onlyOwner {
318
+ for (uint256 i; i < yieldLockers.length ; ++ i) {
319
+ if (locker == yieldLockers[i]) revert IsActiveLocker ();
320
+ }
277
321
isPrivateLocker[locker] = true ;
278
322
}
279
323
324
+ /**
325
+ * @notice Deposits an amount into a private locker.
326
+ * @param locker The address of the private locker.
327
+ * @param amount The amount to deposit.
328
+ */
280
329
function depositInPrivateLocker (address locker , uint256 amount ) external onlyOwner {
281
330
if (isPrivateLocker[locker] == false ) revert LockerNotPrivate ();
282
331
@@ -285,8 +334,26 @@ contract EurB is ERC20Wrapper, Ownable, Storage {
285
334
ILocker (locker).deposit (address (underlying ()), amount);
286
335
}
287
336
288
- function collectYieldFromPrivateLocker (address locker ) external onlyOwner {
337
+ /**
338
+ * @notice Collects yield from a private locker.
339
+ * @param locker The address of the private locker.
340
+ */
341
+ function collectYieldFromPrivateLocker (address locker ) external onlyOwner returns (uint256 yield ) {
289
342
if (isPrivateLocker[locker] == false ) revert LockerNotPrivate ();
343
+
344
+ // Cache value
345
+ address underlying_ = address (underlying ());
346
+ // Get total balance before collecting yield.
347
+ uint256 initBalance = IERC20 (underlying_).balanceOf (address (this ));
348
+ ILocker (locker).collectYield (underlying_);
349
+ // Calculate yield collected.
350
+ uint256 newBalance = IERC20 (underlying_).balanceOf (address (this ));
351
+
352
+ yield = newBalance > initBalance ? newBalance - initBalance : 0 ;
353
+ if (yield > 0 ) {
354
+ // Mint the yield generated to the treasury.
355
+ _mint (treasury, yield);
356
+ }
290
357
}
291
358
// Note : Do we put a recover function (yes with limited withdrawable assets) ?
292
359
}
0 commit comments