@@ -4,8 +4,8 @@ pragma solidity ^0.8.28;
44import {INostalgicPool} from "./interfaces/INostalgicPool.sol " ;
55import {INostalgicController} from "./interfaces/INostalgicController.sol " ;
66import {Math} from "@openzeppelin/contracts/utils/math/Math.sol " ;
7+ import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol " ;
78import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol " ;
8- import {console} from "forge-std/console.sol " ;
99
1010// /$$ /$$ /$$ /$$ /$$ /$$$$$$ /$$ /$$ /$$
1111// | $$$ | $$ | $$ | $$ |__/ /$$__ $$ | $$ | $$| $$
@@ -18,23 +18,44 @@ import {console} from "forge-std/console.sol";
1818// /$$ \ $$
1919// | $$$$$$/
2020// \______/
21- //
22- contract NostalgicController is AccessControl , INostalgicController {
21+
22+ /// @title Nostalgic Controller
23+ /// @notice Manages user interactions with Nostalgic Pools
24+ /// @author typicalHuman
25+ contract NostalgicController is
26+ AccessControl ,
27+ ReentrancyGuard ,
28+ INostalgicController
29+ {
2330 using Math for uint256 ;
2431
2532 uint256 internal constant SCALING_FACTOR = 1e18 ;
2633
34+ /// @notice Liquidation incentive for liquidators
35+ uint256 public constant LIQUIDATION_INCENTIVE = 0.04e18 ; // 4%
36+
37+ /// @notice Protocol liquidation fee
38+ uint256 public constant PROTOCOL_LIQUIDATION_FEE = 0.01e18 ; // 1%
39+
40+ /// @notice Address of the Nostalgic factory contract
41+ address public factory;
42+
43+ /// @notice Mapping of existing pool addresses
2744 mapping (INostalgicPool pool => bool exists ) public existingPools;
45+
46+ /// @notice Mapping of user addresses to their entered pool addresses
2847 mapping (address user = > INostalgicPool[] pools ) public userEnteredMarkets;
48+
49+ /// @notice Mapping of user addresses to their interaction status with each pool
2950 mapping (address user = > mapping (INostalgicPool pool => bool hasInteracted ))
3051 public userMarketEntries;
31- mapping (address asset = > uint256 collateralFactor ) public collateralFactors;
3252
33- address public factory;
34-
35- uint256 public liquidationIncentive = 0.04e18 ; // 4%
36- uint256 public protocolLiquidationFee = 0.01e18 ; // 1%
53+ /// @notice Mapping of asset addresses to their collateral factors
54+ mapping (address asset = > uint256 collateralFactor ) public collateralFactors;
3755
56+ /// @notice Constructor for the NostalgicController contract
57+ /// @param initialAdmin The address of the initial admin
58+ /// @param _factory The address of the Nostalgic factory contract
3859 constructor (address initialAdmin , address _factory ) {
3960 require (
4061 initialAdmin != address (0 ) && _factory != address (0 ),
@@ -44,11 +65,14 @@ contract NostalgicController is AccessControl, INostalgicController {
4465 _grantRole (DEFAULT_ADMIN_ROLE, initialAdmin);
4566 }
4667
47- modifier onlyOwnerOrFactory () {
48- _onlyOwnerOrFactory ();
68+ /// @notice Modifier to restrict access to the admin or factory
69+ modifier onlyAdminOrFactory () {
70+ _onlyAdminOrFactory ();
4971 _;
5072 }
5173
74+ /// @notice Updates the address of the Nostalgic factory contract
75+ /// @param newFactory The address of the new Nostalgic factory contract
5276 function updateFactory (
5377 address newFactory
5478 ) public onlyRole (DEFAULT_ADMIN_ROLE) {
@@ -57,29 +81,36 @@ contract NostalgicController is AccessControl, INostalgicController {
5781 emit FactoryUpdate (newFactory);
5882 }
5983
84+ /// @inheritdoc INostalgicController
6085 function isHealthy (address user ) public view returns (bool ) {
6186 (uint256 totalUsdCollateral , uint256 totalUsdBorrow ) = userPosition (
6287 user
6388 );
6489 return totalUsdCollateral >= totalUsdBorrow;
6590 }
6691
92+ /// @inheritdoc INostalgicController
6793 function userPosition (
6894 address user
6995 ) public view returns (uint256 totalUsdCollateral , uint256 totalUsdBorrow ) {
7096 INostalgicPool[] memory investedPools = userEnteredMarkets[user];
71- for (uint i = 0 ; i < investedPools.length ; i++ ) {
72- uint256 userCollateral = investedPools[i].getTokenValueInUSD (
73- investedPools[i].userLends (user)
97+ for (uint256 i = 0 ; i < investedPools.length ; ) {
98+ INostalgicPool pool = investedPools[i];
99+
100+ uint256 userCollateral = pool.getTokenValueInUSD (
101+ pool.userLends (user)
74102 );
75- totalUsdBorrow += investedPools[i] .getTokenValueInUSD (
76- investedPools[i] .scaledBorrowPosition (user)
103+ totalUsdBorrow += pool .getTokenValueInUSD (
104+ pool .scaledBorrowPosition (user)
77105 );
78106
79- totalUsdCollateral += getUsdValue (investedPools[i], userCollateral);
107+ totalUsdCollateral += getUsdValue (pool, userCollateral);
108+ unchecked {
109+ ++ i;
110+ }
80111 }
81112 }
82-
113+ /// @inheritdoc INostalgicController
83114 function canBorrow (
84115 INostalgicPool pool ,
85116 address user ,
@@ -95,12 +126,13 @@ contract NostalgicController is AccessControl, INostalgicController {
95126 return totalUsdCollateral > totalUsdBorrow;
96127 }
97128
129+ /// @inheritdoc INostalgicController
98130 function liquidateBorrower (
99131 address borrower ,
100132 address liquidator ,
101133 uint256 repaidAmount ,
102134 INostalgicPool collateralPool
103- ) external {
135+ ) external nonReentrant {
104136 require (
105137 existingPools[INostalgicPool (msg .sender )] &&
106138 existingPools[collateralPool],
@@ -113,9 +145,9 @@ contract NostalgicController is AccessControl, INostalgicController {
113145 repaidAmountUsd
114146 );
115147 uint256 liquidatorIncentive = (repaidInCollateralToken *
116- liquidationIncentive ) / SCALING_FACTOR;
148+ LIQUIDATION_INCENTIVE ) / SCALING_FACTOR;
117149 uint256 protocolReward = (repaidInCollateralToken *
118- protocolLiquidationFee ) / SCALING_FACTOR;
150+ PROTOCOL_LIQUIDATION_FEE ) / SCALING_FACTOR;
119151 uint256 liquidatorReward = liquidatorIncentive +
120152 repaidInCollateralToken;
121153 require (
@@ -131,11 +163,12 @@ contract NostalgicController is AccessControl, INostalgicController {
131163 );
132164 }
133165
166+ /// @inheritdoc INostalgicController
134167 function interactWithPool (address user ) external {
135168 require (existingPools[INostalgicPool (msg .sender )], PoolNotFound ());
136169 uint256 lends = INostalgicPool (msg .sender ).userLends (user);
137170 uint256 borrows = INostalgicPool (msg .sender ).userBorrows (user);
138- bool toAdd = lends + borrows > 0 ? true : false ;
171+ bool toAdd = lends + borrows > 0 ;
139172 if (toAdd) {
140173 if (userMarketEntries[user][INostalgicPool (msg .sender )]) return ;
141174 userMarketEntries[user][INostalgicPool (msg .sender )] = true ;
@@ -147,83 +180,113 @@ contract NostalgicController is AccessControl, INostalgicController {
147180 _removePool (user, INostalgicPool (msg .sender ));
148181 }
149182
150- function addPool (INostalgicPool pool ) external onlyOwnerOrFactory {
183+ /// @notice Adds a new Nostalgic pool
184+ /// @param pool The address of the Nostalgic pool to add
185+ function addPool (INostalgicPool pool ) external onlyAdminOrFactory {
151186 existingPools[pool] = true ;
152187
153- emit PoolAdded (pool);
188+ emit PoolAdd (pool);
154189 }
155190
191+ /// @notice Removes an existing Nostalgic pool
192+ /// @param pool The address of the Nostalgic pool to remove
156193 function removePool (
157194 INostalgicPool pool
158195 ) external onlyRole (DEFAULT_ADMIN_ROLE) {
159196 require (pool.totalLended () == 0 , PoolNotEmpty ());
160197 existingPools[pool] = false ;
161- emit PoolRemoved (pool);
198+ emit PoolRemove (pool);
162199 }
200+
201+ /// @notice Adds a new asset to the collateral manager
202+ /// @param asset The address of the asset to add
203+ /// @param collateralFactor The collateral factor for the asset
163204 function addAsset (
164205 address asset ,
165206 uint256 collateralFactor
166- ) external onlyOwnerOrFactory {
207+ ) external onlyAdminOrFactory {
167208 require (collateralFactors[asset] == 0 , AssetAlreadyAdded ());
168209 require (
169210 collateralFactor <=
170- SCALING_FACTOR - protocolLiquidationFee - liquidationIncentive,
211+ SCALING_FACTOR -
212+ PROTOCOL_LIQUIDATION_FEE -
213+ LIQUIDATION_INCENTIVE,
171214 InvalidCollateralFactor ()
172215 );
173216 collateralFactors[asset] = collateralFactor;
174217
175- emit AssetAdded (asset, collateralFactor);
218+ emit AssetAdd (asset, collateralFactor);
176219 }
177220
178- function update (
221+ /// @notice Updates the collateral factor for an existing asset
222+ /// @param asset The address of the asset to update
223+ /// @param collateralFactor The new collateral factor for the asset
224+ function updateCollateralFactor (
179225 address asset ,
180226 uint256 collateralFactor
181227 ) external onlyRole (DEFAULT_ADMIN_ROLE) {
182228 require (collateralFactors[asset] != 0 , AssetNotAdded ());
183229 require (
184230 collateralFactor <=
185- SCALING_FACTOR - protocolLiquidationFee - liquidationIncentive,
231+ SCALING_FACTOR -
232+ PROTOCOL_LIQUIDATION_FEE -
233+ LIQUIDATION_INCENTIVE,
186234 InvalidCollateralFactor ()
187235 );
188236 collateralFactors[asset] = collateralFactor;
189237
190- emit CollateralFactorUpdated (asset, collateralFactor);
238+ emit CollateralFactorUpdate (asset, collateralFactor);
191239 }
192240
241+ /// @notice Removes an existing asset from the collateral manager
242+ /// @param asset The address of the asset to remove
193243 function removeAsset (address asset ) external onlyRole (DEFAULT_ADMIN_ROLE) {
194244 require (collateralFactors[asset] != 0 , AssetNotAdded ());
195245
196246 collateralFactors[asset] = 0 ;
197- emit AssetRemoved (asset);
247+ emit AssetRemove (asset);
198248 }
199249
250+ /// @notice Gets the USD value of a given amount of an asset in a Nostalgic pool
251+ /// @param pool The Nostalgic pool to get the USD value from
252+ /// @param amount The amount of the asset to convert to USD
200253 function getUsdValue (
201254 INostalgicPool pool ,
202255 uint256 amount
203256 ) public view returns (uint256 ) {
204257 return amount.mulDiv (collateralFactors[pool.asset ()], SCALING_FACTOR);
205258 }
206259
207- function _onlyOwnerOrFactory () internal view {
260+ /// @notice Checks if the caller is the admin or the factory
261+ function _onlyAdminOrFactory () internal view {
208262 require (
209263 hasRole (DEFAULT_ADMIN_ROLE, msg .sender ) || msg .sender == factory,
210264 InvalidCaller ()
211265 );
212266 }
213267
268+ /// @notice Removes a Nostalgic pool from a user's entered markets
269+ /// @param user The address of the user
270+ /// @param pool The Nostalgic pool to remove
214271 function _removePool (address user , INostalgicPool pool ) internal {
215- uint length = userEnteredMarkets[user].length ;
216- for (uint i = 0 ; i < length; i ++ ) {
272+ uint256 length = userEnteredMarkets[user].length ;
273+ for (uint256 i = 0 ; i < length; ) {
217274 if (userEnteredMarkets[user][i] == pool) {
218275 // Shift elements left
219- for (uint j = i; j < length - 1 ; j ++ ) {
276+ for (uint256 j = i; j < length - 1 ; ) {
220277 userEnteredMarkets[user][j] = userEnteredMarkets[user][
221278 j + 1
222279 ];
280+ unchecked {
281+ ++ j;
282+ }
223283 }
224284 userEnteredMarkets[user].pop (); // remove last
225285 break ;
226286 }
287+ unchecked {
288+ ++ i;
289+ }
227290 }
228291 }
229292}
0 commit comments