Skip to content

Commit 29c7c2a

Browse files
authored
Merge pull request #280 from hopperlabsxyz/fix/pr-270-review-comments
fix: address PR #270 review comments
2 parents 5e4a24f + e4cdb26 commit 29c7c2a

19 files changed

Lines changed: 101 additions & 117 deletions

src/protocol-v3/OptinProxyFactory.sol

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
pragma solidity 0.8.26;
33

44
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
5-
import {IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
65
import {LagoonVault} from "@src/proxy/OptinProxy.sol";
7-
import {AccessMode} from "@src/v0.6.0/primitives/Enums.sol";
6+
import {InitStruct} from "@src/v0.6.0/vault/Vault-v0.6.0.sol";
87

98
interface IVault {
109
function initialize(
@@ -26,42 +25,6 @@ struct OptinProxyFactoryStorage {
2625
mapping(address => bool) isInstance;
2726
}
2827

29-
/// @title InitStruct
30-
/// @notice Initialization structure for creating new vault proxies
31-
/// @dev Contains all necessary parameters to initialize a vault
32-
struct InitStruct {
33-
/// @notice Underlying ERC20 token for the vault
34-
IERC20 underlying;
35-
/// @notice Name of the vault token
36-
string name;
37-
/// @notice Symbol of the vault token
38-
string symbol;
39-
/// @notice Address of the safe/multisig
40-
address safe;
41-
/// @notice Address of the whitelist manager
42-
address whitelistManager;
43-
/// @notice Address of the valuation manager
44-
address valuationManager;
45-
/// @notice Admin address for the vault
46-
address admin;
47-
/// @notice Fee receiver address
48-
address feeReceiver;
49-
/// @notice Management fee rate (in basis points)
50-
uint16 managementRate;
51-
/// @notice Performance fee rate (in basis points)
52-
uint16 performanceRate;
53-
/// @notice Access mode (Whitelist or Blacklist)
54-
AccessMode accessMode;
55-
/// @notice Entry fee rate (in basis points)
56-
uint16 entryRate;
57-
/// @notice Exit fee rate (in basis points)
58-
uint16 exitRate;
59-
/// @notice Address of the security council
60-
address securityCouncil;
61-
/// @notice Address of the external sanctions list
62-
address externalSanctionsList;
63-
}
64-
6528
/// @title OptinProxyFactory
6629
/// @notice Factory contract for creating and managing OptinProxy instances
6730
/// @dev Inherits from OwnableUpgradeable to provide ownership functionality
@@ -112,6 +75,7 @@ contract OptinProxyFactory is OwnableUpgradeable {
11275
$.WRAPPED_NATIVE = _wrappedNativeToken;
11376
}
11477

78+
/// @param _logic Address of the vault logic implementation
11579
/// @param _initialOwner Address of the initial proxy owner
11680
/// @param _initialDelay The initial delay before which an upgrade can occur by the proxy admin
11781
/// @param _init Initialization parameters for the vault

src/v0.5.0/Vault.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ import {
1818
ValuationUpdateNotAllowed
1919
} from "./primitives/Errors.sol";
2020

21-
import {FeeRegistry} from "../protocol-v1/FeeRegistry.sol";
2221
import {DepositSync, Referral, StateUpdated} from "./primitives/Events.sol";
2322
import {ERC4626Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol";
2423
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
2524
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
2625
import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
2726
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
27+
import {FeeRegistry} from "@src/protocol-v1/FeeRegistry.sol";
2828

2929
using SafeERC20 for IERC20;
3030

@@ -59,6 +59,7 @@ struct InitStruct {
5959
}
6060

6161
/// @custom:contact team@hopperlabs.xyz
62+
/// @custom:oz-upgrades-from src/v0.4.0/Vault.sol:Vault
6263
contract Vault is ERC7540, Whitelistable, FeeManager {
6364
/// @custom:storage-location erc7201:hopper.storage.vault
6465
/// @param newTotalAssets The new total assets of the vault. It is used to update the totalAssets variable.

src/v0.6.0/FeeManager.sol

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,16 @@ abstract contract FeeManager is Ownable2StepUpgradeable {
5151
/// @param _decimals the number of decimals of the shares
5252
/// @param _entryRate the entry fee rate, expressed in BPS
5353
/// @param _exitRate the exit fee rate, expressed in BPS
54+
/// @param _haircutRate the haircut fee rate, expressed in BPS
5455
// solhint-disable-next-line func-name-mixedcase
5556
function __FeeManager_init(
5657
address _registry,
5758
uint16 _managementRate,
5859
uint16 _performanceRate,
5960
uint256 _decimals,
6061
uint16 _entryRate,
61-
uint16 _exitRate
62+
uint16 _exitRate,
63+
uint16 _haircutRate
6264
) internal onlyInitializing {
6365
FeeManagerStorage storage $ = FeeLib._getFeeManagerStorage();
6466
FeeLib.updateRates(
@@ -68,7 +70,7 @@ abstract contract FeeManager is Ownable2StepUpgradeable {
6870
performanceRate: _performanceRate,
6971
entryRate: _entryRate,
7072
exitRate: _exitRate,
71-
haircutRate: 0 // ????????????
73+
haircutRate: _haircutRate
7274
})
7375
);
7476

src/v0.6.0/GuardRailsManager.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ abstract contract GuardrailsManager is Roles {
4040
});
4141
}
4242

43-
// @inheritdoc GuardrailsLib
43+
/// @notice Updates the current guardrails policy with a new one.
44+
/// @param guardrails_ The new guardrails to be set.
4445
function updateGuardrails(
4546
Guardrails calldata guardrails_
4647
) external onlySecurityCouncil {

src/v0.6.0/Roles.sol

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@
22
pragma solidity 0.8.26;
33

44
import {RolesLib} from "./libraries/RolesLib.sol";
5-
import {
6-
OnlySafe,
7-
OnlyValuationManagerOrSecurityCouncil,
8-
OnlyWhitelistManager,
9-
SafeUpgradeabilityNotAllowed
10-
} from "./primitives/Errors.sol";
5+
import {OnlySafe, OnlyWhitelistManager, SafeUpgradeabilityNotAllowed} from "./primitives/Errors.sol";
116
import {
127
FeeReceiverUpdated,
138
SafeUpdated,
@@ -28,8 +23,9 @@ abstract contract Roles is Ownable2StepUpgradeable {
2823
/// @param safe Every lagoon vault is associated with a Safe smart contract. This address will receive the assets of
2924
/// the vault and can settle deposits and redeems.
3025
/// @param feeRegistry The address of the FeeRegistry contract.
31-
/// @param valuationManager. This address is responsible of updating the newTotalAssets value of the vault.
32-
/// @param owner The address of the owner of the contract. It considered as the admin. It is not visible in the
26+
/// @param valuationManager This address is responsible of updating the newTotalAssets value of the vault.
27+
/// @param securityCouncil The address of the security council that can update total assets without guardrails.
28+
/// @dev owner The address of the owner of the contract. It considered as the admin. It is not visible in the
3329
/// struct. It can change the others roles and itself. Initiate the fund closing. Disable the whitelist.
3430
struct RolesStorage {
3531
address whitelistManager;
@@ -75,8 +71,8 @@ abstract contract Roles is Ownable2StepUpgradeable {
7571
}
7672

7773
/// @dev Modifier to check if the caller is the valuation manager.
78-
modifier onlyValuationManagerOrSecurityCouncil() {
79-
RolesLib._onlyValuationManagerOrSecurityCouncil();
74+
modifier onlyValuationManager() {
75+
RolesLib._onlyValuationManager();
8076
_;
8177
}
8278

src/v0.6.0/Whitelistable.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {AccessMode} from "./primitives/Enums.sol";
1010
abstract contract Whitelistable is Roles {
1111
/// @custom:storage-definition erc7201:hopper.storage.Whitelistable
1212
/// @param isWhitelisted The mapping of whitelisted addresses.
13-
/// @param whitelistState The current whitelist mode (whitelist or blacklist).
13+
/// @param accessMode The current access mode (whitelist or blacklist).
1414
struct WhitelistableStorage {
1515
mapping(address => bool) isWhitelisted;
1616
// in v0.6.0, we replace the bool isActivated with a enum AccessMode

src/v0.6.0/libraries/FeeLib.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ library FeeLib {
2525
uint16 constant MAX_PERFORMANCE_RATE = 5000; // 50 %
2626
uint16 constant MAX_ENTRY_RATE = 1000; // 10 %
2727
uint16 constant MAX_EXIT_RATE = 1000; // 10 %
28-
uint16 constant MAX_HAIRCUT_RATE = 1000; // 10 %
2928
uint16 constant MAX_PROTOCOL_RATE = 3000; // 30 %
29+
uint16 constant MAX_HAIRCUT_RATE = 1000; // 10 %
3030

3131
// keccak256(abi.encode(uint256(keccak256("hopper.storage.FeeManager")) - 1)) & ~bytes32(uint256(0xff));
3232
/// @custom:storage-location erc7201:hopper.storage.FeeManager
@@ -46,7 +46,7 @@ library FeeLib {
4646
/// @param assets the total assets under management
4747
/// @param annualRate the management rate, expressed in BPS and corresponding to the annual
4848
/// @param timeElapsed the time elapsed since the last fee calculation in seconds
49-
/// @return managementFee the management fee express in assets
49+
/// @return managementFee the management fee expressed in assets
5050
function calculateManagementFee(
5151
uint256 assets,
5252
uint256 annualRate,
@@ -227,6 +227,9 @@ library FeeLib {
227227
if (newRates.exitRate > MAX_EXIT_RATE) {
228228
revert AboveMaxRate(MAX_EXIT_RATE);
229229
}
230+
if (newRates.haircutRate > MAX_HAIRCUT_RATE) {
231+
revert AboveMaxRate(MAX_HAIRCUT_RATE);
232+
}
230233

231234
Rates memory currentRates = $.rates;
232235
$.rates = newRates;

src/v0.6.0/libraries/GuardrailsLib.sol

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ library GuardrailsLib {
1414
// scale to avoid loss of precision
1515
uint256 public constant SCALE = 1e18;
1616

17-
/// @custom:storage-definition erc7201:hopper.storage.FeeManager
17+
/// @custom:storage-definition erc7201:hopper.storage.GuardrailsManager
1818
/// @param guardrails The current guardrails.
1919
struct GuardrailsManagerStorage {
2020
Guardrails guardrails;
@@ -39,13 +39,11 @@ library GuardrailsLib {
3939
}
4040
}
4141

42-
/**
43-
* @notice Checks if a price-per-share (PPS) update is compliant with the current guardrails.
44-
* @param currentPps The current price-per-share.
45-
* @param nextPps The proposed new price-per-share.
46-
* @param _timePast The time elapsed since the last update.
47-
* @return bool True if the update is compliant, false otherwise.
48-
*/
42+
/// @notice Checks if a price-per-share (PPS) update is compliant with the current guardrails.
43+
/// @param currentPps The current price-per-share.
44+
/// @param nextPps The proposed new price-per-share.
45+
/// @param _timePast The time elapsed since the last update.
46+
/// @return bool True if the update is compliant, false otherwise.
4947
function isCompliant(
5048
uint256 currentPps,
5149
uint256 nextPps,
@@ -87,10 +85,8 @@ library GuardrailsLib {
8785
}
8886
}
8987

90-
/**
91-
* @notice Updates the current policy with a new one.
92-
* @param guardrails_ The new guardrails to be set.
93-
*/
88+
/// @notice Updates the current policy with a new one.
89+
/// @param guardrails_ The new guardrails to be set.
9490
function updateGuardrails(
9591
Guardrails memory guardrails_
9692
) external {

src/v0.6.0/libraries/RolesLib.sol

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@
22
pragma solidity 0.8.26;
33

44
import {Roles} from "../Roles.sol";
5-
import {OnlySafe, OnlyWhitelistManager} from "../primitives/Errors.sol";
6-
import {
7-
OnlySafe,
8-
OnlySecurityCouncil,
9-
OnlyValuationManagerOrSecurityCouncil,
10-
OnlyWhitelistManager
11-
} from "../primitives/Errors.sol";
5+
import {OnlySafe, OnlySecurityCouncil, OnlyValuationManager, OnlyWhitelistManager} from "../primitives/Errors.sol";
126
import {
137
FeeReceiverUpdated,
148
SafeUpdated,
@@ -44,11 +38,10 @@ library RolesLib {
4438
}
4539
}
4640

47-
function _onlyValuationManagerOrSecurityCouncil() internal view {
41+
function _onlyValuationManager() internal view {
4842
address _valuationManager = _getRolesStorage().valuationManager;
49-
address _securityCouncil = _getRolesStorage().securityCouncil;
50-
if (_valuationManager != msg.sender && _securityCouncil != msg.sender) {
51-
revert OnlyValuationManagerOrSecurityCouncil(_valuationManager, _securityCouncil);
43+
if (_valuationManager != msg.sender) {
44+
revert OnlyValuationManager(_valuationManager);
5245
}
5346
}
5447

src/v0.6.0/primitives/Errors.sol

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,9 @@ error OnlySafe(address safe);
8080
/// @param whitelistManager The address of the whitelist manager.
8181
error OnlyWhitelistManager(address whitelistManager);
8282

83-
/// @notice Indicates that the caller is not the valuation manager or the security council.
83+
/// @notice Indicates that the caller is not the valuation manager.
8484
/// @param valuationManager The address of the valuation manager.
85-
/// @param securityCouncil The address of the security council.
86-
error OnlyValuationManagerOrSecurityCouncil(address valuationManager, address securityCouncil);
85+
error OnlyValuationManager(address valuationManager);
8786

8887
/// @notice Indicates that the safe upgradeability has been given up..
8988
error SafeUpgradeabilityNotAllowed();

0 commit comments

Comments
 (0)