@@ -6,9 +6,15 @@ import {OwnableUpgradeable, Initializable} from "@openzeppelin/contracts-upgrade
6
6
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol " ;
7
7
import {IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
8
8
9
+ import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol " ;
10
+
9
11
import {ICore} from "./interfaces/ICore.sol " ;
10
12
import {IBasedAppManager} from "./interfaces/IBasedAppManager.sol " ;
11
13
14
+ // TODO assumption that sharedRiskLevel can not be 0 when it's set
15
+ // todo should check that is not 0, otherwise use a fixed value to identify the "0 value".
16
+ // if max cap is 10000, then "0 value" could be 10001
17
+
12
18
/**
13
19
* @title BasedAppManager
14
20
* @notice The Core Contract to manage Based Applications, Delegations & Strategies for SSV Based Applications Platform.
@@ -51,7 +57,7 @@ import {IBasedAppManager} from "./interfaces/IBasedAppManager.sol";
51
57
* Marco Tabasco
52
58
* Riccardo Persiani
53
59
*/
54
- contract BasedAppManager is Initializable , OwnableUpgradeable , UUPSUpgradeable , IBasedAppManager {
60
+ contract BasedAppManager is Initializable , OwnableUpgradeable , UUPSUpgradeable , ReentrancyGuard , IBasedAppManager {
55
61
using SafeERC20 for IERC20 ;
56
62
57
63
uint32 public constant MAX_PERCENTAGE = 1e4 ;
@@ -70,10 +76,15 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
70
76
uint256 private _strategyCounter;
71
77
72
78
/**
73
- * @notice Tracks the bApps created
79
+ * @notice Tracks the owners of the bApps
74
80
* @dev The bApp is identified with its address
75
81
*/
76
- mapping (address bApp = > ICore.BApp) public bApps;
82
+ mapping (address bApp = > address owner ) public bAppOwners;
83
+ /**
84
+ * @notice Tracks the tokens supported by the bApps
85
+ * @dev The bApp is identified with its address
86
+ */
87
+ mapping (address bApp = > mapping (address token = > uint32 sharedRiskLevel )) public bAppTokens;
77
88
/**
78
89
* @notice Tracks the strategies created
79
90
* @dev The strategy ID is incremental and unique
@@ -127,26 +138,20 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
127
138
*/
128
139
mapping (uint256 strategyId = > mapping (address token = > mapping (address bApp = > ICore.ObligationRequest))) public
129
140
obligationRequests;
130
- /**
131
- * @notice Tracks all the obligation created in a strategy.
132
- * @dev This value is never decremented. It is used to avoid a new opt in for an obligation that was created before and set to zero.
133
- */
134
- mapping (uint256 strategyId = > mapping (address bApp = > uint32 numberOfObligations )) public obligationsCounter;
135
141
136
142
/// @notice Prevents the initialization of the implementation contract itself during deployment
137
143
constructor () {
138
144
_disableInitializers ();
139
145
}
140
146
141
147
/// @notice Initialize the contract
148
+ /// @param owner The owner of the contract
142
149
/// @param _maxFeeIncrement The maximum fee increment
143
- function initialize (
144
- uint32 _maxFeeIncrement
145
- ) public initializer {
150
+ function initialize (address owner , uint32 _maxFeeIncrement ) public initializer {
146
151
if (_maxFeeIncrement == 0 || _maxFeeIncrement > MAX_PERCENTAGE) {
147
152
revert ICore.InvalidMaxFeeIncrement ();
148
153
}
149
- __Ownable_init (msg . sender );
154
+ __Ownable_init (owner );
150
155
__UUPSUpgradeable_init ();
151
156
maxFeeIncrement = _maxFeeIncrement;
152
157
emit MaxFeeIncrementSet (maxFeeIncrement);
@@ -168,7 +173,7 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
168
173
modifier onlyBAppOwner (
169
174
address bApp
170
175
) {
171
- if (bApps [bApp].owner != msg .sender ) revert ICore.InvalidBAppOwner (msg .sender , bApps [bApp].owner );
176
+ if (bAppOwners [bApp] != msg .sender ) revert ICore.InvalidBAppOwner (msg .sender , bAppOwners [bApp]);
172
177
_;
173
178
}
174
179
@@ -238,28 +243,24 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
238
243
// ********************
239
244
240
245
/// @notice Function to register a bApp
241
- /// @param owner The address of the owner
242
246
/// @param bAppAddress The address of the bApp
243
247
/// @param tokens The list of tokens the bApp accepts, can also be empty.
244
- /// @param sharedRiskLevel The shared risk level of the bApp
248
+ /// @param sharedRiskLevels The shared risk level of the bApp
249
+ /// @param metadataURI The metadata URI of the bApp
245
250
function registerBApp (
246
- address owner ,
247
251
address bAppAddress ,
248
252
address [] calldata tokens ,
249
- uint32 sharedRiskLevel ,
253
+ uint32 [] calldata sharedRiskLevels ,
250
254
string calldata metadataURI
251
255
) external {
252
- ICore.BApp storage bApp = bApps[bAppAddress];
253
- if (bApp.owner != address (0 )) revert ICore.BAppAlreadyRegistered ();
254
-
255
- bApp.owner = owner;
256
- bApp.sharedRiskLevel = sharedRiskLevel;
256
+ if (bAppOwners[bAppAddress] != address (0 )) revert ICore.BAppAlreadyRegistered ();
257
+ bAppOwners[bAppAddress] = msg .sender ;
257
258
258
259
for (uint256 i = 0 ; i < tokens.length ; i++ ) {
259
- bApp. tokens. push (tokens [i]) ;
260
+ bAppTokens[bAppAddress][ tokens[i]] = sharedRiskLevels[i] ;
260
261
}
261
262
262
- emit BAppRegistered (bAppAddress, owner, msg .sender , metadataURI, tokens );
263
+ emit BAppRegistered (bAppAddress, msg .sender , tokens, sharedRiskLevels, metadataURI );
263
264
}
264
265
265
266
/// @notice Function to update the metadata URI of the Based Application
@@ -272,25 +273,20 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
272
273
/// @notice Function to add tokens to a bApp
273
274
/// @param bAppAddress The address of the bApp
274
275
/// @param tokens The list of tokens to add
275
- function addTokensToBApp (address bAppAddress , address [] calldata tokens ) external {
276
- ICore.BApp storage bApp = bApps[bAppAddress];
276
+ function addTokensToBApp (
277
+ address bAppAddress ,
278
+ address [] calldata tokens ,
279
+ uint32 [] calldata sharedRiskLevels
280
+ ) external onlyBAppOwner (bAppAddress) {
281
+ if (tokens.length != sharedRiskLevels.length ) revert ICore.TokensLengthNotMatchingRiskLevels ();
277
282
for (uint256 i = 0 ; i < tokens.length ; i++ ) {
278
- for (uint256 j = 0 ; j < bApp.tokens.length ; j++ ) {
279
- if (bApp.tokens[j] == tokens[i]) revert ICore.TokenAlreadyAddedToBApp (tokens[i]);
280
- }
281
- bApp.tokens.push (tokens[i]);
283
+ // todo if (sharedRiskLevels[i] == 0 || sharedRiskLevels[i] > MAX_RISK_VALUE) revert ICore.InvalidPercentage();
284
+ if (bAppTokens[bAppAddress][tokens[i]] != 0 ) revert ICore.TokenAlreadyAddedToBApp (tokens[i]);
285
+ bAppTokens[bAppAddress][tokens[i]] = sharedRiskLevels[i];
282
286
}
283
287
emit BAppTokensUpdated (bAppAddress, tokens);
284
288
}
285
289
286
- /// @notice Function to get the tokens for a bApp
287
- /// @param bAppAddress The address of the bApp
288
- function getBAppTokens (
289
- address bAppAddress
290
- ) external view returns (address [] memory ) {
291
- return bApps[bAppAddress].tokens;
292
- }
293
-
294
290
// ***********************
295
291
// ** Section: Strategy **
296
292
// ***********************
@@ -312,6 +308,7 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
312
308
}
313
309
314
310
/// @notice Opt-in to a bApp with a list of tokens and obligation percentages
311
+ /// @dev checks that each token is supported by the bApp, but not that the obligation is > 0
315
312
/// @param strategyId The ID of the strategy
316
313
/// @param bApp The address of the bApp
317
314
/// @param tokens The list of tokens to opt-in with
@@ -326,14 +323,14 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
326
323
) external onlyStrategyOwner (strategyId) {
327
324
if (tokens.length != obligationPercentages.length ) revert ICore.TokensLengthNotMatchingPercentages ();
328
325
329
- ICore.BApp storage existingBApp = bApps[bApp];
330
- _matchTokens (tokens, existingBApp.tokens );
326
+ // ICore.BApp storage existingBApp = bApps[bApp];
327
+ _matchTokens (tokens, bApp );
331
328
332
329
// Check if a strategy exists for the given bApp.
333
330
// It is not possible opt-in to the same bApp twice with the same strategy owner.
334
331
if (accountBAppStrategy[msg .sender ][bApp] != 0 ) revert ICore.BAppAlreadyOptedIn ();
335
332
336
- emit BAppOptedInByStrategy (strategyId, bApp, data);
333
+ emit BAppOptedInByStrategy (strategyId, bApp, data, tokens, obligationPercentages );
337
334
338
335
_setObligations (strategyId, bApp, tokens, obligationPercentages);
339
336
@@ -370,7 +367,7 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
370
367
/// @param strategyId The ID of the strategy
371
368
/// @param token The ERC20 token address
372
369
/// @param amount The amount to withdraw
373
- function fastWithdrawERC20 (uint256 strategyId , IERC20 token , uint256 amount ) external {
370
+ function fastWithdrawERC20 (uint256 strategyId , IERC20 token , uint256 amount ) external nonReentrant {
374
371
if (amount == 0 ) revert ICore.InvalidAmount ();
375
372
if (usedTokens[strategyId][address (token)] != 0 ) revert ICore.TokenIsUsedByTheBApp ();
376
373
if (strategyTokenBalances[strategyId][msg .sender ][address (token)] < amount) revert ICore.InsufficientBalance ();
@@ -386,7 +383,7 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
386
383
/// @notice Withdraw ETH from the strategy
387
384
/// @param strategyId The ID of the strategy
388
385
/// @param amount The amount to withdraw
389
- function fastWithdrawETH (uint256 strategyId , uint256 amount ) external {
386
+ function fastWithdrawETH (uint256 strategyId , uint256 amount ) external nonReentrant {
390
387
if (amount == 0 ) revert ICore.InvalidAmount ();
391
388
if (usedTokens[strategyId][ETH_ADDRESS] != 0 ) revert ICore.TokenIsUsedByTheBApp ();
392
389
if (strategyTokenBalances[strategyId][msg .sender ][ETH_ADDRESS] < amount) revert ICore.InsufficientBalance ();
@@ -492,19 +489,15 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
492
489
) external onlyStrategyOwner (strategyId) {
493
490
if (obligationPercentage > MAX_PERCENTAGE) revert ICore.InvalidPercentage ();
494
491
if (obligations[strategyId][bApp][token] != 0 ) revert ICore.ObligationAlreadySet ();
495
- if (obligationsCounter[strategyId ][bApp] == 0 ) revert ICore.BAppNotOptedIn ();
492
+ if (accountBAppStrategy[ msg . sender ][bApp] != strategyId ) revert ICore.BAppNotOptedIn ();
496
493
497
- address [] storage bAppTokens = bApps[bApp].tokens;
498
- _matchToken (token, bAppTokens);
494
+ if (bAppTokens[bApp][token] == 0 ) revert ICore.TokenNoTSupportedByBApp (token);
499
495
500
496
if (obligationPercentage != 0 ) {
501
497
usedTokens[strategyId][token] += 1 ;
502
498
obligations[strategyId][bApp][token] = obligationPercentage;
503
499
}
504
500
505
- accountBAppStrategy[msg .sender ][bApp] = strategyId;
506
- obligationsCounter[strategyId][bApp] += 1 ;
507
-
508
501
emit ObligationCreated (strategyId, bApp, token, obligationPercentage);
509
502
}
510
503
@@ -519,10 +512,14 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
519
512
address token ,
520
513
uint32 obligationPercentage
521
514
) external onlyStrategyOwner (strategyId) {
522
- if (obligationsCounter[strategyId ][bApp] == 0 ) revert ICore.BAppNotOptedIn ();
515
+ if (accountBAppStrategy[ msg . sender ][bApp] != strategyId ) revert ICore.BAppNotOptedIn ();
523
516
if (obligationPercentage > MAX_PERCENTAGE) revert ICore.InvalidPercentage ();
524
517
if (obligationPercentage <= obligations[strategyId][bApp][token]) revert ICore.InvalidPercentage ();
525
518
519
+ if (obligations[strategyId][bApp][token] == 0 && obligationPercentage > 0 ) {
520
+ usedTokens[strategyId][token] += 1 ;
521
+ }
522
+
526
523
obligations[strategyId][bApp][token] = obligationPercentage;
527
524
528
525
emit ObligationUpdated (strategyId, bApp, token, obligationPercentage, true );
@@ -538,8 +535,9 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
538
535
address token ,
539
536
uint32 obligationPercentage
540
537
) external onlyStrategyOwner (strategyId) {
541
- if (obligationsCounter[strategyId ][bApp] == 0 ) revert ICore.BAppNotOptedIn ();
538
+ if (accountBAppStrategy[ msg . sender ][bApp] != strategyId ) revert ICore.BAppNotOptedIn ();
542
539
if (obligationPercentage > MAX_PERCENTAGE) revert ICore.InvalidPercentage ();
540
+ if (obligationPercentage == obligations[strategyId][bApp][token]) revert ICore.PercentageAlreadySet ();
543
541
544
542
ICore.ObligationRequest storage request = obligationRequests[strategyId][bApp][token];
545
543
@@ -577,13 +575,11 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
577
575
revert ICore.UpdateObligationExpired ();
578
576
}
579
577
580
- // Remove the usedToken from the counter, but not the obligation counter.
581
- if (percentage == 0 ) {
578
+ if (percentage == 0 && obligations[strategyId][bApp][address (token)] > 0 ) {
582
579
usedTokens[strategyId][address (token)] -= 1 ;
583
580
}
584
581
585
- // If updating an obligation from 0 to greater then increase the usedToken counter.
586
- if (obligations[strategyId][bApp][address (token)] == 0 ) {
582
+ if (obligations[strategyId][bApp][address (token)] == 0 && percentage > 0 ) {
587
583
usedTokens[strategyId][address (token)] += 1 ;
588
584
}
589
585
@@ -654,42 +650,28 @@ contract BasedAppManager is Initializable, OwnableUpgradeable, UUPSUpgradeable,
654
650
address token = tokens[i];
655
651
uint32 obligationPercentage = obligationPercentages[i];
656
652
653
+ // todo check the bapp mapping and reject if the token is not available
654
+
657
655
if (obligationPercentage > MAX_PERCENTAGE) revert ICore.InvalidPercentage ();
658
656
659
657
if (obligationPercentage != 0 ) {
660
658
usedTokens[strategyId][token] += 1 ;
661
659
obligations[strategyId][bApp][token] = obligationPercentage;
662
660
}
663
661
664
- obligationsCounter[strategyId][bApp] += 1 ;
662
+ // obligationsCounter[strategyId][bApp] += 1;
665
663
666
664
emit ObligationCreated (strategyId, bApp, token, obligationPercentage);
667
665
}
668
666
}
669
667
670
668
/// @notice Match the tokens of strategy with the bApp
671
- /// Complexity: O(n * m )
669
+ /// Complexity: O(n)
672
670
/// @param tokens The list of strategy tokens
673
- /// @param bAppTokens The list of bApp tokens
674
- function _matchTokens (address [] calldata tokens , address [] memory bAppTokens ) private pure {
671
+ /// @param bApp The bApp address
672
+ function _matchTokens (address [] calldata tokens , address bApp ) private view {
675
673
for (uint256 i = 0 ; i < tokens.length ; i++ ) {
676
- address token = tokens[i];
677
- _matchToken (token, bAppTokens);
678
- }
679
- }
680
-
681
- /// @notice Match the single token of strategy with the bApp token list
682
- /// @param token The strategy token
683
- /// @param bAppTokens The list of bApp tokens
684
- function _matchToken (address token , address [] memory bAppTokens ) private pure {
685
- bool matched = false ;
686
- for (uint256 i = 0 ; i < bAppTokens.length ; ++ i) {
687
- address bAppToken = bAppTokens[i];
688
- if (bAppToken == token) {
689
- matched = true ;
690
- break ;
691
- }
674
+ if (bAppTokens[bApp][tokens[i]] == 0 ) revert ICore.TokenNoTSupportedByBApp (tokens[i]);
692
675
}
693
- if (! matched) revert ICore.TokenNoTSupportedByBApp (token);
694
676
}
695
677
}
0 commit comments