Skip to content

Instantly share code, notes, and snippets.

@liveactionllama
Created June 23, 2023 22:58
Show Gist options
  • Save liveactionllama/27513952718ec3cbcf9de0fda7fef49c to your computer and use it in GitHub Desktop.
Save liveactionllama/27513952718ec3cbcf9de0fda7fef49c to your computer and use it in GitHub Desktop.
Winning bot race submission

Summary

High Risk Issues

Issue Instances
[H‑01] get_dy_underlying() is not a flash-loan-resistant price 1
[H‑02] wstETH's functions operate on units of stEth, not Eth 1

Total: 2 instances over 2 issues

Medium Risk Issues

Issue Instances
[M‑01] Contracts are vulnerable to fee-on-transfer accounting-related issues 1
[M‑02] Insufficient oracle validation 3
[M‑03] Missing checks for whether the L2 Sequencer is active 3
[M‑04] The owner is a single point of failure and a centralization risk 17
[M‑05] Contracts are vulnerable to rebasing accounting-related issues 1
[M‑06] Some tokens may revert when zero value transfers are made 2
[M‑07] Unsafe use of transfer()/transferFrom() with IERC20 15
[M‑08] Return values of transfer()/transferFrom() not checked 14

Total: 56 instances over 8 issues

Low Risk Issues

Issue Instances
[L‑01] Missing checks for address(0x0) when assigning values to address state variables 34
[L‑02] decimals() is not a part of the ERC-20 standard 2
[L‑03] Solidity version 0.8.20 may not work on other chains due to PUSH0 21
[L‑04] Loss of precision 50
[L‑05] Array lengths not checked 1
[L‑06] Use Ownable2Step rather than Ownable 4
[L‑07] Upgradeable contract is missing a __gap[50] storage variable to allow for new storage variables in later versions 1

Total: 113 instances over 7 issues

Non-critical Issues

Issue Instances
[N‑01] Events are missing sender information 3
[N‑02] Variables need not be initialized to zero 4
[N‑03] Consider using named mappings 37
[N‑04] Non-external/public variable and function names should begin with an underscore 29
[N‑05] Large numeric literals should use underscores for readability 15
[N‑06] Constants in comparisons should appear on the left side 33
[N‑07] Consider disabling renounceOwnership() 4
[N‑08] else-block not required 3
[N‑09] addresss shouldn't be hard-coded 2
[N‑10] Interfaces should be defined in separate files from their usage 17
[N‑11] Imports could be organized more systematically 1
[N‑12] Mixed usage of int/uint with int256/uint256 40
[N‑13] public functions not called by the contract should be declared external instead 13
[N‑14] constants should be defined rather than using magic numbers 118
[N‑15] Event is not properly indexed 13
[N‑16] Duplicated require()/revert() checks should be refactored to a modifier or function 9
[N‑17] Import declarations should import specific identifiers, rather than the whole file 56
[N‑18] Contract implements interface without extending the interface 7
[N‑19] require()/revert() statements should have descriptive reason strings 2
[N‑20] Missing event and or timelock for critical parameter change 11
[N‑21] Events that mark critical parameter changes should contain both the old and the new value 9
[N‑22] Constant redefined elsewhere 3
[N‑23] Use @inheritdoc rather than using a non-standard annotation 1
[N‑24] Inconsistent spacing in comments 6
[N‑25] Lines are too long 92
[N‑26] Variable names that consist of all capital letters should be reserved for constant/immutable variables 4
[N‑27] Non-library/interface files should use fixed compiler versions, not floating ones 19
[N‑28] Typos 1
[N‑29] File is missing NatSpec 11
[N‑30] NatSpec @param is missing 133
[N‑31] NatSpec @return argument is missing 20
[N‑32] Function definition modifier order does not follow Solidity style guide 2
[N‑33] Visibility should be set explicitly rather than defaulting to internal 18
[N‑34] Function ordering does not follow the Solidity style guide 30
[N‑35] Contract does not follow the Solidity style guide's suggested layout ordering 16
[N‑36] Interfaces should be indicated with an I prefix in the contract name 2
[N‑37] Control structures do not follow the Solidity Style Guide 12
[N‑38] mapping definitions do not follow the Solidity Style Guide 1
[N‑39] Expressions for constant values such as a call to keccak256(), should use immutable rather than constant 7
[N‑40] Numeric values having to do with time should use time units for readability 2
[N‑41] Consider using delete rather than assigning zero/false to clear values 9
[N‑42] Contracts should have full test coverage 1
[N‑43] Large or complicated code bases should implement invariant tests 1

Total: 817 instances over 43 issues

Gas Optimizations

Issue Instances Total Gas Saved
[G‑01] Reduce gas usage by moving to Solidity 0.8.19 or later 21 -
[G‑02] Avoid updating storage when the value hasn't changed 17 13600
[G‑03] Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate 7 -
[G‑04] State variables only set in the constructor should be declared immutable 5 10485
[G‑05] Using storage instead of memory for structs/arrays saves gas 1 4200
[G‑06] State variables should be cached in stack variables rather than re-reading them from storage 22 2134
[G‑07] Multiple accesses of a mapping/array should use a local variable cache 13 546
[G‑08] The result of function calls should be cached rather than re-calling the function 1 -
[G‑09] <x> += <y> costs more gas than <x> = <x> + <y> for state variables 16 1808
[G‑10] internal functions only called once can be inlined to save gas 1 20
[G‑11] Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if-statement 16 1360
[G‑12] <array>.length should not be looked up in every loop of a for-loop 3 9
[G‑13] ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops 3 180
[G‑14] require()/revert() strings longer than 32 bytes cost extra gas 39 -
[G‑15] keccak256() should only need to be called on a specific string literal once 3 126
[G‑16] Optimize names to save gas 15 330
[G‑17] Using bools for storage incurs overhead 7 119700
[G‑18] Use a more recent version of solidity 1 -
[G‑19] Using > 0 costs more gas than != 0 when used on a uint in a require() statement 3 18
[G‑20] >= costs less gas than > 2 6
[G‑21] ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) 3 15
[G‑22] Splitting require() statements that use && saves gas 3 9
[G‑23] Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead 1 -
[G‑24] Using private rather than public for constants, saves gas 8 -
[G‑25] Don't compare boolean expressions to boolean literals 1 9
[G‑26] Don't use SafeMath once the solidity version is 0.8.0 or greater 1 -
[G‑27] require() or revert() statements that check input arguments should be at the top of the function 2 -
[G‑28] Empty blocks should be removed or emit something 20 -
[G‑29] Superfluous event fields 19 -
[G‑30] Use custom errors rather than revert()/require() strings to save gas 111 -
[G‑31] Functions guaranteed to revert when called by normal users can be marked payable 26 546
[G‑32] Constructors can be marked payable 20 420
[G‑33] Don't use _msgSender() if not supporting EIP-2771 17 272
[G‑34] Not using the named return variables anywhere in the function is confusing 1 -

Total: 429 instances over 34 issues with 155793 gas saved

Gas totals use lower bounds of ranges and count two iterations of each for-loop. All values above are runtime, not deployment, values; deployment values are listed in the individual issue descriptions. The table above as well as its gas numbers do not include any of the excluded findings.

Invalid Issues

The issues below may be reported by other wardens, but can be ignored since either the rule or the specified instances are invalid

Issue Instances
[I‑01] Do not calculate constant variables, which will save gas 7
[I‑02] Using delete instead of setting mapping/state variable 10
[I‑03] Change public function visibility to external to save gas 18

Total: 35 instances over 3 issues

High Risk Issues

[H‑01] get_dy_underlying() is not a flash-loan-resistant price

get_dy_underlying() calculates the price based on the contract's underlying reserves, which can be manipulated by sandwiching the call with a flash loan. Therefore, using its output as a price oracle is not safe and will lead to loss of funds. Use a Chainlink oracle instead.

There is one instance of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

297:             uint256 price = curvePool.get_dy_underlying(0, 2, 1e18);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L297-L297

[H‑02] wstETH's functions operate on units of stEth, not Eth

wstETH's functions return values related to units of stEth, not units of Eth. Even after the Shanghai upgrade, the price of stETH is not the same as the prices of ETH

There is one instance of this issue:

File: contracts/lybra/pools/LybraWstETHVault.sol

49:          return (_etherPrice() * IWstETH(address(collateralAsset)).stEthPerToken()) / 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L49-L49

Medium Risk Issues

[M‑01] Contracts are vulnerable to fee-on-transfer accounting-related issues

The functions below transfer funds from the caller to the receiver via transferFrom(), but do not ensure that the actual number of tokens received is the same as the input amount to the transfer. If the token is a fee-on-transfer token, the balance after the transfer will be smaller than expected, leading to accounting issues. Even if there are checks later, related to a secondary transfer, an attacker may be able to use latent funds (e.g. mistakenly sent by another user) in order to get a free credit. One way to solve this problem is to measure the balance before and after the transfer, and use the difference as the amount, rather than the stated amount.

There is one instance of this issue:

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

72       function depositAssetToMint(uint256 assetAmount, uint256 mintAmount) external virtual {
73           require(assetAmount >= 1 ether, "Deposit should not be less than 1 stETH.");
74   
75           bool success = collateralAsset.transferFrom(msg.sender, address(this), assetAmount);
76           require(success, "TF");
77   
78           totalDepositedAsset += assetAmount;
79           depositedAsset[msg.sender] += assetAmount;
80           depositedTime[msg.sender] = block.timestamp;
81   
82           if (mintAmount > 0) {
83               _mintEUSD(msg.sender, msg.sender, mintAmount, getAssetPrice());
84           }
85           emit DepositAsset(msg.sender, address(collateralAsset), assetAmount, block.timestamp);
86:      }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L72-L86

[M‑02] Insufficient oracle validation

There is no freshness check on the timestamp of the prices fetched from the Chainlink oracle, so old prices may be used if OCR was unable to push an update in time. Add a staleness threshold number of seconds configuration parameter, and ensure that the price fetched is from within that time range.

There are 3 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

151:         (, int etherPrice, , , ) = etherPriceFeed.latestRoundData();

152:         (, int lbrPrice, , , ) = lbrPriceFeed.latestRoundData();

212:                 (, int lbrPrice, , , ) = lbrPriceFeed.latestRoundData();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L151-L151

[M‑03] Missing checks for whether the L2 Sequencer is active

Chainlink recommends that users using price oracles, check whether the Arbitrum Sequencer is active. If the sequencer goes down, the Chainlink oracles will have stale prices from before the downtime, until a new L2 OCR transaction goes through. Users who submit their transactions via the L1 Dealyed Inbox will be able to take advantage of these stale prices. Use a Chainlink oracle to determine whether the sequencer is offline or not, and don't allow operations to take place while the sequencer is offline.

There are 3 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

151:         (, int etherPrice, , , ) = etherPriceFeed.latestRoundData();

152:         (, int lbrPrice, , , ) = lbrPriceFeed.latestRoundData();

212:                 (, int lbrPrice, , , ) = lbrPriceFeed.latestRoundData();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L151-L151

[M‑04] The owner is a single point of failure and a centralization risk

Having a single EOA as the only owner of contracts is a large centralization risk and a single point of failure. A single private key may be taken in a hack, or the sole holder of the key may become unable to retrieve the key when necessary. Consider changing to a multi-signature setup, or having a role-based authorization model.

There are 17 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

84:      function setToken(address _lbr, address _eslbr) external onlyOwner {

89:      function setLBROracle(address _lbrOracle) external onlyOwner {

93:      function setPools(address[] memory _pools) external onlyOwner {

100:     function setBiddingCost(uint256 _biddingRatio) external onlyOwner {

105:     function setExtraRatio(uint256 ratio) external onlyOwner {

110:     function setPeUSDExtraRatio(uint256 ratio) external onlyOwner {

115:     function setBoost(address _boost) external onlyOwner {

119:     function setRewardsDuration(uint256 _duration) external onlyOwner {

124:     function setEthlbrStakeInfo(address _pool, address _lp) external onlyOwner {

128:     function setEUSDBuyoutAllowed(bool _bool) external onlyOwner {

226      function notifyRewardAmount(
227          uint256 amount
228:     ) external onlyOwner updateReward(address(0)) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L84-L84

File: contracts/lybra/miner/ProtocolRewardsPool.sol

52:      function setTokenAddress(address _eslbr, address _lbr, address _boost) external onlyOwner {

58:      function setGrabCost(uint256 _ratio) external onlyOwner {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L52-L52

File: contracts/lybra/miner/esLBRBoost.sol

33:      function addLockSetting(esLBRLockSetting memory setting) external onlyOwner {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L33-L33

File: contracts/lybra/miner/stakerewardV2pool.sol

121:     function setRewardsDuration(uint256 _duration) external onlyOwner {

127:     function setBoost(address _boost) external onlyOwner {

132:     function notifyRewardAmount(uint256 _amount) external onlyOwner updateReward(address(0)) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L121-L121

[M‑05] Contracts are vulnerable to rebasing accounting-related issues

Rebasing tokens are tokens that have each holder's balanceof() increase over time. Aave aTokens are an example of such tokens. If rebasing tokens are used, rewards accrue to the contract holding the tokens, and cannot be withdrawn by the original depositor. To address the issue, track 'shares' deposited on a pro-rata basis, and let shares be redeemed for their proportion of the current balance at the time of the withdrawal.

There is one instance of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

190      function getReward() external updateReward(msg.sender) {
191          uint reward = rewards[msg.sender];
192          if (reward > 0) {
193              rewards[msg.sender] = 0;
194              IEUSD EUSD = IEUSD(configurator.getEUSDAddress());
195              uint256 balance = EUSD.sharesOf(address(this));
196              uint256 eUSDShare = balance >= reward ? reward : reward - balance;
197              EUSD.transferShares(msg.sender, eUSDShare);
198              if(reward > eUSDShare) {
199                  ERC20 peUSD = ERC20(configurator.peUSD());
200                  uint256 peUSDBalance = peUSD.balanceOf(address(this));
201                  if(peUSDBalance >= reward - eUSDShare) {
202                      peUSD.transfer(msg.sender, reward - eUSDShare);
203                      emit ClaimReward(msg.sender, EUSD.getMintedEUSDByShares(eUSDShare), address(peUSD), reward - eUSDShare, block.timestamp);
204                  } else {
205                      if(peUSDBalance > 0) {
206                          peUSD.transfer(msg.sender, peUSDBalance);
207                      }
208                      ERC20 token = ERC20(configurator.stableToken());
209                      uint256 tokenAmount = (reward - eUSDShare - peUSDBalance) * token.decimals() / 1e18;
210                      token.transfer(msg.sender, tokenAmount);
211                      emit ClaimReward(msg.sender, EUSD.getMintedEUSDByShares(eUSDShare), address(token), reward - eUSDShare, block.timestamp);
212                  }
213              } else {
214                  emit ClaimReward(msg.sender, EUSD.getMintedEUSDByShares(eUSDShare), address(0), 0, block.timestamp);
215              }
216             
217          }
218:     }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L190-L218

[M‑06] Some tokens may revert when zero value transfers are made

In spite of the fact that EIP-20 states that zero-valued transfers must be accepted, some tokens, such as LEND will revert if this is attempted, which may cause transactions that involve other tokens (such as batch operations) to fully revert. Consider skipping the transfer if the amount is zero, which will also save gas.

There are 2 instances of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

207                      }
208                      ERC20 token = ERC20(configurator.stableToken());
209                      uint256 tokenAmount = (reward - eUSDShare - peUSDBalance) * token.decimals() / 1e18;
210:                     token.transfer(msg.sender, tokenAmount);

199                  ERC20 peUSD = ERC20(configurator.peUSD());
200                  uint256 peUSDBalance = peUSD.balanceOf(address(this));
201                  if(peUSDBalance >= reward - eUSDShare) {
202:                     peUSD.transfer(msg.sender, reward - eUSDShare);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L207-L210

[M‑07] Unsafe use of transfer()/transferFrom() with IERC20

Some tokens do not implement the ERC20 standard properly but are still accepted by most code that accepts ERC20 tokens. For example Tether (USDT)'s transfer() and transferFrom() functions on L1 do not return booleans as the specification requires, and instead have no return value. When these sorts of tokens are cast to IERC20, their function signatures do not match and therefore the calls made, revert (see this link for a test case). Use OpenZeppelin’s SafeERC20's safeTransfer()/safeTransferFrom() instead

There are 15 instances of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

210:                      token.transfer(msg.sender, tokenAmount);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L210

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

75:           bool success = collateralAsset.transferFrom(msg.sender, address(this), assetAmount);

107:          collateralAsset.transfer(onBehalfOf, withdrawal);

169:              collateralAsset.transfer(msg.sender, reducedAsset);

172:              collateralAsset.transfer(provider, reducedAsset - reward2keeper);

173:              collateralAsset.transfer(msg.sender, reward2keeper);

206:              collateralAsset.transfer(msg.sender, reward2keeper);

208:          collateralAsset.transfer(provider, assetAmount - reward2keeper);

242:          collateralAsset.transfer(msg.sender, collateralAmount);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L75

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

61:           collateralAsset.transferFrom(msg.sender, address(this), assetAmount);

139:              collateralAsset.transfer(msg.sender, reducedAsset);

142:              collateralAsset.transfer(provider, reducedAsset - reward2keeper);

143:              collateralAsset.transfer(msg.sender, reward2keeper);

166:          collateralAsset.transfer(msg.sender, collateralAmount);

215:          collateralAsset.transfer(_onBehalfOf, _amount);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L61

[M‑08] Return values of transfer()/transferFrom() not checked

Not all IERC20 implementations revert() when there's a failure in transfer()/transferFrom(). The function signature has a boolean return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually making a payment

There are 14 instances of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

210:                      token.transfer(msg.sender, tokenAmount);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L210

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

107:          collateralAsset.transfer(onBehalfOf, withdrawal);

169:              collateralAsset.transfer(msg.sender, reducedAsset);

172:              collateralAsset.transfer(provider, reducedAsset - reward2keeper);

173:              collateralAsset.transfer(msg.sender, reward2keeper);

206:              collateralAsset.transfer(msg.sender, reward2keeper);

208:          collateralAsset.transfer(provider, assetAmount - reward2keeper);

242:          collateralAsset.transfer(msg.sender, collateralAmount);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L107

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

61:           collateralAsset.transferFrom(msg.sender, address(this), assetAmount);

139:              collateralAsset.transfer(msg.sender, reducedAsset);

142:              collateralAsset.transfer(provider, reducedAsset - reward2keeper);

143:              collateralAsset.transfer(msg.sender, reward2keeper);

166:          collateralAsset.transfer(msg.sender, collateralAmount);

215:          collateralAsset.transfer(_onBehalfOf, _amount);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L61

Low Risk Issues

[L‑01] Missing checks for address(0x0) when assigning values to address state variables

There are 34 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

81:          GovernanceTimelock = IGovernanceTimelock(_dao);

82:          curvePool = ICurvePool(_curvePool);

99:          if (address(EUSD) == address(0)) EUSD = IEUSD(_eusd);

100:         if (address(peUSD) == address(0)) peUSD = IEUSD(_peusd);

138:         lybraProtocolRewardsPool = IProtocolRewardsPool(addr);

148:         eUSDMiningIncentives = IeUSDMiningIncentives(addr);

262:         stableToken = _token;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L81-L81

File: contracts/lybra/governance/LybraGovernance.sol

40:          esLBR = IesLBR(_esLBR);

41:          GovernanceTimelock = IGovernanceTimelock(address(timelock_));

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L40-L40

File: contracts/lybra/miner/EUSDMiningIncentives.sol

65:          configurator = Iconfigurator(_config);

66:          esLBRBoost = IesLBRBoost(_boost);

68:          etherPriceFeed = AggregatorV3Interface(_etherOracle);

69:          lbrPriceFeed = AggregatorV3Interface(_lbrOracle);

85:          LBR = _lbr;

86:          esLBR = _eslbr;

90:          lbrPriceFeed = AggregatorV3Interface(_lbrOracle);

116:         esLBRBoost = IesLBRBoost(_boost);

125:         ethlbrStakePool = _pool;

126:         ethlbrLpToken = _lp;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L65-L65

File: contracts/lybra/miner/ProtocolRewardsPool.sol

49:          configurator = Iconfigurator(_config);

53:          esLBR = IesLBR(_eslbr);

54:          LBR = IesLBR(_lbr);

55:          esLBRBoost = IesLBRBoost(_boost);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L49-L49

File: contracts/lybra/miner/stakerewardV2pool.sol

50:          stakingToken = IERC20(_stakingToken);

51:          rewardsToken = IesLBR(_rewardToken);

52:          esLBRBoost = IesLBRBoost(_boost);

128:         esLBRBoost = IesLBRBoost(_boost);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L50-L50

File: contracts/lybra/pools/LybraRETHVault.sol

24:              rkPool = IRkPool(_rkPool);

43:          rkPool = IRkPool(addr);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L24-L24

File: contracts/lybra/pools/LybraWstETHVault.sol

26:          lido = Ilido(_lido);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L26-L26

File: contracts/lybra/token/EUSD.sol

93:          configurator = Iconfigurator(_config);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L93-L93

File: contracts/lybra/token/LBR.sol

19:          configurator = Iconfigurator(_config);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L19-L19

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

56:          configurator = Iconfigurator(_config);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L56-L56

File: contracts/lybra/token/esLBR.sol

23:          configurator = Iconfigurator(_config);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L23-L23

[L‑02] decimals() is not a part of the ERC-20 standard

The decimals() function is not a part of the ERC-20 standard, and was added later as an optional extension. As such, some valid ERC20 tokens do not support this interface, so it is unsafe to blindly cast all tokens to this interface, and then call this function.

There are 2 instances of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

209:                     uint256 tokenAmount = (reward - eUSDShare - peUSDBalance) * token.decimals() / 1e18;

236:             rewardPerTokenStored = rewardPerTokenStored + (amount * 1e36 / token.decimals()) / totalStaked();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L209-L209

[L‑03] Solidity version 0.8.20 may not work on other chains due to PUSH0

The compiler for Solidity 0.8.20 switches the default target EVM version to Shanghai, which includes the new PUSH0 op code. This op code may not yet be implemented on all L2s, so deployment on these chains will fail. To work around this issue, use an earlier EVM version. While the project itself may or may not compile with 0.8.20, other projects with which it integrates, or which extend this project may, and those projects will have problems deploying these contracts/libraries.

There are 21 instances of this issue:

see instances
File: contracts/lybra/Proxy/LybraProxy.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxy.sol#L3-L3

File: contracts/lybra/Proxy/LybraProxyAdmin.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxyAdmin.sol#L3-L3

File: contracts/lybra/configuration/LybraConfigurator.sol

15:  pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L15-L15

File: contracts/lybra/governance/AdminTimelock.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/AdminTimelock.sol#L3-L3

File: contracts/lybra/governance/GovernanceTimelock.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L3-L3

File: contracts/lybra/governance/LybraGovernance.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L3-L3

File: contracts/lybra/miner/EUSDMiningIncentives.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L3-L3

File: contracts/lybra/miner/ProtocolRewardsPool.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L3-L3

File: contracts/lybra/miner/esLBRBoost.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L3-L3

File: contracts/lybra/miner/stakerewardV2pool.sol

2:   pragma solidity ^0.8;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L2-L2

File: contracts/lybra/pools/LybraRETHVault.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L3-L3

File: contracts/lybra/pools/LybraStETHVault.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L3-L3

File: contracts/lybra/pools/LybraWbETHVault.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L3-L3

File: contracts/lybra/pools/LybraWstETHVault.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L3-L3

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L3-L3

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L3-L3

File: contracts/lybra/token/EUSD.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L3-L3

File: contracts/lybra/token/LBR.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L3-L3

File: contracts/lybra/token/PeUSD.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L3-L3

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

14:  pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L14-L14

File: contracts/lybra/token/esLBR.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L3-L3

[L‑04] Loss of precision

Division by large numbers may result in the result being zero, due to solidity not supporting fractions. Consider requiring a minimum amount for the numerator to ensure that it is always larger than the denominator

There are 50 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

303:                  uint256 amount = curvePool.exchange_underlying(0, 2, balance, balance * price * 998 / 1e21);

357:          return (EUSD.totalSupply() * maxStableRatio) / 10_000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L303

File: contracts/lybra/governance/LybraGovernance.sol

52:           return esLBR.getPastTotalSupply(timepoint) / 3;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L52

File: contracts/lybra/miner/esLBRBoost.sol

67:               return ((boostEndTime - userUpdatedAt) * maxBoost) / (time - userUpdatedAt);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L67

File: contracts/lybra/miner/EUSDMiningIncentives.sol

153:          uint256 etherInLp = (IEUSD(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2).balanceOf(ethlbrLpToken) * uint(etherPrice)) / 1e8;

154:          uint256 lbrInLp = (IEUSD(LBR).balanceOf(ethlbrLpToken) * uint(lbrPrice)) / 1e8;

156:          return (userStaked * (lbrInLp + etherInLp)) / totalLp;

168:          return rewardPerTokenStored + (rewardRatio * (lastTimeRewardApplicable() - updatedAt) * 1e18) / totalStaked();

185:          return ((stakedOf(_account) * getBoost(_account) * (rewardPerToken() - userRewardPerTokenPaid[_account])) / 1e38) + rewards[_account];

210:              uint256 biddingFee = (reward * biddingFeeRatio) / 10000;

213:                  biddingFee = biddingFee * uint256(lbrPrice) / 1e8;

231:              rewardRatio = amount / duration;

234:              rewardRatio = (amount + remainingRewards) / duration;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L153

File: contracts/lybra/miner/ProtocolRewardsPool.sol

134:          LBR.burn(msg.sender, (amount * grabFeeRatio) / 10000);

152:          amount = (a * (75e18 - ((time2fullRedemption[user] - block.timestamp) * 70e18) / (exitCycle / 1 days - 3) / 1 days)) / 100e18;

168:          return ((stakedOf(_account) * (rewardPerTokenStored - userRewardPerTokenPaid[_account])) / 1e18) + rewards[_account];

209:                      uint256 tokenAmount = (reward - eUSDShare - peUSDBalance) * token.decimals() / 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L134

File: contracts/lybra/miner/stakerewardV2pool.sol

107:          return ((balanceOf[_account] * getBoost(_account) * (rewardPerToken() - userRewardPerTokenPaid[_account])) / 1e38) + rewards[_account];

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L107

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

115:          withdrawal = block.timestamp - 3 days >= depositedTime[user] ? amount : (amount * 999) / 1000;

156:          uint256 onBehalfOfCollateralRatio = (depositedAsset[onBehalfOf] * assetPrice * 100) / borrowed[onBehalfOf];

161:          uint256 eusdAmount = (assetAmount * assetPrice) / 1e18;

171:              reward2keeper = (reducedAsset * configurator.vaultKeeperRatio(address(this))) / 110;

195:              eusdAmount = (eusdAmount * 1e20) / onBehalfOfCollateralRatio;

205:              reward2keeper = ((assetAmount * configurator.vaultKeeperRatio(address(this))) * 1e18) / onBehalfOfCollateralRatio;

236:          uint256 providerCollateralRatio = (depositedAsset[provider] * assetPrice * 100) / borrowed[provider];

239:          uint256 collateralAmount = (((eusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;

292:          if (((depositedAsset[_user] * _assetPrice * 100) / borrowed[_user]) < configurator.getSafeCollateralRatio(address(this))) revert("collateralRatio is Below safeCollateralRatio");

301:          return (poolTotalEUSDCirculation * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - lastReportTime)) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L115

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

127:          uint256 onBehalfOfCollateralRatio = (depositedAsset[onBehalfOf] * assetPrice * 100) / getBorrowedOf(onBehalfOf);

132:          uint256 peusdAmount = (assetAmount * assetPrice) / 1e18;

141:              reward2keeper = (reducedAsset * configurator.vaultKeeperRatio(address(this))) / 110;

161:          uint256 providerCollateralRatio = (depositedAsset[provider] * assetPrice * 100) / borrowed[provider];

164:          uint256 collateralAmount = (((peusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;

226:          if (((depositedAsset[user] * price * 100) / getBorrowedOf(user)) < configurator.getSafeCollateralRatio(address(this))) 

238:          return (borrowed[user] * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - feeUpdatedAt[user])) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L127

File: contracts/lybra/pools/LybraRETHVault.sol

47:           return (_etherPrice() * IRETH(address(collateralAsset)).getExchangeRatio()) / 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L47

File: contracts/lybra/pools/LybraStETHVault.sol

66:           uint256 payAmount = (((realAmount * getAssetPrice()) / 1e18) * getDutchAuctionDiscountPrice()) / 10000;

104:          return 10000 - (time / 30 minutes - 1) * 100;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L66

File: contracts/lybra/pools/LybraWbETHVault.sol

35:           return (_etherPrice() * IWBETH(address(collateralAsset)).exchangeRatio()) / 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L35

File: contracts/lybra/pools/LybraWstETHVault.sol

49:           return (_etherPrice() * IWstETH(address(collateralAsset)).stEthPerToken()) / 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L49

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

117:          uint256 share = (userConvertInfo[msg.sender].depositedEUSDShares * peusdAmount) / userConvertInfo[msg.sender].mintedPeUSD;

157:          return (share * configurator.flashloanFee()) / 10_000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L117

[L‑05] Array lengths not checked

If the length of the arrays are not required to be of the same length, user operations may not be fully executed due to a mismatch in the number of items iterated over, versus the number of items provided in the second array

There is one instance of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

235:      function setTokenMiner(address[] calldata _contracts, bool[] calldata _bools) external checkRole(TIMELOCK) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L235

[L‑06] Use Ownable2Step rather than Ownable

Ownable2Step and Ownable2StepUpgradeable prevent the contract ownership from mistakenly being transferred to an address that cannot handle it (e.g. due to a typo in the address), by requiring that the recipient of the owner permissions actively accept via a contract call of its own.

There are 4 instances of this issue:

File: contracts/lybra/miner/esLBRBoost.sol

7:    contract esLBRBoost is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L7

File: contracts/lybra/miner/EUSDMiningIncentives.sol

27:   contract EUSDMiningIncentives is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L27

File: contracts/lybra/miner/ProtocolRewardsPool.sol

24:   contract ProtocolRewardsPool is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L24

File: contracts/lybra/miner/stakerewardV2pool.sol

16    contract StakingRewardsV2 is Ownable {
17:       // Immutable variables for staking and rewards tokens

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L16-L17

[L‑07] Upgradeable contract is missing a __gap[50] storage variable to allow for new storage variables in later versions

See this link for a description of this storage variable. While some contracts may not currently be sub-classed, adding the variable now protects against forgetting to add it in the future.

There is one instance of this issue:

File: contracts/lybra/Proxy/LybraProxy.sol

8:    contract LybraProxy is TransparentUpgradeableProxy {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxy.sol#L8

Non-critical Issues

[N‑01] Events are missing sender information

When an action is triggered based on a user's action, not being able to filter based on who triggered the action makes event processing a lot more cumbersome. Including the msg.sender the events of these types of action will make events much more useful to end users, especially when msg.sender is not tx.origin.

There are 3 instances of this issue:

File: contracts/lybra/pools/LybraStETHVault.sol

89:              emit FeeDistribution(address(configurator), payAmount, block.timestamp);

83:              emit FeeDistribution(address(configurator), income, block.timestamp);

94:          emit LSDValueCaptured(realAmount, payAmount, getDutchAuctionDiscountPrice(), block.timestamp);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L89-L89

[N‑02] Variables need not be initialized to zero

The default value for variables is zero, so initializing them to zero is superfluous.

There are 4 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

236:         for (uint256 i = 0; i < _contracts.length; i++) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L236-L236

File: contracts/lybra/miner/EUSDMiningIncentives.sol

94:          for (uint i = 0; i < _pools.length; i++) {

138:         for (uint i = 0; i < pools.length; i++) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L94-L94

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

30:      uint8 immutable vaultType = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L30-L30

[N‑03] Consider using named mappings

Consider moving to solidity version 0.8.18 or later, and using named mappings to make it easier to understand the purpose of each mapping

There are 37 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

38:      mapping(address => bool) public mintVault;

39:      mapping(address => uint256) public mintVaultMaxSupply;

40:      mapping(address => bool) public vaultMintPaused;

41:      mapping(address => bool) public vaultBurnPaused;

42:      mapping(address => uint256) vaultSafeCollateralRatio;

43:      mapping(address => uint256) vaultBadCollateralRatio;

44:      mapping(address => uint256) public vaultMintFeeApy;

45:      mapping(address => uint256) public vaultKeeperRatio;

46:      mapping(address => bool) redemptionProvider;

47:      mapping(address => bool) public tokenMiner;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L38-L38

File: contracts/lybra/governance/LybraGovernance.sol

28:          mapping(address => Receipt)  receipts;

29:          mapping(uint8 => uint256) supportVotes;

33:      mapping (uint256 => ProposalExtraData) public proposalData;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L28-L28

File: contracts/lybra/miner/EUSDMiningIncentives.sol

46:      mapping(address => uint256) public userRewardPerTokenPaid;

48:      mapping(address => uint256) public rewards;

49:      mapping(address => uint256) public userUpdatedAt;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L46-L46

File: contracts/lybra/miner/ProtocolRewardsPool.sol

33:      mapping(address => uint) public userRewardPerTokenPaid;

35:      mapping(address => uint) public rewards;

36:      mapping(address => uint) public time2fullRedemption;

37:      mapping(address => uint) public unstakeRatio;

38:      mapping(address => uint) public lastWithdrawTime;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L33-L33

File: contracts/lybra/miner/esLBRBoost.sol

9:       mapping(address => LockStatus) public userLockStatus;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L9-L9

File: contracts/lybra/miner/stakerewardV2pool.sol

33:      mapping(address => uint256) public userRewardPerTokenPaid;

35:      mapping(address => uint256) public rewards;

36:      mapping(address => uint256) public userUpdatedAt;

41:      mapping(address => uint256) public balanceOf;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L33-L33

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

28:      mapping(address => uint256) public depositedAsset;

29:      mapping(address => uint256) borrowed;

32:      mapping(address => uint256) depositedTime;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L28-L28

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

21:      mapping(address => uint256) public depositedAsset;

22:      mapping(address => uint256) borrowed;

23:      mapping(address => uint256) feeStored;

24:      mapping(address => uint256) feeUpdatedAt;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L21-L21

File: contracts/lybra/token/EUSD.sol

51:      mapping(address => uint256) private shares;

56:      mapping(address => mapping(address => uint256)) private allowances;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L51-L51

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

33:      mapping(address => ConvertInfo) public userConvertInfo;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L33-L33

[N‑04] Non-external/public variable and function names should begin with an underscore

According to the Solidity Style Guide, Non-external/public variable and function names should begin with an underscore

There are 29 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

42:      mapping(address => uint256) vaultSafeCollateralRatio;

43:      mapping(address => uint256) vaultBadCollateralRatio;

46:      mapping(address => bool) redemptionProvider;

58:      uint256 maxStableRatio = 5_000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L42-L42

File: contracts/lybra/miner/EUSDMiningIncentives.sol

55:      AggregatorV3Interface internal etherPriceFeed;

56:      AggregatorV3Interface internal lbrPriceFeed;

132:     function totalStaked() internal view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L55-L55

File: contracts/lybra/miner/ProtocolRewardsPool.sol

39:      uint256 immutable exitCycle = 90 days;

64:      function totalStaked() internal view returns (uint256) {

69:      function stakedOf(address staker) internal view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L39-L39

File: contracts/lybra/pools/LybraRETHVault.sol

18:      IRkPool rkPool = IRkPool(0xDD3f50F8A6CafbE9b31a427582963f465E745AF8);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L18-L18

File: contracts/lybra/pools/LybraWstETHVault.sol

22:      Ilido immutable lido;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L22-L22

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

22:      IPriceFeed immutable etherOracle;

29:      mapping(address => uint256) borrowed;

30:      uint8 immutable vaultType = 0;

32:      mapping(address => uint256) depositedTime;

114:     function checkWithdrawal(address user, uint256 amount) internal view returns (uint256 withdrawal) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L22-L22

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

18:      uint8 immutable vaultType = 1;

19:      IPriceFeed immutable etherOracle;

22:      mapping(address => uint256) borrowed;

23:      mapping(address => uint256) feeStored;

24:      mapping(address => uint256) feeUpdatedAt;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L18-L18

File: contracts/lybra/token/EUSD.sol

51:      mapping(address => uint256) private shares;

56:      mapping(address => mapping(address => uint256)) private allowances;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L51-L51

File: contracts/lybra/token/LBR.sol

15:      uint256 maxSupply = 100_000_000 * 1e18;

16:      uint internal immutable ld2sdRatio;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L15-L15

File: contracts/lybra/token/PeUSD.sol

9:       uint internal immutable ld2sdRatio;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L9-L9

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

32:      uint internal immutable ld2sdRatio;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L32-L32

File: contracts/lybra/token/esLBR.sol

20:      uint256 maxSupply = 100_000_000 * 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L20-L20

[N‑05] Large numeric literals should use underscores for readability

There are 15 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

298:             if(!premiumTradingEnabled || price <= 1005000) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L298-L298

File: contracts/lybra/miner/EUSDMiningIncentives.sol

189:         return (stakedLBRLpValue(user) * 10000) / stakedOf(user) < 500;

210:             uint256 biddingFee = (reward * biddingFeeRatio) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L189-L189

File: contracts/lybra/miner/ProtocolRewardsPool.sol

134:         LBR.burn(msg.sender, (amount * grabFeeRatio) / 10000);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L134-L134

File: contracts/lybra/pools/LybraStETHVault.sol

66:          uint256 payAmount = (((realAmount * getAssetPrice()) / 1e18) * getDutchAuctionDiscountPrice()) / 10000;

103:         if (time < 30 minutes) return 10000;

104:         return 10000 - (time / 30 minutes - 1) * 100;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L66-L66

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

239:         uint256 collateralAmount = (((eusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;

301:         return (poolTotalEUSDCirculation * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - lastReportTime)) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L239-L239

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

164:         uint256 collateralAmount = (((peusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;

238:         return (borrowed[user] * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - feeUpdatedAt[user])) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L164-L164

[N‑06] Constants in comparisons should appear on the left side

Doing so will prevent typo bugs

There are 33 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

187:         require(newFee <= 500, "Max Redemption Fee is 5%");

199:         if(IVault(pool).vaultType() == 0) {

214:         require(newApy <= 200, "Borrow APY cannot exceed 2%");

225:         require(newRatio <= 5, "Max Keeper reward is 5%");

247:         require(_ratio <= 10_000, "The maximum value is 10000");

291:         if(peUSDBalance >= 1e21) {

298:             if(!premiumTradingEnabled || price <= 1005000) {

334:         if (vaultSafeCollateralRatio[pool] == 0) return 160 * 1e18;

339:         if(vaultBadCollateralRatio[pool] == 0) return vaultSafeCollateralRatio[pool] - 1e19;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L187-L187

File: contracts/lybra/governance/LybraGovernance.sol

79:          require(support <= 2, "GovernorBravo::castVoteInternal: invalid vote type");

82:          require(receipt.hasVoted == false, "GovernorBravo::castVoteInternal: voter already voted");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L79-L79

File: contracts/lybra/miner/EUSDMiningIncentives.sol

101:         require(_biddingRatio <= 8000, "BCE");

106:         require(ratio <= 1e20, "BCE");

111:         require(ratio <= 1e20, "BCE");

141:             if (pool.getVaultType() == 1) {

164:         if (totalStaked() == 0) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L101-L101

File: contracts/lybra/miner/ProtocolRewardsPool.sol

59:          require(_ratio <= 8000, "BCE");

151:         if (a == 0) return 0;

229:         if (totalStaked() == 0) return;

231:         if(tokenType == 0) {

234:         } else if(tokenType == 1) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L59-L59

File: contracts/lybra/miner/stakerewardV2pool.sol

75:          if (totalSupply == 0) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L75-L75

File: contracts/lybra/pools/LybraRETHVault.sol

28:          require(msg.value >= 1 ether, "DNL");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L28-L28

File: contracts/lybra/pools/LybraStETHVault.sol

38:          require(msg.value >= 1 ether, "DNL");

76:              if (sharesAmount == 0) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L38-L38

File: contracts/lybra/pools/LybraWbETHVault.sol

21:          require(msg.value >= 1 ether, "DNL");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L21-L21

File: contracts/lybra/pools/LybraWstETHVault.sol

30:          require(msg.value >= 1 ether, "DNL");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L30-L30

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

73:          require(assetAmount >= 1 ether, "Deposit should not be less than 1 stETH.");

194:         if (onBehalfOfCollateralRatio >= 1e20) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L73-L73

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

59:          require(assetAmount >= 1 ether, "Deposit should not be less than 1 collateral asset.");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L59-L59

File: contracts/lybra/token/EUSD.sol

301:         if (totalMintedEUSD == 0) {

312:         if (_totalShares == 0) {

415:         if (sharesAmount == 0) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L301-L301

[N‑07] Consider disabling renounceOwnership()

If the plan for your project does not include eventually giving up all ownership control, consider overwriting OpenZeppelin's Ownable's renounceOwnership() function in order to disable it.

There are 4 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

27:  contract EUSDMiningIncentives is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L27-L27

File: contracts/lybra/miner/ProtocolRewardsPool.sol

24:  contract ProtocolRewardsPool is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L24-L24

File: contracts/lybra/miner/esLBRBoost.sol

7:   contract esLBRBoost is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L7-L7

File: contracts/lybra/miner/stakerewardV2pool.sol

16:  contract StakingRewardsV2 is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L16-L16

[N‑08] else-block not required

One level of nesting can be removed by not having an else block when the if-block returns, and if (foo) { return 1; } else { return 2; } becomes if (foo) { return 1; } return 2;

There are 3 instances of this issue:

File: contracts/lybra/miner/esLBRBoost.sol

63           if (finishAt <= boostEndTime || block.timestamp <= boostEndTime) {
64               return maxBoost;
65           } else {
66               uint256 time = block.timestamp > finishAt ? finishAt : block.timestamp;
67               return ((boostEndTime - userUpdatedAt) * maxBoost) / (time - userUpdatedAt);
68:          }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L63-L68

File: contracts/lybra/token/EUSD.sol

301          if (totalMintedEUSD == 0) {
302              return 0;
303          } else {
304              return _EUSDAmount.mul(_totalShares).div(totalMintedEUSD);
305:         }

312          if (_totalShares == 0) {
313              return 0;
314          } else {
315              return _sharesAmount.mul(_totalSupply).div(_totalShares);
316:         }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L301-L305

[N‑09] addresss shouldn't be hard-coded

It is often better to declare addresses as immutable, and assign them via constructor arguments. This allows the code to remain the same across deployments on different networks, and avoids recompilation when addresses need to change.

There are 2 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

153:         uint256 etherInLp = (IEUSD(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2).balanceOf(ethlbrLpToken) * uint(etherPrice)) / 1e8;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L153-L153

File: contracts/lybra/pools/LybraRETHVault.sol

18:      IRkPool rkPool = IRkPool(0xDD3f50F8A6CafbE9b31a427582963f465E745AF8);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L18-L18

[N‑10] Interfaces should be defined in separate files from their usage

The interfaces below should be defined in separate files, so that it's easier for future projects to import them, and to avoid duplication later on if they need to be used elsewhere in the project

There are 17 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

20   interface IProtocolRewardsPool {
21       function notifyRewardAmount(uint256 amount, uint256 tokenType) external;
22:  }

24   interface IeUSDMiningIncentives {
25       function refreshReward(address user) external;
26:  }

28   interface IVault {
29       function vaultType() external view returns (uint8);
30:  }

32   interface ICurvePool{
33       function get_dy_underlying(int128 i, int128 j, uint256 dx) external view returns (uint256);
34       function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) external returns(uint256);
35:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L20-L22

File: contracts/lybra/miner/EUSDMiningIncentives.sol

19   interface IesLBRBoost {
20       function getUserBoost(
21           address user,
22           uint256 userUpdatedAt,
23           uint256 finishAt
24       ) external view returns (uint256);
25:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L19-L25

File: contracts/lybra/miner/ProtocolRewardsPool.sol

18   interface IesLBRBoost {
19       function getUnlockTime(
20           address user
21       ) external view returns (uint256 unlockTime);
22:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L18-L22

File: contracts/lybra/miner/stakerewardV2pool.sol

8    interface IesLBRBoost {
9        function getUserBoost(
10           address user,
11           uint256 userUpdatedAt,
12           uint256 finishAt
13       ) external view returns (uint256);
14:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L8-L14

File: contracts/lybra/pools/LybraRETHVault.sol

9    interface IRETH {
10       function getExchangeRatio() external view returns (uint256);
11:  }

13   interface IRkPool {
14       function deposit() external payable;
15:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L9-L11

File: contracts/lybra/pools/LybraStETHVault.sol

8    interface Ilido {
9        function submit(address _referral) external payable returns (uint256 StETH);
10:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L8-L10

File: contracts/lybra/pools/LybraWbETHVault.sol

9    interface IWBETH {
10       function exchangeRatio() external view returns (uint256);
11   
12       function deposit(address referral) external payable;
13:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L9-L13

File: contracts/lybra/pools/LybraWstETHVault.sol

9    interface IWstETH {
10       function stEthPerToken() external view returns (uint256);
11   
12       function wrap(uint256 _stETHAmount) external returns (uint256);
13:  }

15   interface Ilido {
16       function submit(address _referral) external payable returns (uint256 StETH);
17   
18       function approve(address spender, uint256 amount) external returns (bool);
19:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L9-L13

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

13   interface IPriceFeed {
14       function fetchPrice() external returns (uint256);
15:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L13-L15

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

9    interface IPriceFeed {
10       function fetchPrice() external returns (uint256);
11:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L9-L11

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

21   interface FlashBorrower {
22       /// @notice Flash loan callback
23       /// @param amount The amount of tokens received
24       /// @param data Forwarded data from the flash loan request
25       /// @dev Called after receiving the requested flash loan, should return tokens + any fees before the end of the transaction
26       function onFlashLoan(uint256 amount, bytes calldata data) external;
27:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L21-L27

File: contracts/lybra/token/esLBR.sol

13   interface IProtocolRewardsPool {
14       function refreshReward(address user) external;
15:  }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L13-L15

[N‑11] Imports could be organized more systematically

The contract's interface should be imported first, followed by each of the interfaces it uses, followed by all other files. The examples below do not follow this layout.

There is one instance of this issue:

File: contracts/lybra/token/EUSD.sol

6:   import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L6-L6

[N‑12] Mixed usage of int/uint with int256/uint256

int256/uint256 are the preferred type names (they're what are used for function signatures), so they should be used consistently

There are 40 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

94:          for (uint i = 0; i < _pools.length; i++) {

140:             uint borrowed = pool.getBorrowedOf(user);

138:         for (uint i = 0; i < pools.length; i++) {

151:         (, int etherPrice, , , ) = etherPriceFeed.latestRoundData();

152:         (, int lbrPrice, , , ) = lbrPriceFeed.latestRoundData();

153:         uint256 etherInLp = (IEUSD(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2).balanceOf(ethlbrLpToken) * uint(etherPrice)) / 1e8;

154:         uint256 lbrInLp = (IEUSD(LBR).balanceOf(ethlbrLpToken) * uint(lbrPrice)) / 1e8;

212:                 (, int lbrPrice, , , ) = lbrPriceFeed.latestRoundData();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L94-L94

File: contracts/lybra/miner/ProtocolRewardsPool.sol

31:      uint public rewardPerTokenStored;

167:     function earned(address _account) public view returns (uint) {

191:         uint reward = rewards[msg.sender];

227:     function notifyRewardAmount(uint amount, uint tokenType) external {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L31-L31

File: contracts/lybra/token/LBR.sol

16:      uint internal immutable ld2sdRatio;

38:      function circulatingSupply() public view virtual override returns (uint) {

49:      function _debitFrom(address _from, uint16, bytes32, uint _amount) internal virtual override returns (uint) {

56:      function _creditTo(uint16, address _toAddress, uint _amount) internal virtual override returns (uint) {

61:      function _transferFrom(address _from, address _to, uint _amount) internal virtual override returns (uint) {

70:      function _ld2sdRatio() internal view virtual override returns (uint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L16-L16

File: contracts/lybra/token/PeUSD.sol

9:       uint internal immutable ld2sdRatio;

20:      function circulatingSupply() public view virtual override returns (uint) {

31:      function _debitFrom(address _from, uint16, bytes32, uint _amount) internal virtual override returns (uint) {

38:      function _creditTo(uint16, address _toAddress, uint _amount) internal virtual override returns (uint) {

43:      function _transferFrom(address _from, address _to, uint _amount) internal virtual override returns (uint) {

52:      function _ld2sdRatio() internal view virtual override returns (uint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L9-L9

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

32:      uint internal immutable ld2sdRatio;

171:     function circulatingSupply() public view virtual override returns (uint) {

184:     function _debitFrom(address _from, uint16, bytes32, uint _amount) internal virtual override returns (uint) {

191:     function _creditTo(uint16, address _toAddress, uint _amount) internal virtual override returns (uint) {

196:     function _transferFrom(address _from, address _to, uint _amount) internal virtual override returns (uint) {

205:     function _ld2sdRatio() internal view virtual override returns (uint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L32-L32

[N‑13] public functions not called by the contract should be declared external instead

Contracts are allowed to override their parents' functions and change the visibility from external to public.

There are 13 instances of this issue:

File: contracts/lybra/governance/GovernanceTimelock.sol

29:       function checkOnlyRole(bytes32 role, address _sender) public view  returns(bool){

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L29

File: contracts/lybra/token/EUSD.sol

99:       function name() public pure returns (string memory) {

107:      function symbol() public pure returns (string memory) {

134:      function balanceOf(address _account) public view returns (uint256) {

153:      function transfer(address _recipient, uint256 _amount) public returns (bool) {

200:      function approve(address _spender, uint256 _amount) public returns (bool) {

226:      function transferFrom(address from, address to, uint256 amount) public returns (bool) {

248:      function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) {

285:      function getTotalShares() public view returns (uint256) {

292:      function sharesOf(address _account) public view returns (uint256) {

334:      function transferShares(address _recipient, uint256 _sharesAmount) public returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L99

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

129:      function executeFlashloan(FlashBorrower receiver, uint256 eusdAmount, bytes calldata data) public payable {

165       function getAccruedEUSDInterest(
166           address user
167:      ) public view returns (uint256 eusdAmount) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L129

[N‑14] constants should be defined rather than using magic numbers

Even assembly can benefit from using readable constants instead of hex/numeric literals

There are 118 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit 130
/// @audit 1e18
/// @audit 150
/// @audit 1e19
127:          require(newRatio >= 130 * 1e18 && newRatio <= 150 * 1e18 && newRatio <= vaultSafeCollateralRatio[pool] + 1e19, "LNA");

/// @audit 500
187:          require(newFee <= 500, "Max Redemption Fee is 5%");

/// @audit 160
/// @audit 1e18
200:              require(newRatio >= 160 * 1e18, "eUSD vault safe collateralRatio should more than 160%");

/// @audit 1e19
202:              require(newRatio >= vaultBadCollateralRatio[pool] + 1e19, "PeUSD vault safe collateralRatio should more than bad collateralRatio");

/// @audit 200
214:          require(newApy <= 200, "Borrow APY cannot exceed 2%");

/// @audit 5
225:          require(newRatio <= 5, "Max Keeper reward is 5%");

/// @audit 10_000
247:          require(_ratio <= 10_000, "The maximum value is 10000");

/// @audit 10_000
254:          if (fee > 10_000) revert('EL');

/// @audit 1e21
291:          if(peUSDBalance >= 1e21) {

/// @audit 1e21
296:          if (balance > 1e21) {

/// @audit 1e18
297:              uint256 price = curvePool.get_dy_underlying(0, 2, 1e18);

/// @audit 1005000
298:              if(!premiumTradingEnabled || price <= 1005000) {

/// @audit 998
/// @audit 1e21
303:                  uint256 amount = curvePool.exchange_underlying(0, 2, balance, balance * price * 998 / 1e21);

/// @audit 160
/// @audit 1e18
334:          if (vaultSafeCollateralRatio[pool] == 0) return 160 * 1e18;

/// @audit 1e19
339:          if(vaultBadCollateralRatio[pool] == 0) return vaultSafeCollateralRatio[pool] - 1e19;

/// @audit 10_000
357:          return (EUSD.totalSupply() * maxStableRatio) / 10_000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L127

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit 3
52:           return esLBR.getPastTotalSupply(timepoint) / 3;

/// @audit 3
144:           return 3;

/// @audit 1e23
173:          return 1e23;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L52

File: contracts/lybra/miner/esLBRBoost.sol

/// @audit 30
/// @audit 20
/// @audit 1e18
26:           esLBRLockSettings.push(esLBRLockSetting(30 days, 20 * 1e18));

/// @audit 90
/// @audit 30
/// @audit 1e18
27:           esLBRLockSettings.push(esLBRLockSetting(90 days, 30 * 1e18));

/// @audit 180
/// @audit 50
/// @audit 1e18
28:           esLBRLockSettings.push(esLBRLockSetting(180 days, 50 * 1e18));

/// @audit 365
/// @audit 100
/// @audit 1e18
29:           esLBRLockSettings.push(esLBRLockSetting(365 days, 100 * 1e18));

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L26

File: contracts/lybra/miner/EUSDMiningIncentives.sol

/// @audit 8000
101:          require(_biddingRatio <= 8000, "BCE");

/// @audit 1e20
106:          require(ratio <= 1e20, "BCE");

/// @audit 1e20
111:          require(ratio <= 1e20, "BCE");

/// @audit 1e20
142:                  borrowed = borrowed * (1e20 + peUSDExtraRatio) / 1e20;

/// @audit 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
/// @audit 1e8
153:          uint256 etherInLp = (IEUSD(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2).balanceOf(ethlbrLpToken) * uint(etherPrice)) / 1e8;

/// @audit 1e8
154:          uint256 lbrInLp = (IEUSD(LBR).balanceOf(ethlbrLpToken) * uint(lbrPrice)) / 1e8;

/// @audit 1e18
168:          return rewardPerTokenStored + (rewardRatio * (lastTimeRewardApplicable() - updatedAt) * 1e18) / totalStaked();

/// @audit 100
/// @audit 1e18
181:          return 100 * 1e18 + redemptionBoost + esLBRBoost.getUserBoost(_account, userUpdatedAt[_account], finishAt);

/// @audit 1e38
185:          return ((stakedOf(_account) * getBoost(_account) * (rewardPerToken() - userRewardPerTokenPaid[_account])) / 1e38) + rewards[_account];

/// @audit 10000
/// @audit 500
189:          return (stakedLBRLpValue(user) * 10000) / stakedOf(user) < 500;

/// @audit 10000
210:              uint256 biddingFee = (reward * biddingFeeRatio) / 10000;

/// @audit 1e8
213:                  biddingFee = biddingFee * uint256(lbrPrice) / 1e8;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L101

File: contracts/lybra/miner/ProtocolRewardsPool.sol

/// @audit 8000
59:           require(_ratio <= 8000, "BCE");

/// @audit 3
114:          require(block.timestamp + exitCycle - 3 days > time2fullRedemption[msg.sender], "ENW");

/// @audit 10000
134:          LBR.burn(msg.sender, (amount * grabFeeRatio) / 10000);

/// @audit 75e18
/// @audit 70e18
/// @audit 3
/// @audit 100e18
152:          amount = (a * (75e18 - ((time2fullRedemption[user] - block.timestamp) * 70e18) / (exitCycle / 1 days - 3) / 1 days)) / 100e18;

/// @audit 1e18
168:          return ((stakedOf(_account) * (rewardPerTokenStored - userRewardPerTokenPaid[_account])) / 1e18) + rewards[_account];

/// @audit 1e18
209:                      uint256 tokenAmount = (reward - eUSDShare - peUSDBalance) * token.decimals() / 1e18;

/// @audit 1e18
233:              rewardPerTokenStored = rewardPerTokenStored + (share * 1e18) / totalStaked();

/// @audit 1e36
236:              rewardPerTokenStored = rewardPerTokenStored + (amount * 1e36 / token.decimals()) / totalStaked();

/// @audit 1e18
238:              rewardPerTokenStored = rewardPerTokenStored + (amount * 1e18) / totalStaked();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L59

File: contracts/lybra/miner/stakerewardV2pool.sol

/// @audit 1e18
79:           return rewardPerTokenStored + (rewardRatio * (lastTimeRewardApplicable() - updatedAt) * 1e18) / totalSupply;

/// @audit 100
/// @audit 1e18
102:          return 100 * 1e18 + esLBRBoost.getUserBoost(_account, userUpdatedAt[_account], finishAt);

/// @audit 1e38
107:          return ((balanceOf[_account] * getBoost(_account) * (rewardPerToken() - userRewardPerTokenPaid[_account])) / 1e38) + rewards[_account];

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L79

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

/// @audit 3
/// @audit 999
/// @audit 1000
115:          withdrawal = block.timestamp - 3 days >= depositedTime[user] ? amount : (amount * 999) / 1000;

/// @audit 100
156:          uint256 onBehalfOfCollateralRatio = (depositedAsset[onBehalfOf] * assetPrice * 100) / borrowed[onBehalfOf];

/// @audit 1e18
161:          uint256 eusdAmount = (assetAmount * assetPrice) / 1e18;

/// @audit 11
164:          uint256 reducedAsset = (assetAmount * 11) / 10;

/// @audit 110
171:              reward2keeper = (reducedAsset * configurator.vaultKeeperRatio(address(this))) / 110;

/// @audit 100
189:          require((totalDepositedAsset * assetPrice * 100) / poolTotalEUSDCirculation < badCollateralRatio, "overallCollateralRatio should below 150%");

/// @audit 100
190:          uint256 onBehalfOfCollateralRatio = (depositedAsset[onBehalfOf] * assetPrice * 100) / borrowed[onBehalfOf];

/// @audit 125
/// @audit 1e18
191:          require(onBehalfOfCollateralRatio < 125 * 1e18, "borrowers collateralRatio should below 125%");

/// @audit 1e18
193:          uint256 eusdAmount = (assetAmount * assetPrice) / 1e18;

/// @audit 1e20
194:          if (onBehalfOfCollateralRatio >= 1e20) {

/// @audit 1e20
195:              eusdAmount = (eusdAmount * 1e20) / onBehalfOfCollateralRatio;

/// @audit 1e20
/// @audit 1e18
204:          if (msg.sender != provider && onBehalfOfCollateralRatio >= 1e20 + configurator.vaultKeeperRatio(address(this)) * 1e18) {

/// @audit 1e18
205:              reward2keeper = ((assetAmount * configurator.vaultKeeperRatio(address(this))) * 1e18) / onBehalfOfCollateralRatio;

/// @audit 100
236:          uint256 providerCollateralRatio = (depositedAsset[provider] * assetPrice * 100) / borrowed[provider];

/// @audit 100
/// @audit 1e18
237:          require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");

/// @audit 1e18
/// @audit 10000
239:          uint256 collateralAmount = (((eusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;

/// @audit 100
292:          if (((depositedAsset[_user] * _assetPrice * 100) / borrowed[_user]) < configurator.getSafeCollateralRatio(address(this))) revert("collateralRatio is Below safeCollateralRatio");

/// @audit 86400
/// @audit 365
/// @audit 10000
301:          return (poolTotalEUSDCirculation * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - lastReportTime)) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L115

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit 100
127:          uint256 onBehalfOfCollateralRatio = (depositedAsset[onBehalfOf] * assetPrice * 100) / getBorrowedOf(onBehalfOf);

/// @audit 1e18
132:          uint256 peusdAmount = (assetAmount * assetPrice) / 1e18;

/// @audit 11
135:          uint256 reducedAsset = (assetAmount * 11) / 10;

/// @audit 110
141:              reward2keeper = (reducedAsset * configurator.vaultKeeperRatio(address(this))) / 110;

/// @audit 100
161:          uint256 providerCollateralRatio = (depositedAsset[provider] * assetPrice * 100) / borrowed[provider];

/// @audit 100
/// @audit 1e18
162:          require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");

/// @audit 1e18
/// @audit 10000
164:          uint256 collateralAmount = (((peusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;

/// @audit 100
226:          if (((depositedAsset[user] * price * 100) / getBorrowedOf(user)) < configurator.getSafeCollateralRatio(address(this))) 

/// @audit 86400
/// @audit 365
/// @audit 10000
238:          return (borrowed[user] * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - feeUpdatedAt[user])) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L127

File: contracts/lybra/pools/LybraRETHVault.sol

/// @audit 1e18
47:           return (_etherPrice() * IRETH(address(collateralAsset)).getExchangeRatio()) / 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L47

File: contracts/lybra/pools/LybraStETHVault.sol

/// @audit 1e18
/// @audit 10000
66:           uint256 payAmount = (((realAmount * getAssetPrice()) / 1e18) * getDutchAuctionDiscountPrice()) / 10000;

/// @audit 30
/// @audit 10000
103:          if (time < 30 minutes) return 10000;

/// @audit 10000
/// @audit 30
/// @audit 100
104:          return 10000 - (time / 30 minutes - 1) * 100;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L66

File: contracts/lybra/pools/LybraWbETHVault.sol

/// @audit 1e18
35:           return (_etherPrice() * IWBETH(address(collateralAsset)).exchangeRatio()) / 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L35

File: contracts/lybra/pools/LybraWstETHVault.sol

/// @audit 1e18
49:           return (_etherPrice() * IWstETH(address(collateralAsset)).stEthPerToken()) / 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L49

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit 10_000
157:          return (share * configurator.flashloanFee()) / 10_000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L157

[N‑15] Event is not properly indexed

Index event fields make the field more quickly accessible to off-chain tools that parse events. This is especially useful when it comes to filtering based on an address. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Where applicable, each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three applicable fields, all of the applicable fields should be indexed.

There are 13 instances of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

46:       event ClaimReward(address indexed user, uint256 eUSDAmount, address token, uint256 tokenAmount, uint256 time);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L46

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

34:       event DepositEther(address indexed onBehalfOf, address asset, uint256 etherAmount, uint256 assetAmount, uint256 timestamp);

36:       event DepositAsset(address indexed onBehalfOf, address asset, uint256 amount, uint256 timestamp);

38:       event WithdrawAsset(address sponsor, address asset, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

39:       event Mint(address sponsor, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

40:       event Burn(address sponsor, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

41:       event LiquidationRecord(address provider, address keeper, address indexed onBehalfOf, uint256 eusdamount, uint256 liquidateEtherAmount, uint256 keeperReward, bool superLiquidation, uint256 timestamp);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L34

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

26:       event DepositEther(address indexed onBehalfOf, address asset, uint256 etherAmount, uint256 assetAmount, uint256 timestamp);

28:       event DepositAsset(address indexed onBehalfOf, address asset, uint256 amount, uint256 timestamp);

29:       event WithdrawAsset(address sponsor, address indexed onBehalfOf, address asset, uint256 amount, uint256 timestamp);

30:       event Mint(address sponsor, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

31:       event Burn(address sponsor, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

32:       event LiquidationRecord(address provider, address keeper, address indexed onBehalfOf, uint256 eusdamount, uint256 LiquidateAssetAmount, uint256 keeperReward, bool superLiquidation, uint256 timestamp);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L26

[N‑16] Duplicated require()/revert() checks should be refactored to a modifier or function

The compiler will inline the function, which will avoid JUMP instructions usually associated with functions

There are 9 instances of this issue:

see instances
File: contracts/lybra/miner/EUSDMiningIncentives.sol

111:          require(ratio <= 1e20, "BCE");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L111

File: contracts/lybra/miner/stakerewardV2pool.sol

94:           require(_amount > 0, "amount = 0");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L94

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

97:           require(onBehalfOf != address(0), "TZA");

98:           require(amount > 0, "ZA");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L97

File: contracts/lybra/pools/LybraStETHVault.sol

86:               require(success, "TF");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L86

File: contracts/lybra/token/esLBR.sol

39:           require(configurator.tokenMiner(msg.sender), "not authorized");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L39

File: contracts/lybra/token/EUSD.sol

460:          require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L460

File: contracts/lybra/token/LBR.sol

33:           require(configurator.tokenMiner(msg.sender), "not authorized");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L33

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

134:          require(success, "TF");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L134

[N‑17] Import declarations should import specific identifiers, rather than the whole file

Using import declarations of the form import {<identifier_name>} from "some/file.sol" avoids polluting the symbol namespace making flattened files smaller, and speeds up compilation

There are 56 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

17:   import "../interfaces/IGovernanceTimelock.sol";

18:   import "../interfaces/IEUSD.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L17

File: contracts/lybra/governance/AdminTimelock.sol

5:    import "@openzeppelin/contracts/governance/TimelockController.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/AdminTimelock.sol#L5

File: contracts/lybra/governance/GovernanceTimelock.sol

5:    import "@openzeppelin/contracts/governance/TimelockController.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L5

File: contracts/lybra/governance/LybraGovernance.sol

5:    import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

6:    import "../interfaces/IesLBR.sol";

7:    import "../interfaces/IGovernanceTimelock.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L5

File: contracts/lybra/miner/esLBRBoost.sol

5:    import "@openzeppelin/contracts/access/Ownable.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L5

File: contracts/lybra/miner/EUSDMiningIncentives.sol

12:   import "@openzeppelin/contracts/access/Ownable.sol";

13:   import "../interfaces/IesLBR.sol";

14:   import "../interfaces/IEUSD.sol";

15:   import "../interfaces/ILybra.sol";

16:   import "../interfaces/Iconfigurator.sol";

17:   import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L12

File: contracts/lybra/miner/ProtocolRewardsPool.sol

12:   import "@openzeppelin/contracts/access/Ownable.sol";

13:   import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

14:   import "../interfaces/IEUSD.sol";

15:   import "../interfaces/Iconfigurator.sol";

16:   import "../interfaces/IesLBR.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L12

File: contracts/lybra/miner/stakerewardV2pool.sol

4:    import "@openzeppelin/contracts/access/Ownable.sol";

5:    import "../interfaces/IesLBR.sol";

6:    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L4

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

5:    import "../../interfaces/IEUSD.sol";

6:    import "../../interfaces/Iconfigurator.sol";

7:    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L5

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

5:    import "../../interfaces/Iconfigurator.sol";

6:    import "../../interfaces/IPeUSD.sol";

7:    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L5

File: contracts/lybra/pools/LybraRETHVault.sol

5:    import "../interfaces/IEUSD.sol";

6:    import "./base/LybraPeUSDVaultBase.sol";

7:    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L5

File: contracts/lybra/pools/LybraStETHVault.sol

5:    import "../interfaces/IEUSD.sol";

6:    import "./base/LybraEUSDVaultBase.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L5

File: contracts/lybra/pools/LybraWbETHVault.sol

5:    import "../interfaces/IEUSD.sol";

6:    import "./base/LybraPeUSDVaultBase.sol";

7:    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L5

File: contracts/lybra/pools/LybraWstETHVault.sol

5:    import "../interfaces/IEUSD.sol";

6:    import "./base/LybraPeUSDVaultBase.sol";

7:    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L5

File: contracts/lybra/Proxy/LybraProxyAdmin.sol

4:    import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxyAdmin.sol#L4

File: contracts/lybra/Proxy/LybraProxy.sol

5:    import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxy.sol#L5

File: contracts/lybra/token/esLBR.sol

10:   import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";

11:   import "../interfaces/Iconfigurator.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L10

File: contracts/lybra/token/EUSD.sol

5:    import "@openzeppelin/contracts/utils/math/SafeMath.sol";

6:    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

7:    import "@openzeppelin/contracts/utils/Context.sol";

8:    import "../interfaces/Iconfigurator.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L5

File: contracts/lybra/token/LBR.sol

9:    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

10:   import "../interfaces/Iconfigurator.sol";

11:   import "../../OFT/BaseOFTV2.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L9

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

16:   import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

17:   import "../../OFT/BaseOFTV2.sol";

18:   import "../interfaces/Iconfigurator.sol";

19:   import "../interfaces/IEUSD.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L16

File: contracts/lybra/token/PeUSD.sol

5:    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

6:    import "../../OFT/BaseOFTV2.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L5

[N‑18] Contract implements interface without extending the interface

Not extending the interface may lead to the wrong function signature being used, leading to unexpected behavior. If the interface is in fact being implemented, use the override keyword to indicate that fact

There are 7 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit IAPWineIBT.hasRole()
37:   contract Configurator {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L37

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

/// @audit IAPWineIBT.mint()
17:   abstract contract LybraEUSDVaultBase {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L17

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit IAPWineIBT.mint()
13:   abstract contract LybraPeUSDVaultBase {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L13

File: contracts/lybra/token/esLBR.sol

/// @audit IAPWineIBT.mint()
17:   contract esLBR is ERC20Votes {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L17

File: contracts/lybra/token/EUSD.sol

/// @audit IAPWineIBT.name(), IAPWineIBT.symbol(), IAPWineIBT.decimals(), IAPWineIBT.totalSupply(), IAPWineIBT.balanceOf(), IAPWineIBT.transfer(), IAPWineIBT.allowance(), IAPWineIBT.approve(), IAPWineIBT.transferFrom(), IAPWineIBT.increaseAllowance(), IAPWineIBT.decreaseAllowance(), IAPWineIBT.mint()
37:   contract EUSD is IERC20, Context {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L37

File: contracts/lybra/token/LBR.sol

/// @audit IAPWineIBT.mint()
13:   contract LBR is BaseOFTV2, ERC20 {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L13

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit IAPWineIBT.mint()
29:   contract PeUSDMainnet is BaseOFTV2, ERC20 {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L29

[N‑19] require()/revert() statements should have descriptive reason strings

There are 2 instances of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

228:          require(msg.sender == address(configurator));

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L228

File: contracts/lybra/pools/LybraRETHVault.sol

42:           require(configurator.hasRole(keccak256("TIMELOCK"), msg.sender));

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L42

[N‑20] Missing event and or timelock for critical parameter change

Events help non-contract tools to track changes, and events prevent users from being surprised by changes

There are 11 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

84        function setToken(address _lbr, address _eslbr) external onlyOwner {
85            LBR = _lbr;
86            esLBR = _eslbr;
87:       }

93        function setPools(address[] memory _pools) external onlyOwner {
94            for (uint i = 0; i < _pools.length; i++) {
95                require(configurator.mintVault(_pools[i]), "NOT_VAULT");
96            }
97            pools = _pools;
98:       }

100       function setBiddingCost(uint256 _biddingRatio) external onlyOwner {
101           require(_biddingRatio <= 8000, "BCE");
102           biddingFeeRatio = _biddingRatio;
103:      }

105       function setExtraRatio(uint256 ratio) external onlyOwner {
106           require(ratio <= 1e20, "BCE");
107           extraRatio = ratio;
108:      }

110       function setPeUSDExtraRatio(uint256 ratio) external onlyOwner {
111           require(ratio <= 1e20, "BCE");
112           peUSDExtraRatio = ratio;
113:      }

119       function setRewardsDuration(uint256 _duration) external onlyOwner {
120           require(finishAt < block.timestamp, "reward duration not finished");
121           duration = _duration;
122:      }

124       function setEthlbrStakeInfo(address _pool, address _lp) external onlyOwner {
125           ethlbrStakePool = _pool;
126           ethlbrLpToken = _lp;
127:      }

128       function setEUSDBuyoutAllowed(bool _bool) external onlyOwner {
129           isEUSDBuyoutAllowed = _bool;
130:      }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L84-L87

File: contracts/lybra/miner/ProtocolRewardsPool.sol

58        function setGrabCost(uint256 _ratio) external onlyOwner {
59            require(_ratio <= 8000, "BCE");
60            grabFeeRatio = _ratio;
61:       }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L58-L61

File: contracts/lybra/miner/stakerewardV2pool.sol

121       function setRewardsDuration(uint256 _duration) external onlyOwner {
122           require(finishAt < block.timestamp, "reward duration not finished");
123           duration = _duration;
124:      }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L121-L124

File: contracts/lybra/pools/LybraStETHVault.sol

25        function setLidoRebaseTime(uint256 _time) external {
26            require(configurator.hasRole(keccak256("ADMIN"), msg.sender), "not authorized");
27            lidoRebaseTime = _time;
28:       }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L25-L28

[N‑21] Events that mark critical parameter changes should contain both the old and the new value

This should especially be done if the new value is not required to be different from the old value

There are 9 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit setBadCollateralRatio()
129:          emit SafeCollateralRatioChanged(pool, newRatio);

/// @audit setProtocolRewardsPool()
139:          emit ProtocolRewardsPoolChanged(addr, block.timestamp);

/// @audit setEUSDMiningIncentives()
149:          emit EUSDMiningIncentivesChanged(addr, block.timestamp);

/// @audit setRedemptionFee()
189:          emit RedemptionFeeChanged(newFee);

/// @audit setSafeCollateralRatio()
205:          emit SafeCollateralRatioChanged(pool, newRatio);

/// @audit setBorrowApy()
216:          emit BorrowApyChanged(pool, newApy);

/// @audit setKeeperRatio()
227:          emit KeeperRatioChanged(pool, newRatio);

/// @audit setTokenMiner()
238:              emit tokenMinerChanges(_contracts[i], _bools[i]);

/// @audit setFlashloanFee()
255:          emit FlashloanFeeUpdated(fee);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L129

[N‑22] Constant redefined elsewhere

Consider defining in only one contract so that values cannot become out of sync when only one location is updated. A cheap way to store constants in a single location is to create an internal constant in a library. If the variable is a local cache of another contract's value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don't get out of sync.

There are 3 instances of this issue:

File: contracts/lybra/governance/GovernanceTimelock.sol

/// @audit seen in contracts/lybra/configuration/LybraConfigurator.sol 
10:       bytes32 public constant DAO = keccak256("DAO");

/// @audit seen in contracts/lybra/configuration/LybraConfigurator.sol 
11:       bytes32 public constant TIMELOCK = keccak256("TIMELOCK");

/// @audit seen in contracts/lybra/configuration/LybraConfigurator.sol 
12:       bytes32 public constant ADMIN = keccak256("ADMIN");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L10

[N‑23] Use @inheritdoc rather than using a non-standard annotation

There is one instance of this issue:

File: contracts/lybra/governance/LybraGovernance.sol

176       /**
177        * @dev See {IERC165-supportsInterface}.
178        */
179:      function supportsInterface(bytes4 interfaceId) public view virtual override(GovernorTimelockControl) returns (bool) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L176-L179

[N‑24] Inconsistent spacing in comments

Some lines use // x and some use //x. The instances below point out the usages that don't follow the majority, within each file

There are 6 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

63:       //etherOracle = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L63

File: contracts/lybra/miner/stakerewardV2pool.sol

43:       ///events

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L43

File: contracts/lybra/pools/LybraStETHVault.sol

39:           //convert to steth

77:                   //EUSD totalSupply is 0: assume that shares correspond to EUSD 1-to-1

80:               //Income is distributed to LBR staker.

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L39

File: contracts/lybra/token/EUSD.sol

416:              //EUSD totalSupply is 0: assume that shares correspond to EUSD 1-to-1

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L416

[N‑25] Lines are too long

Usually lines in source code are limited to 80 characters. Today's screens are much larger so it's reasonable to stretch this in some cases. The solidity style guide recommends a maximumum line length of 120 characters, so the lines below should be split when they reach that length.

There are 92 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

5:     * @dev The Configurator contract is used to set various parameters and control functionalities of the Lybra Protocol. It is based on OpenZeppelin's Proxy and AccessControl libraries, allowing the DAO to control contract upgrades. There are three types of governance roles:

6:     * * DAO: A time-locked contract initiated by esLBR voting, with a minimum effective period of 14 days. After the vote is passed, only the developer can execute the action.

57:       // Limiting the maximum percentage of eUSD that can be cross-chain transferred to L2 in relation to the total supply.

73:       /// @param fee The new fee for this token as a percentage and multiplied by 100 to avoid decimals (for example, 10% is 10_00)

127:          require(newRatio >= 130 * 1e18 && newRatio <= 150 * 1e18 && newRatio <= vaultSafeCollateralRatio[pool] + 1e19, "LNA");

202:              require(newRatio >= vaultBadCollateralRatio[pool] + 1e19, "PeUSD vault safe collateralRatio should more than bad collateralRatio");

284:       * If premiumTradingEnabled is false or the price of the trading pair (0, 2) on the Curve pool is less than or equal to 1005000, eUSD rewards are directly transferred to the LybraProtocolRewardsPool.

285:       * Otherwise, a controlled premium trading is performed by exchanging eUSD for the third token in the trading pair on the Curve pool, using a calculated amount to maintain a premium.

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L5

File: contracts/lybra/governance/AdminTimelock.sol

8:        constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) TimelockController(minDelay, proposers, executors, admin) {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/AdminTimelock.sol#L8

File: contracts/lybra/governance/GovernanceTimelock.sol

15:       constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) TimelockController(minDelay, proposers, executors, admin) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L15

File: contracts/lybra/governance/LybraGovernance.sol

38:         constructor(string memory name_, TimelockController timelock_, address _esLBR) GovernorTimelockControl(timelock_)  Governor(name_) {

60:           return proposalData[proposalId].supportVotes[1] + proposalData[proposalId].supportVotes[2] >= quorum(proposalSnapshot(proposalId));

76:       function _countVote(uint256 proposalId, address account, uint8 support, uint256 weight, bytes memory) internal override {

106:      function _execute(uint256 /* proposalId */, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) internal virtual override {

112:      function proposals(uint256 proposalId) external view returns (uint256 id, address proposer, uint256 eta, uint256 startBlock, uint256 endBlock, uint256 forVotes, uint256 againstVotes, uint256 abstainVotes, bool canceled, bool executed) {

129:      function getReceipt(uint256 proposalId, address account) external view returns (bool voted, uint8 support, uint256 votes){  

170:       * @dev Part of the Governor Bravo's interface: _"The number of votes required in order for a voter to become a proposer"_.

179:      function supportsInterface(bytes4 interfaceId) public view virtual override(GovernorTimelockControl) returns (bool) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L38

File: contracts/lybra/miner/esLBRBoost.sol

42:               require(userStatus.duration <= _setting.duration, "Your lock-in period has not ended, and the term can only be extended, not reduced.");

44:           userLockStatus[msg.sender] = LockStatus(block.timestamp + _setting.duration, _setting.duration, _setting.miningBoost);

55:        * there are several scenarios that could occur, including no acceleration, full acceleration, and partial acceleration.

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L42

File: contracts/lybra/miner/EUSDMiningIncentives.sol

60:       event ClaimedOtherEarnings(address indexed user, address indexed Victim, uint256 buyAmount, uint256 biddingFee, bool useEUSD, uint256 time);

153:          uint256 etherInLp = (IEUSD(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2).balanceOf(ethlbrLpToken) * uint(etherPrice)) / 1e8;

185:          return ((stakedOf(_account) * getBoost(_account) * (rewardPerToken() - userRewardPerTokenPaid[_account])) / 1e38) + rewards[_account];

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L60

File: contracts/lybra/miner/ProtocolRewardsPool.sol

5:     * @title ProtocolRewardsPool is a derivative version of Synthetix StakingRewards.sol, distributing Protocol revenue to esLBR stakers.

88:           require(block.timestamp >= esLBRBoost.getUnlockTime(msg.sender), "Your lock-in period has not ended. You can't convert your esLBR now.");

111:       * with the lost portion being recorded in the contract and available for others to purchase in LBR at a certain ratio.

152:          amount = (a * (75e18 - ((time2fullRedemption[user] - block.timestamp) * 70e18) / (exitCycle / 1 days - 3) / 1 days)) / 100e18;

157:              amount = block.timestamp > time2fullRedemption[user] ? unstakeRatio[user] * (time2fullRedemption[user] - lastWithdrawTime[user]) : unstakeRatio[user] * (block.timestamp - lastWithdrawTime[user]);

168:          return ((stakedOf(_account) * (rewardPerTokenStored - userRewardPerTokenPaid[_account])) / 1e18) + rewards[_account];

187:       * @notice When claiming protocol rewards earnings, if there is a sufficient amount of eUSD in the ProtocolRewards Pool,

188:       * the eUSD will be prioritized for distribution. Distributes earnings in the order of peUSD and other stablecoins if the eUSD balance is insufficient..

203:                      emit ClaimReward(msg.sender, EUSD.getMintedEUSDByShares(eUSDShare), address(peUSD), reward - eUSDShare, block.timestamp);

211:                      emit ClaimReward(msg.sender, EUSD.getMintedEUSDByShares(eUSDShare), address(token), reward - eUSDShare, block.timestamp);

221:       * @dev Receives stablecoin tokens sent by the configurator contract and records the protocol rewards accumulation per esLBR held.

225:       * @dev When receiving stablecoin tokens other than eUSD, the decimals of the token are converted to 18 for consistent calculations.

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L5

File: contracts/lybra/miner/stakerewardV2pool.sol

107:          return ((balanceOf[_account] * getBoost(_account) * (rewardPerToken() - userRewardPerTokenPaid[_account])) / 1e38) + rewards[_account];

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L107

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

34:       event DepositEther(address indexed onBehalfOf, address asset, uint256 etherAmount, uint256 assetAmount, uint256 timestamp);

41:       event LiquidationRecord(address provider, address keeper, address indexed onBehalfOf, uint256 eusdamount, uint256 liquidateEtherAmount, uint256 keeperReward, bool superLiquidation, uint256 timestamp);

43:       event RigidRedemption(address indexed caller, address indexed provider, uint256 eusdAmount, uint256 collateralAmount, uint256 timestamp);

54:        * @notice Allowing direct deposits of ETH, the pool may convert it into the corresponding collateral during the implementation.

124:       * - `amount` Must be higher than 0. Individual mint amount shouldn't surpass 10% when the circulation reaches 10_000_000

146:       * @notice When overallCollateralRatio is above 150%, Keeper liquidates borrowers whose collateral ratio is below badCollateralRatio, using EUSD provided by Liquidation Provider.

152:       * @dev After liquidation, borrower's debt is reduced by collateralAmount * etherPrice, collateral is reduced by the collateralAmount corresponding to 110% of the value. Keeper gets keeperRatio / 110 of Liquidation Reward and Liquidator gets the remaining stETH.

157:          require(onBehalfOfCollateralRatio < badCollateralRatio, "Borrowers collateral ratio should below badCollateralRatio");

175:          emit LiquidationRecord(provider, msg.sender, onBehalfOf, eusdAmount, reducedAsset, reward2keeper, false, block.timestamp);

179:       * @notice When overallCollateralRatio is below badCollateralRatio, borrowers with collateralRatio below 125% could be fully liquidated.

185:       * @dev After Liquidation, borrower's debt is reduced by collateralAmount * etherPrice, deposit is reduced by collateralAmount * borrower's collateralRatio. Keeper gets a liquidation reward of `keeperRatio / borrower's collateralRatio

189:          require((totalDepositedAsset * assetPrice * 100) / poolTotalEUSDCirculation < badCollateralRatio, "overallCollateralRatio should below 150%");

197:          require(EUSD.allowance(provider, address(this)) >= eusdAmount, "provider should authorize to provide liquidation EUSD");

204:          if (msg.sender != provider && onBehalfOfCollateralRatio >= 1e20 + configurator.vaultKeeperRatio(address(this)) * 1e18) {

205:              reward2keeper = ((assetAmount * configurator.vaultKeeperRatio(address(this))) * 1e18) / onBehalfOfCollateralRatio;

210:          emit LiquidationRecord(provider, msg.sender, onBehalfOf, eusdAmount, assetAmount, reward2keeper, true, block.timestamp);

214:       * @notice When stETH balance increases through LSD or other reasons, the excess income is sold for EUSD, allocated to EUSD holders through rebase mechanism.

239:          uint256 collateralAmount = (((eusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;

259:      function _mintEUSD(address _provider, address _onBehalfOf, uint256 _mintAmount, uint256 _assetPrice) internal virtual {

274:       * @dev Refresh LBR reward before reducing providers debt. Refresh Lybra generated service fee before reducing totalEUSDCirculation.

289:       * @dev Get USD value of current collateral asset and minted EUSD through price oracle / Collateral asset USD value must higher than safe Collateral Ratio.

292:          if (((depositedAsset[_user] * _assetPrice * 100) / borrowed[_user]) < configurator.getSafeCollateralRatio(address(this))) revert("collateralRatio is Below safeCollateralRatio");

301:          return (poolTotalEUSDCirculation * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - lastReportTime)) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L34

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

26:       event DepositEther(address indexed onBehalfOf, address asset, uint256 etherAmount, uint256 assetAmount, uint256 timestamp);

32:       event LiquidationRecord(address provider, address keeper, address indexed onBehalfOf, uint256 eusdamount, uint256 LiquidateAssetAmount, uint256 keeperReward, bool superLiquidation, uint256 timestamp);

34:       event RigidRedemption(address indexed caller, address indexed provider, uint256 peusdAmount, uint256 assetAmount, uint256 timestamp);

94:        * - `amount` Must be higher than 0. Individual mint amount shouldn't surpass 10% when the circulation reaches 10_000_000

117:       * @notice When overallCollateralRatio is above 150%, Keeper liquidates borrowers whose collateral ratio is below badCollateralRatio, using PeUSD provided by Liquidation Provider.

123:       * @dev After liquidation, borrower's debt is reduced by assetAmount * assetPrice, collateral is reduced by the assetAmount corresponding to 110% of the value. Keeper gets keeperRatio / 110 of Liquidation Reward and Liquidator gets the remaining stETH.

128:          require(onBehalfOfCollateralRatio < configurator.getBadCollateralRatio(address(this)), "Borrowers collateral ratio should below badCollateralRatio");

145:          emit LiquidationRecord(provider, msg.sender, onBehalfOf, peusdAmount, reducedAsset, reward2keeper, false, block.timestamp);

164:          uint256 collateralAmount = (((peusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;

171:       * @dev Refresh LBR reward before adding providers debt. Refresh Lybra generated service fee before adding totalSupply. Check providers collateralRatio cannot below `safeCollateralRatio`after minting.

173:      function _mintPeUSD(address _provider, address _onBehalfOf, uint256 _mintAmount, uint256 _assetPrice) internal virtual {

190:       * @dev Refresh LBR reward before reducing providers debt. Refresh Lybra generated service fee before reducing totalPeUSDCirculation.

223:       * @dev Get USD value of current collateral asset and minted EUSD through price oracle / Collateral asset USD value must higher than safe Collateral Ratio.

226:          if (((depositedAsset[user] * price * 100) / getBorrowedOf(user)) < configurator.getSafeCollateralRatio(address(this))) 

238:          return (borrowed[user] * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - feeUpdatedAt[user])) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L26

File: contracts/lybra/pools/LybraStETHVault.sol

55:        * @notice When stETH balance increases through LSD or other reasons, the excess income is sold for EUSD, allocated to EUSD holders through rebase mechanism.

98:        * @notice Reduces the discount for the issuance of additional tokens based on the rebase time using the Dutch auction method.

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L55

File: contracts/lybra/pools/LybraWstETHVault.sol

25:       constructor(address _lido, address _peusd, address _oracle, address _asset, address _config) LybraPeUSDVaultBase(_peusd, _oracle, _asset,_config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L25

File: contracts/lybra/token/esLBR.sol

5:     * @title esLBR is an ERC20-compliant token, but cannot be transferred and can only be minted through the esLBRMinter contract or redeemed for LBR by destruction.

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L5

File: contracts/lybra/token/EUSD.sol

77:       event SharesBurnt(address indexed account, uint256 preRebaseTokenAmount, uint256 postRebaseTokenAmount, uint256 sharesAmount);

411:      function mint(address _recipient, uint256 _mintAmount) external onlyMintVault MintPaused returns (uint256 newTotalShares) {

440:      function burn(address _account, uint256 _burnAmount) external onlyMintVault BurnPaused returns (uint256 newTotalShares) {

459:      function burnShares(address _account, uint256 _sharesAmount) external onlyMintVault BurnPaused returns (uint256 newTotalShares) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L77

File: contracts/lybra/token/LBR.sol

18:       constructor(address _config, uint8 _sharedDecimals, address _lzEndpoint) ERC20("LBR", "LBR") BaseOFTV2(_sharedDecimals, _lzEndpoint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L18

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

25:       /// @dev Called after receiving the requested flash loan, should return tokens + any fees before the end of the transaction

55:       constructor(address _config, uint8 _sharedDecimals, address _lzEndpoint) ERC20("peg-eUSD", "PeUSD") BaseOFTV2(_sharedDecimals, _lzEndpoint) {

76:        * @param user The address of the user who wants to deposit eUSD and mint PeUSD. It can only be the contract itself or the msg.sender.

109:       * @param peusdAmount The amount of PeUSD tokens to burn and retrieve eUSD. The user's balance of PeUSD tokens must be greater than or equal to this amount.

117:          uint256 share = (userConvertInfo[msg.sender].depositedEUSDShares * peusdAmount) / userConvertInfo[msg.sender].mintedPeUSD;

168:          return EUSD.getMintedEUSDByShares(userConvertInfo[user].depositedEUSDShares) - userConvertInfo[user].mintedPeUSD;

181:       * @dev The following functions are internal functions of Layer Zero OFT, used for internal calls during cross-chain operations.

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L25

File: contracts/lybra/token/PeUSD.sol

11:       constructor(uint8 _sharedDecimals, address _lzEndpoint) ERC20("peg-eUSD", "peUSD") BaseOFTV2(_sharedDecimals, _lzEndpoint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L11

[N‑26] Variable names that consist of all capital letters should be reserved for constant/immutable variables

If the variable needs to be different based on which class it comes from, a view/pure function should be used instead (e.g. like this).

There are 4 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

54:       IEUSD public EUSD;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L54

File: contracts/lybra/miner/EUSDMiningIncentives.sol

32:       address public LBR;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L32

File: contracts/lybra/miner/ProtocolRewardsPool.sol

27:       IesLBR public LBR;

194:              IEUSD EUSD = IEUSD(configurator.getEUSDAddress());

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L27

[N‑27] Non-library/interface files should use fixed compiler versions, not floating ones

There are 19 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

15:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L15

File: contracts/lybra/governance/AdminTimelock.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/AdminTimelock.sol#L3

File: contracts/lybra/governance/GovernanceTimelock.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L3

File: contracts/lybra/governance/LybraGovernance.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L3

File: contracts/lybra/miner/esLBRBoost.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L3

File: contracts/lybra/miner/EUSDMiningIncentives.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L3

File: contracts/lybra/miner/ProtocolRewardsPool.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L3

File: contracts/lybra/miner/stakerewardV2pool.sol

2:    pragma solidity ^0.8;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L2

File: contracts/lybra/pools/LybraRETHVault.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L3

File: contracts/lybra/pools/LybraStETHVault.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L3

File: contracts/lybra/pools/LybraWbETHVault.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L3

File: contracts/lybra/pools/LybraWstETHVault.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L3

File: contracts/lybra/Proxy/LybraProxyAdmin.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxyAdmin.sol#L3

File: contracts/lybra/Proxy/LybraProxy.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxy.sol#L3

File: contracts/lybra/token/esLBR.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L3

File: contracts/lybra/token/EUSD.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L3

File: contracts/lybra/token/LBR.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L3

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

14:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L14

File: contracts/lybra/token/PeUSD.sol

3:    pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L3

[N‑28] Typos

There is one instance of this issue:

File: contracts/lybra/governance/GovernanceTimelock.sol

/// @audit contructor
9:        // contructor()

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L9

[N‑29] File is missing NatSpec

There are 11 instances of this issue:

see instances
File: contracts/lybra/governance/AdminTimelock.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/AdminTimelock.sol

File: contracts/lybra/governance/GovernanceTimelock.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol

File: contracts/lybra/miner/stakerewardV2pool.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol

File: contracts/lybra/pools/LybraRETHVault.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol

File: contracts/lybra/pools/LybraWbETHVault.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol

File: contracts/lybra/pools/LybraWstETHVault.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol

File: contracts/lybra/Proxy/LybraProxyAdmin.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxyAdmin.sol

File: contracts/lybra/Proxy/LybraProxy.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxy.sol

File: contracts/lybra/token/esLBR.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol

File: contracts/lybra/token/LBR.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol

File: contracts/lybra/token/PeUSD.sol

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol

[N‑30] NatSpec @param is missing

There are 133 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit Missing: '@param _eusd'
/// @audit Missing: '@param _peusd'
95        /**
96         * @notice Initializes the eUSD and peUSD address. This function can only be executed once.
97         */
98:       function initToken(address _eusd, address _peusd) external onlyRole(DAO) {

/// @audit Missing: '@param pool'
/// @audit Missing: '@param newRatio'
123       /**
124        * @notice  badCollateralRatio can be decided by DAO,starts at 130%
125        */
126:      function setBadCollateralRatio(address pool, uint256 newRatio) external onlyRole(DAO) {

/// @audit Missing: '@param pool'
/// @audit Missing: '@param newRatio'
192       /**
193        * @notice  safeCollateralRatio can be decided by TIMELOCK.
194        * The eUSD vault requires a minimum safe collateral rate of 160%,
195        * On the other hand, the PeUSD vault requires a safe collateral rate at least 10% higher
196        * than the liquidation collateral rate, providing an additional buffer to protect against liquidation risks.
197        */
198:      function setSafeCollateralRatio(address pool, uint256 newRatio) external checkRole(TIMELOCK) {

/// @audit Missing: '@param _bool'
265       /**
266        * @notice User chooses to become a Redemption Provider
267        */
268:      function becomeRedemptionProvider(bool _bool) external {

/// @audit Missing: '@param user'
274       /**
275        * @dev Updates the mining data for the user's eUSD mining incentives.
276        */
277:      function refreshMintReward(address user) external {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L95-L98

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit Missing: '@param name_'
/// @audit Missing: '@param timelock_'
/// @audit Missing: '@param _esLBR'
37            // TimelockController timelockAddress;
38:         constructor(string memory name_, TimelockController timelock_, address _esLBR) GovernorTimelockControl(timelock_)  Governor(name_) {

/// @audit Missing: '@param timepoint'
44          /**
45         * @notice module:user-config
46         * @dev Minimum number of cast voted required for a proposal to be successful.
47         *
48         * NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the
49         * quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}).
50         */
51:       function quorum(uint256 timepoint) public view override returns (uint256){

/// @audit Missing: '@param proposalId'
56        /**
57         * @dev Amount of votes already cast passes the threshold limit.
58         */
59:       function _quorumReached(uint256 proposalId) internal view override returns (bool){

/// @audit Missing: '@param proposalId'
63           /**
64         * @dev Is the proposal successful or not.
65         */
66:       function _voteSucceeded(uint256 proposalId) internal view override returns (bool){

/// @audit Missing: '@param proposalId'
/// @audit Missing: '@param account'
/// @audit Missing: '@param support'
/// @audit Missing: '@param weight'
/// @audit Missing: '@param bytes'
70           /**
71         * @dev Register a vote for `proposalId` by `account` with a given `support`, voting `weight` and voting `params`.
72         *
73         * Note: Support is generic and can represent various things depending on the voting system used.
74         */
75    
76:       function _countVote(uint256 proposalId, address account, uint8 support, uint256 weight, bytes memory) internal override {

/// @audit Missing: '@param account'
/// @audit Missing: '@param timepoint'
/// @audit Missing: '@param bytes'
94        /**
95         * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`.
96         */
97    
98:        function _getVotes(address account, uint256 timepoint, bytes memory) internal view override returns (uint256){

/// @audit Missing: '@param uint256'
/// @audit Missing: '@param targets'
/// @audit Missing: '@param values'
/// @audit Missing: '@param calldatas'
/// @audit Missing: '@param descriptionHash'
103       /**
104        * @dev Overridden execute function that run the already queued proposal through the timelock.
105        */
106:      function _execute(uint256 /* proposalId */, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) internal virtual override {

/// @audit Missing: '@param interfaceId'
176       /**
177        * @dev See {IERC165-supportsInterface}.
178        */
179:      function supportsInterface(bytes4 interfaceId) public view virtual override(GovernorTimelockControl) returns (bool) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L37-L38

File: contracts/lybra/miner/esLBRBoost.sol

/// @audit Missing: '@param setting'
32        // Function to add a new lock setting
33:       function addLockSetting(esLBRLockSetting memory setting) external onlyOwner {

/// @audit Missing: '@param id'
37        // Function to set the user's lock status
38:       function setLockStatus(uint256 id) external {

/// @audit Missing: '@param user'
47        // Function to get the user's unlock time
48:       function getUnlockTime(address user) external view returns (uint256 unlockTime) {

/// @audit Missing: '@param user'
/// @audit Missing: '@param userUpdatedAt'
/// @audit Missing: '@param finishAt'
52        /**
53         * @notice calculate the user's mining boost based on their lock status
54         * @dev Based on the user's userUpdatedAt time, finishAt time, and the current time,
55         * there are several scenarios that could occur, including no acceleration, full acceleration, and partial acceleration.
56         */
57:       function getUserBoost(address user, uint256 userUpdatedAt, uint256 finishAt) external view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L32-L33

File: contracts/lybra/miner/EUSDMiningIncentives.sol

/// @audit Missing: '@param _config'
/// @audit Missing: '@param _boost'
/// @audit Missing: '@param _etherOracle'
/// @audit Missing: '@param _lbrOracle'
63        //etherOracle = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
64:       constructor(address _config, address _boost, address _etherOracle, address _lbrOracle) {

/// @audit Missing: '@param _account'
171       /**
172        * @notice Update user's claimable reward data and record the timestamp.
173        */
174:      function refreshReward(address _account) external updateReward(_account) {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L63-L64

File: contracts/lybra/miner/ProtocolRewardsPool.sol

/// @audit Missing: '@param staker'
68        // User address => esLBR balance
69:       function stakedOf(address staker) internal view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L68-L69

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

/// @audit Missing: '@param mintAmount'
53        /**
54         * @notice Allowing direct deposits of ETH, the pool may convert it into the corresponding collateral during the implementation.
55         * While depositing, it is possible to simultaneously mint eUSD for oneself.
56         * Emits a `DepositEther` event.
57         *
58         * Requirements:
59         * - `mintAmount` Send 0 if doesn't mint EUSD
60         * - msg.value Must be higher than 0.
61         */
62:       function depositEtherToMint(uint256 mintAmount) external payable virtual;

/// @audit Missing: '@param assetAmount'
/// @audit Missing: '@param mintAmount'
64        /**
65         * @notice Deposit collateral and allow minting eUSD for oneself.
66         * Emits a `DepositAsset` event.
67         *
68         * Requirements:
69         * - `assetAmount` Must be higher than 0.
70         * - `mintAmount` Send 0 if doesn't mint EUSD
71         */
72:       function depositAssetToMint(uint256 assetAmount, uint256 mintAmount) external virtual {

/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param amount'
88        /**
89         * @notice Withdraw collateral assets to an address
90         * Emits a `WithdrawEther` event.
91         *
92         * Requirements:
93         * - `onBehalfOf` cannot be the zero address.
94         * - `amount` Must be higher than 0.
95         *
96         * @dev Withdraw stETH. Check user’s collateral ratio after withdrawal, should be higher than `safeCollateralRatio`
97         */
98:       function withdraw(address onBehalfOf, uint256 amount) external virtual {

/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param amount'
118       /**
119        * @notice The mint amount number of EUSD is minted to the address
120        * Emits a `Mint` event.
121        *
122        * Requirements:
123        * - `onBehalfOf` cannot be the zero address.
124        * - `amount` Must be higher than 0. Individual mint amount shouldn't surpass 10% when the circulation reaches 10_000_000
125        */
126:      function mint(address onBehalfOf, uint256 amount) external {

/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param amount'
132       /**
133        * @notice Burn the amount of EUSD and payback the amount of minted EUSD
134        * Emits a `Burn` event.
135        * Requirements:
136        * - `onBehalfOf` cannot be the zero address.
137        * - `amount` Must be higher than 0.
138        * @dev Calling the internal`_repay`function.
139        */
140:      function burn(address onBehalfOf, uint256 amount) external {

/// @audit Missing: '@param provider'
/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param assetAmount'
145       /**
146        * @notice When overallCollateralRatio is above 150%, Keeper liquidates borrowers whose collateral ratio is below badCollateralRatio, using EUSD provided by Liquidation Provider.
147        *
148        * Requirements:
149        * - onBehalfOf Collateral Ratio should be below badCollateralRatio
150        * - collateralAmount should be less than 50% of collateral
151        * - provider should authorize Lybra to utilize EUSD
152        * @dev After liquidation, borrower's debt is reduced by collateralAmount * etherPrice, collateral is reduced by the collateralAmount corresponding to 110% of the value. Keeper gets keeperRatio / 110 of Liquidation Reward and Liquidator gets the remaining stETH.
153        */
154:      function liquidation(address provider, address onBehalfOf, uint256 assetAmount) external virtual {

/// @audit Missing: '@param provider'
/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param assetAmount'
178       /**
179        * @notice When overallCollateralRatio is below badCollateralRatio, borrowers with collateralRatio below 125% could be fully liquidated.
180        * Emits a `LiquidationRecord` event.
181        *
182        * Requirements:
183        * - Current overallCollateralRatio should be below badCollateralRatio
184        * - `onBehalfOf`collateralRatio should be below 125%
185        * @dev After Liquidation, borrower's debt is reduced by collateralAmount * etherPrice, deposit is reduced by collateralAmount * borrower's collateralRatio. Keeper gets a liquidation reward of `keeperRatio / borrower's collateralRatio
186        */
187:      function superLiquidation(address provider, address onBehalfOf, uint256 assetAmount) external virtual {

/// @audit Missing: '@param payAmount'
213       /**
214        * @notice When stETH balance increases through LSD or other reasons, the excess income is sold for EUSD, allocated to EUSD holders through rebase mechanism.
215        * Emits a `LSDistribution` event.
216        *
217        * *Requirements:
218        * - stETH balance in the contract cannot be less than totalDepositedAsset after exchange.
219        * @dev Income is used to cover accumulated Service Fee first.
220        */
221:      function excessIncomeDistribution(uint256 payAmount) external virtual;

/// @audit Missing: '@param provider'
/// @audit Missing: '@param eusdAmount'
223       /**
224        * @notice Choose a Redemption Provider, Rigid Redeem `eusdAmount` of EUSD and get 1:1 value of stETH
225        * Emits a `RigidRedemption` event.
226        *
227        * *Requirements:
228        * - `provider` must be a Redemption Provider
229        * - `provider`debt must equal to or above`eusdAmount`
230        * @dev Service Fee for rigidRedemption `redemptionFee` is set to 0.5% by default, can be revised by DAO.
231        */
232:      function rigidRedemption(address provider, uint256 eusdAmount) external virtual {

/// @audit Missing: '@param _provider'
/// @audit Missing: '@param _onBehalfOf'
/// @audit Missing: '@param _amount'
271       /**
272        * @notice Burn _provideramount EUSD to payback minted EUSD for _onBehalfOf.
273        *
274        * @dev Refresh LBR reward before reducing providers debt. Refresh Lybra generated service fee before reducing totalEUSDCirculation.
275        */
276:      function _repay(address _provider, address _onBehalfOf, uint256 _amount) internal virtual {

/// @audit Missing: '@param _user'
/// @audit Missing: '@param _assetPrice'
288       /**
289        * @dev Get USD value of current collateral asset and minted EUSD through price oracle / Collateral asset USD value must higher than safe Collateral Ratio.
290        */
291:      function _checkHealth(address _user, uint256 _assetPrice) internal view {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L53-L62

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit Missing: '@param assetAmount'
/// @audit Missing: '@param mintAmount'
50        /**
51         * @notice Deposit staked ETH, update the interest distribution, can mint PeUSD directly
52         * Emits a `DepositAsset` event.
53         *
54         * Requirements:
55         * - `assetAmount` Must be higher than 0.
56         * - `mintAmount` Send 0 if doesn't mint PeUSD
57         */
58:       function depositAssetToMint(uint256 assetAmount, uint256 mintAmount) external virtual {

/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param amount'
72        /**
73         * @notice Withdraw collateral assets to an address
74         * Emits a `WithdrawAsset` event.
75         *
76         * Requirements:
77         * - `onBehalfOf` cannot be the zero address.
78         * - `amount` Must be higher than 0.
79         *
80         * @dev Withdraw stETH. Check user’s collateral ratio after withdrawal, should be higher than `safeCollateralRatio`
81         */
82:       function withdraw(address onBehalfOf, uint256 amount) external virtual {

/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param amount'
88        /**
89         * @notice The mint amount number of PeUSD is minted to the address
90         * Emits a `Mint` event.
91         *
92         * Requirements:
93         * - `onBehalfOf` cannot be the zero address.
94         * - `amount` Must be higher than 0. Individual mint amount shouldn't surpass 10% when the circulation reaches 10_000_000
95         */
96:       function mint(address onBehalfOf, uint256 amount) external virtual {

/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param amount'
102       /**
103        * @notice Burn the amount of PeUSD and payback the amount of minted PeUSD
104        * Emits a `Burn` event.
105        * Requirements:
106        * - `onBehalfOf` cannot be the zero address.
107        * - `amount` Must be higher than 0.
108        * @dev Calling the internal`_repay`function.
109        */
110:      function burn(address onBehalfOf, uint256 amount) external virtual {

/// @audit Missing: '@param provider'
/// @audit Missing: '@param onBehalfOf'
/// @audit Missing: '@param assetAmount'
116       /**
117        * @notice When overallCollateralRatio is above 150%, Keeper liquidates borrowers whose collateral ratio is below badCollateralRatio, using PeUSD provided by Liquidation Provider.
118        *
119        * Requirements:
120        * - onBehalfOf Collateral Ratio should be below badCollateralRatio
121        * - assetAmount should be less than 50% of collateral
122        * - provider should authorize Lybra to utilize PeUSD
123        * @dev After liquidation, borrower's debt is reduced by assetAmount * assetPrice, collateral is reduced by the assetAmount corresponding to 110% of the value. Keeper gets keeperRatio / 110 of Liquidation Reward and Liquidator gets the remaining stETH.
124        */
125:      function liquidation(address provider, address onBehalfOf, uint256 assetAmount) external virtual {

/// @audit Missing: '@param provider'
/// @audit Missing: '@param peusdAmount'
148       /**
149        * @notice Choose a Redemption Provider, Rigid Redeem `peusdAmount` of EUSD and get 1:1 value of stETH
150        * Emits a `RigidRedemption` event.
151        *
152        * *Requirements:
153        * - `provider` must be a Redemption Provider
154        * - `provider`debt must equal to or above`peusdAmount`
155        * @dev Service Fee for rigidRedemption `redemptionFee` is set to 0.5% by default, can be revised by DAO.
156        */
157:      function rigidRedemption(address provider, uint256 peusdAmount) external virtual {

/// @audit Missing: '@param _provider'
/// @audit Missing: '@param _onBehalfOf'
/// @audit Missing: '@param _mintAmount'
/// @audit Missing: '@param _assetPrice'
170       /**
171        * @dev Refresh LBR reward before adding providers debt. Refresh Lybra generated service fee before adding totalSupply. Check providers collateralRatio cannot below `safeCollateralRatio`after minting.
172        */
173:      function _mintPeUSD(address _provider, address _onBehalfOf, uint256 _mintAmount, uint256 _assetPrice) internal virtual {

/// @audit Missing: '@param _provider'
/// @audit Missing: '@param _onBehalfOf'
/// @audit Missing: '@param _amount'
187       /**
188        * @notice Burn _provideramount PeUSD to payback minted PeUSD for _onBehalfOf.
189        *
190        * @dev Refresh LBR reward before reducing providers debt. Refresh Lybra generated service fee before reducing totalPeUSDCirculation.
191        */
192:      function _repay(address _provider, address _onBehalfOf, uint256 _amount) internal virtual {

/// @audit Missing: '@param user'
/// @audit Missing: '@param price'
222       /**
223        * @dev Get USD value of current collateral asset and minted EUSD through price oracle / Collateral asset USD value must higher than safe Collateral Ratio.
224        */
225:      function _checkHealth(address user, uint256 price) internal view {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L50-L58

File: contracts/lybra/pools/LybraStETHVault.sol

/// @audit Missing: '@param _config'
/// @audit Missing: '@param _stETH'
/// @audit Missing: '@param _oracle'
16        // stETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84
17        // oracle = 0x4c517D4e2C851CA76d7eC94B805269Df0f2201De
18:       constructor(address _config, address _stETH, address _oracle) LybraEUSDVaultBase(_stETH, _oracle, _config) {

/// @audit Missing: '@param _time'
21        /**
22         * @notice Sets the rebase time for Lido based on the actual situation.
23         * This function can only be called by an address with the ADMIN role.
24         */
25:       function setLidoRebaseTime(uint256 _time) external {

/// @audit Missing: '@param stETHAmount'
54        /**
55         * @notice When stETH balance increases through LSD or other reasons, the excess income is sold for EUSD, allocated to EUSD holders through rebase mechanism.
56         * Emits a `LSDValueCaptured` event.
57         *
58         * *Requirements:
59         * - stETH balance in the contract cannot be less than totalDepositedAsset after exchange.
60         * @dev Income is used to cover accumulated Service Fee first.
61         */
62:       function excessIncomeDistribution(uint256 stETHAmount) external override {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L16-L18

File: contracts/lybra/token/EUSD.sol

/// @audit Missing: '@param _account'
128       /**
129        * @return the amount of tokens owned by the `_account`.
130        *
131        * @dev Balances are dynamic and equal the `_account`'s share in the amount of the
132        * total Ether controlled by the protocol. See `sharesOf`.
133        */
134:      function balanceOf(address _account) public view returns (uint256) {

/// @audit Missing: '@param _recipient'
/// @audit Missing: '@param _amount'
138       /**
139        * @notice Moves `_amount` tokens from the caller's account to the `_recipient` account.
140        *
141        * @return a boolean value indicating whether the operation succeeded.
142        * Emits a `Transfer` event.
143        * Emits a `TransferShares` event.
144        *
145        * Requirements:
146        *
147        * - `_recipient` cannot be the zero address.
148        * - the caller must have a balance of at least `_amount`.
149        * - the contract must not be paused.
150        *
151        * @dev The `_amount` argument is the amount of tokens, not shares.
152        */
153:      function transfer(address _recipient, uint256 _amount) public returns (bool) {

/// @audit Missing: '@param _owner'
/// @audit Missing: '@param _spender'
159       /**
160        * @return the remaining number of tokens that `_spender` is allowed to spend
161        * on behalf of `_owner` through `transferFrom`. This is zero by default.
162        *
163        * @dev This value changes when `approve` or `transferFrom` is called.
164        */
165:      function allowance(address _owner, address _spender) public view returns (uint256) {

/// @audit Missing: '@param owner'
/// @audit Missing: '@param spender'
/// @audit Missing: '@param amount'
169       /**
170        * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
171        *
172        * Does not update the allowance amount in case of infinite allowance.
173        * Revert if not enough allowance is available.
174        *
175        * Might emit an {Approval} event.
176        */
177:      function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {

/// @audit Missing: '@param _spender'
/// @audit Missing: '@param _amount'
187       /**
188        * @notice Sets `_amount` as the allowance of `_spender` over the caller's tokens.
189        *
190        * @return a boolean value indicating whether the operation succeeded.
191        * Emits an `Approval` event.
192        *
193        * Requirements:
194        *
195        * - `_spender` cannot be the zero address.
196        * - the contract must not be paused.
197        *
198        * @dev The `_amount` argument is the amount of tokens, not shares.
199        */
200:      function approve(address _spender, uint256 _amount) public returns (bool) {

/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param amount'
206       /**
207        * @notice Moves `_amount` tokens from `_sender` to `_recipient` using the
208        * allowance mechanism. `_amount` is then deducted from the caller's
209        * allowance.
210        *
211        * @return a boolean value indicating whether the operation succeeded.
212        *
213        * Emits a `Transfer` event.
214        * Emits a `TransferShares` event.
215        * Emits an `Approval` event indicating the updated allowance.
216        *
217        * Requirements:
218        *
219        * - `_sender` and `_recipient` cannot be the zero addresses.
220        * - `_sender` must have a balance of at least `_amount`.
221        * - the caller must have allowance for `_sender`'s tokens of at least `_amount`.
222        * - the contract must not be paused.
223        *
224        * @dev The `_amount` argument is the amount of tokens, not shares.
225        */
226:      function transferFrom(address from, address to, uint256 amount) public returns (bool) {

/// @audit Missing: '@param _spender'
/// @audit Missing: '@param _addedValue'
235       /**
236        * @notice Atomically increases the allowance granted to `_spender` by the caller by `_addedValue`.
237        *
238        * This is an alternative to `approve` that can be used as a mitigation for
239        * problems described in:
240        * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42
241        * Emits an `Approval` event indicating the updated allowance.
242        *
243        * Requirements:
244        *
245        * - `_spender` cannot be the the zero address.
246        * - the contract must not be paused.
247        */
248:      function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) {

/// @audit Missing: '@param spender'
/// @audit Missing: '@param subtractedValue'
254       /**
255        * @notice Atomically decreases the allowance granted to `_spender` by the caller by `_subtractedValue`.
256        *
257        * This is an alternative to `approve` that can be used as a mitigation for
258        * problems described in:
259        * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42
260        * Emits an `Approval` event indicating the updated allowance.
261        *
262        * Requirements:
263        *
264        * - `_spender` cannot be the zero address.
265        * - `_spender` must have allowance for the caller of at least `_subtractedValue`.
266        * - the contract must not be paused.
267        */
268:      function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {

/// @audit Missing: '@param _account'
289       /**
290        * @return the amount of shares owned by `_account`.
291        */
292:      function sharesOf(address _account) public view returns (uint256) {

/// @audit Missing: '@param _EUSDAmount'
296       /**
297        * @return the amount of shares that corresponds to `_EUSDAmount` protocol-supplied EUSD.
298        */
299:      function getSharesByMintedEUSD(uint256 _EUSDAmount) public view returns (uint256) {

/// @audit Missing: '@param _sharesAmount'
308       /**
309        * @return the amount of EUSD that corresponds to `_sharesAmount` token shares.
310        */
311:      function getMintedEUSDByShares(uint256 _sharesAmount) public view returns (uint256) {

/// @audit Missing: '@param _recipient'
/// @audit Missing: '@param _sharesAmount'
319       /**
320        * @notice Moves `_sharesAmount` token shares from the caller's account to the `_recipient` account.
321        *
322        * @return amount of transferred tokens.
323        * Emits a `TransferShares` event.
324        * Emits a `Transfer` event.
325        *
326        * Requirements:
327        *
328        * - `_recipient` cannot be the zero address.
329        * - the caller must have at least `_sharesAmount` shares.
330        * - the contract must not be paused.
331        *
332        * @dev The `_sharesAmount` argument is the amount of shares, not tokens.
333        */
334:      function transferShares(address _recipient, uint256 _sharesAmount) public returns (uint256) {

/// @audit Missing: '@param _sender'
/// @audit Missing: '@param _recipient'
/// @audit Missing: '@param _amount'
343       /**
344        * @notice Moves `_amount` tokens from `_sender` to `_recipient`.
345        * Emits a `Transfer` event.
346        * Emits a `TransferShares` event.
347        */
348:      function _transfer(address _sender, address _recipient, uint256 _amount) internal {

/// @audit Missing: '@param _owner'
/// @audit Missing: '@param _spender'
/// @audit Missing: '@param _amount'
355       /**
356        * @notice Sets `_amount` as the allowance of `_spender` over the `_owner` s tokens.
357        *
358        * Emits an `Approval` event.
359        *
360        * Requirements:
361        *
362        * - `_owner` cannot be the zero address.
363        * - `_spender` cannot be the zero address.
364        * - the contract must not be paused.
365        */
366:      function _approve(address _owner, address _spender, uint256 _amount) internal {

/// @audit Missing: '@param _account'
374       /**
375        * @return the amount of shares owned by `_account`.
376        */
377:      function _sharesOf(address _account) internal view returns (uint256) {

/// @audit Missing: '@param _sender'
/// @audit Missing: '@param _recipient'
/// @audit Missing: '@param _sharesAmount'
381       /**
382        * @notice Moves `_sharesAmount` shares from `_sender` to `_recipient`.
383        *
384        * Requirements:
385        *
386        * - `_sender` cannot be the zero address.
387        * - `_recipient` cannot be the zero address.
388        * - `_sender` must hold at least `_sharesAmount` shares.
389        * - the contract must not be paused.
390        */
391:      function _transferShares(address _sender, address _recipient, uint256 _sharesAmount) internal {

/// @audit Missing: '@param _recipient'
/// @audit Missing: '@param _mintAmount'
402       /**
403        * @notice Creates `_sharesAmount` shares and assigns them to `_recipient`, increasing the total amount of shares.
404        * @dev This operation also increases the total supply of tokens.
405        *
406        * Requirements:
407        *
408        * - `_recipient` cannot be the zero address.
409        * - the contract must not be paused.
410        */
411:      function mint(address _recipient, uint256 _mintAmount) external onlyMintVault MintPaused returns (uint256 newTotalShares) {

/// @audit Missing: '@param _account'
/// @audit Missing: '@param _burnAmount'
430       /**
431        * @notice Destroys `sharesAmount` shares from `_account`'s holdings, decreasing the total amount of shares.
432        * @dev This operation also decrease the total supply of tokens.
433        *
434        * Requirements:
435        *
436        * - `_account` cannot be the zero address.
437        * - `_account` must hold at least `sharesAmount` shares.
438        * - the contract must not be paused.
439        */
440:      function burn(address _account, uint256 _burnAmount) external onlyMintVault BurnPaused returns (uint256 newTotalShares) {

/// @audit Missing: '@param _account'
/// @audit Missing: '@param _sharesAmount'
449       /**
450        * @notice Destroys `sharesAmount` shares from `_account`'s holdings, decreasing the total amount of shares.
451        * @dev This doesn't decrease the token total supply.
452        *
453        * Requirements:
454        *
455        * - `_account` cannot be the zero address.
456        * - `_account` must hold at least `sharesAmount` shares.
457        * - the contract must not be paused.
458        */
459:      function burnShares(address _account, uint256 _sharesAmount) external onlyMintVault BurnPaused returns (uint256 newTotalShares) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L128-L134

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit Missing: '@param share'
154       /// @notice Calculate the fee owed for the loaned tokens
155       /// @return The amount of shares you need to pay as a fee
156:      function getFee(uint256 share) public view returns (uint256) {

/// @audit Missing: '@param _from'
/// @audit Missing: '@param uint16'
/// @audit Missing: '@param bytes32'
/// @audit Missing: '@param _amount'
179       /************************************************************************
180        * internal functions
181        * @dev The following functions are internal functions of Layer Zero OFT, used for internal calls during cross-chain operations.
182        ************************************************************************/
183   
184:      function _debitFrom(address _from, uint16, bytes32, uint _amount) internal virtual override returns (uint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L154-L156

[N‑31] NatSpec @return argument is missing

There are 20 instances of this issue:

see instances
File: contracts/lybra/governance/LybraGovernance.sol

/// @audit Missing: '@return'
44          /**
45         * @notice module:user-config
46         * @dev Minimum number of cast voted required for a proposal to be successful.
47         *
48         * NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the
49         * quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}).
50         */
51:       function quorum(uint256 timepoint) public view override returns (uint256){

/// @audit Missing: '@return'
56        /**
57         * @dev Amount of votes already cast passes the threshold limit.
58         */
59:       function _quorumReached(uint256 proposalId) internal view override returns (bool){

/// @audit Missing: '@return'
63           /**
64         * @dev Is the proposal successful or not.
65         */
66:       function _voteSucceeded(uint256 proposalId) internal view override returns (bool){

/// @audit Missing: '@return'
94        /**
95         * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`.
96         */
97    
98:        function _getVotes(address account, uint256 timepoint, bytes memory) internal view override returns (uint256){

/// @audit Missing: '@return'
141        * duration compared to the voting delay.
142        */
143:      function votingPeriod() public pure override returns (uint256){

/// @audit Missing: '@return'
170        * @dev Part of the Governor Bravo's interface: _"The number of votes required in order for a voter to become a proposer"_.
171        */
172:      function proposalThreshold() public pure override returns (uint256) {

/// @audit Missing: '@return'
176       /**
177        * @dev See {IERC165-supportsInterface}.
178        */
179:      function supportsInterface(bytes4 interfaceId) public view virtual override(GovernorTimelockControl) returns (bool) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L44-L51

File: contracts/lybra/miner/esLBRBoost.sol

/// @audit Missing: '@return'
47        // Function to get the user's unlock time
48:       function getUnlockTime(address user) external view returns (uint256 unlockTime) {

/// @audit Missing: '@return'
52        /**
53         * @notice calculate the user's mining boost based on their lock status
54         * @dev Based on the user's userUpdatedAt time, finishAt time, and the current time,
55         * there are several scenarios that could occur, including no acceleration, full acceleration, and partial acceleration.
56         */
57:       function getUserBoost(address user, uint256 userUpdatedAt, uint256 finishAt) external view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L47-L48

File: contracts/lybra/miner/ProtocolRewardsPool.sol

/// @audit Missing: '@return'
63        // Total staked
64:       function totalStaked() internal view returns (uint256) {

/// @audit Missing: '@return'
68        // User address => esLBR balance
69:       function stakedOf(address staker) internal view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L63-L64

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

/// @audit Missing: '@return'
305        * @dev Return USD value of current ETH through Liquity PriceFeed Contract.
306        */
307:      function _etherPrice() internal returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L305-L307

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit Missing: '@return'
242        * @dev Return USD value of current ETH through Liquity PriceFeed Contract.
243        */
244:      function _etherPrice() internal returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L242-L244

File: contracts/lybra/pools/LybraStETHVault.sol

/// @audit Missing: '@return'
99         * The specific rule is that the discount rate increases by 1% every 30 minutes after the rebase occurs.
100        */
101:      function getDutchAuctionDiscountPrice() public view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L99-L101

File: contracts/lybra/token/EUSD.sol

/// @audit Missing: '@return'
235       /**
236        * @notice Atomically increases the allowance granted to `_spender` by the caller by `_addedValue`.
237        *
238        * This is an alternative to `approve` that can be used as a mitigation for
239        * problems described in:
240        * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42
241        * Emits an `Approval` event indicating the updated allowance.
242        *
243        * Requirements:
244        *
245        * - `_spender` cannot be the the zero address.
246        * - the contract must not be paused.
247        */
248:      function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) {

/// @audit Missing: '@return'
254       /**
255        * @notice Atomically decreases the allowance granted to `_spender` by the caller by `_subtractedValue`.
256        *
257        * This is an alternative to `approve` that can be used as a mitigation for
258        * problems described in:
259        * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42
260        * Emits an `Approval` event indicating the updated allowance.
261        *
262        * Requirements:
263        *
264        * - `_spender` cannot be the zero address.
265        * - `_spender` must have allowance for the caller of at least `_subtractedValue`.
266        * - the contract must not be paused.
267        */
268:      function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {

/// @audit Missing: '@return'
402       /**
403        * @notice Creates `_sharesAmount` shares and assigns them to `_recipient`, increasing the total amount of shares.
404        * @dev This operation also increases the total supply of tokens.
405        *
406        * Requirements:
407        *
408        * - `_recipient` cannot be the zero address.
409        * - the contract must not be paused.
410        */
411:      function mint(address _recipient, uint256 _mintAmount) external onlyMintVault MintPaused returns (uint256 newTotalShares) {

/// @audit Missing: '@return'
430       /**
431        * @notice Destroys `sharesAmount` shares from `_account`'s holdings, decreasing the total amount of shares.
432        * @dev This operation also decrease the total supply of tokens.
433        *
434        * Requirements:
435        *
436        * - `_account` cannot be the zero address.
437        * - `_account` must hold at least `sharesAmount` shares.
438        * - the contract must not be paused.
439        */
440:      function burn(address _account, uint256 _burnAmount) external onlyMintVault BurnPaused returns (uint256 newTotalShares) {

/// @audit Missing: '@return'
449       /**
450        * @notice Destroys `sharesAmount` shares from `_account`'s holdings, decreasing the total amount of shares.
451        * @dev This doesn't decrease the token total supply.
452        *
453        * Requirements:
454        *
455        * - `_account` cannot be the zero address.
456        * - `_account` must hold at least `sharesAmount` shares.
457        * - the contract must not be paused.
458        */
459:      function burnShares(address _account, uint256 _sharesAmount) external onlyMintVault BurnPaused returns (uint256 newTotalShares) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L235-L248

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit Missing: '@return'
179       /************************************************************************
180        * internal functions
181        * @dev The following functions are internal functions of Layer Zero OFT, used for internal calls during cross-chain operations.
182        ************************************************************************/
183   
184:      function _debitFrom(address _from, uint16, bytes32, uint _amount) internal virtual override returns (uint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L179-L184

[N‑32] Function definition modifier order does not follow Solidity style guide

See this link for an explanation of the correct ordering

There are 2 instances of this issue:

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit      function COUNTING_MODE() public override view virtual returns (){            return "support=bravo&quorum=for,abstain";      }  : override before virtual 
156:      function COUNTING_MODE() public override view virtual returns (string memory){

/// @audit      function hasVoted() public override view virtual returns (){          return proposalData[proposalId].receipts[account].hasVoted;      }  : override before virtual 
165:      function hasVoted(uint256 proposalId, address account) public override view virtual returns (bool){

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L156

[N‑33] Visibility should be set explicitly rather than defaulting to internal

There are 18 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

42:       mapping(address => uint256) vaultSafeCollateralRatio;

43:       mapping(address => uint256) vaultBadCollateralRatio;

46:       mapping(address => bool) redemptionProvider;

58:       uint256 maxStableRatio = 5_000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L42

File: contracts/lybra/miner/ProtocolRewardsPool.sol

39:       uint256 immutable exitCycle = 90 days;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L39

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

22:       IPriceFeed immutable etherOracle;

29:       mapping(address => uint256) borrowed;

30:       uint8 immutable vaultType = 0;

32:       mapping(address => uint256) depositedTime;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L22

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

18:       uint8 immutable vaultType = 1;

19:       IPriceFeed immutable etherOracle;

22:       mapping(address => uint256) borrowed;

23:       mapping(address => uint256) feeStored;

24:       mapping(address => uint256) feeUpdatedAt;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L18

File: contracts/lybra/pools/LybraRETHVault.sol

18:       IRkPool rkPool = IRkPool(0xDD3f50F8A6CafbE9b31a427582963f465E745AF8);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L18

File: contracts/lybra/pools/LybraWstETHVault.sol

22:       Ilido immutable lido;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L22

File: contracts/lybra/token/esLBR.sol

20:       uint256 maxSupply = 100_000_000 * 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L20

File: contracts/lybra/token/LBR.sol

15:       uint256 maxSupply = 100_000_000 * 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L15

[N‑34] Function ordering does not follow the Solidity style guide

According to the Solidity style guide, functions should be laid out in the following order :constructor(), receive(), fallback(), external, public, internal, private, but the cases below do not follow this pattern

There are 30 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit exchange_underlying() came earlier
80:       constructor(address _dao, address _curvePool) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L80

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit _execute() came earlier
112:      function proposals(uint256 proposalId) external view returns (uint256 id, address proposer, uint256 eta, uint256 startBlock, uint256 endBlock, uint256 forVotes, uint256 againstVotes, uint256 abstainVotes, bool canceled, bool executed) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L112

File: contracts/lybra/miner/EUSDMiningIncentives.sol

/// @audit getUserBoost() came earlier
64:       constructor(address _config, address _boost, address _etherOracle, address _lbrOracle) {

/// @audit totalStaked() came earlier
136:      function stakedOf(address user) public view returns (uint256) {

/// @audit rewardPerToken() came earlier
174:      function refreshReward(address _account) external updateReward(_account) {}

/// @audit isOtherEarningsClaimable() came earlier
192:      function getReward() external updateReward(msg.sender) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L64

File: contracts/lybra/miner/ProtocolRewardsPool.sol

/// @audit getUnlockTime() came earlier
48:       constructor(address _config) {

/// @audit stakedOf() came earlier
73:       function stake(uint256 amount) external {

/// @audit withdraw() came earlier
113       function unlockPrematurely() external {
114:          require(block.timestamp + exitCycle - 3 days > time2fullRedemption[msg.sender], "ENW");

/// @audit earned() came earlier
171:      function getClaimAbleUSD(address user) external view returns (uint256 amount) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L48

File: contracts/lybra/miner/stakerewardV2pool.sol

/// @audit getUserBoost() came earlier
49:       constructor(address _stakingToken, address _rewardToken, address _boost) {

/// @audit rewardPerToken() came earlier
83:       function stake(uint256 _amount) external updateReward(msg.sender) {

/// @audit earned() came earlier
111:      function getReward() external updateReward(msg.sender) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L49

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

/// @audit fetchPrice() came earlier
46:       constructor(address _collateralAsset, address _etherOracle, address _configurator) {

/// @audit checkWithdrawal() came earlier
126:      function mint(address onBehalfOf, uint256 amount) external {

/// @audit _etherPrice() came earlier
311:      function getBorrowedOf(address user) external view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L46

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit fetchPrice() came earlier
37:       constructor(address _peusd, address _etherOracle, address _collateral, address _configurator) {

/// @audit totalDepositedAsset() came earlier
48:       function depositEtherToMint(uint256 mintAmount) external payable virtual;

/// @audit _etherPrice() came earlier
253:      function getBorrowedOf(address user) public view returns (uint256) {

/// @audit getPoolTotalPeUSDCirculation() came earlier
261:      function getAsset() external view returns (address) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L37

File: contracts/lybra/pools/LybraRETHVault.sol

/// @audit deposit() came earlier
22        constructor(address _peusd, address _config, address _rETH, address _oracle, address _rkPool)
23:           LybraPeUSDVaultBase(_peusd, _oracle, _rETH, _config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L22-L23

File: contracts/lybra/pools/LybraStETHVault.sol

/// @audit submit() came earlier
18:       constructor(address _config, address _stETH, address _oracle) LybraEUSDVaultBase(_stETH, _oracle, _config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L18

File: contracts/lybra/pools/LybraWbETHVault.sol

/// @audit deposit() came earlier
17        constructor(address _peusd, address _oracle, address _asset, address _config)
18:           LybraPeUSDVaultBase(_peusd, _oracle, _asset, _config) {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L17-L18

File: contracts/lybra/pools/LybraWstETHVault.sol

/// @audit approve() came earlier
25:       constructor(address _lido, address _peusd, address _oracle, address _asset, address _config) LybraPeUSDVaultBase(_peusd, _oracle, _asset,_config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L25

File: contracts/lybra/token/esLBR.sol

/// @audit refreshReward() came earlier
22:       constructor(address _config) ERC20Permit("esLBR") ERC20("esLBR", "esLBR") {

/// @audit _transfer() came earlier
30:       function mint(address user, uint256 amount) external returns (bool) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L22

File: contracts/lybra/token/EUSD.sol

/// @audit _spendAllowance() came earlier
200:      function approve(address _spender, uint256 _amount) public returns (bool) {

/// @audit _transferShares() came earlier
411:      function mint(address _recipient, uint256 _mintAmount) external onlyMintVault MintPaused returns (uint256 newTotalShares) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L200

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit onFlashLoan() came earlier
55:       constructor(address _config, uint8 _sharedDecimals, address _lzEndpoint) ERC20("peg-eUSD", "PeUSD") BaseOFTV2(_sharedDecimals, _lzEndpoint) {

/// @audit convertToPeUSD() came earlier
97        function convertToPeUSDAndCrossChain(
98            uint256 eusdAmount,
99            uint16 dstChainId,
100           bytes32 toAddress,
101:          LzCallParams calldata callParams

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L55

[N‑35] Contract does not follow the Solidity style guide's suggested layout ordering

The style guide says that, within a contract, the ordering should be 1) Type declarations, 2) State variables, 3) Events, 4) Modifiers, and 5) Functions, but the contract(s) below do not follow this ordering

There are 16 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit function exchange_underlying came earlier
38        mapping(address => bool) public mintVault;
39        mapping(address => uint256) public mintVaultMaxSupply;
40        mapping(address => bool) public vaultMintPaused;
41        mapping(address => bool) public vaultBurnPaused;
42        mapping(address => uint256) vaultSafeCollateralRatio;
43        mapping(address => uint256) vaultBadCollateralRatio;
44        mapping(address => uint256) public vaultMintFeeApy;
45        mapping(address => uint256) public vaultKeeperRatio;
46        mapping(address => bool) redemptionProvider;
47:       mapping(address => bool) public tokenMiner;

/// @audit event FlashloanFeeUpdated came earlier
76:       bytes32 public constant DAO = keccak256("DAO");

/// @audit function constructor came earlier
85        modifier onlyRole(bytes32 role) {
86            GovernanceTimelock.checkOnlyRole(role, msg.sender);
87            _;
88:       }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L38-L47

File: contracts/lybra/miner/EUSDMiningIncentives.sol

/// @audit function getUserBoost came earlier
28:       Iconfigurator public immutable configurator;

/// @audit function constructor came earlier
72        modifier updateReward(address _account) {
73            rewardPerTokenStored = rewardPerToken();
74            updatedAt = lastTimeRewardApplicable();
75    
76            if (_account != address(0)) {
77                rewards[_account] = earned(_account);
78                userRewardPerTokenPaid[_account] = rewardPerTokenStored;
79                userUpdatedAt[_account] = block.timestamp;
80            }
81            _;
82:       }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L28

File: contracts/lybra/miner/ProtocolRewardsPool.sol

/// @audit function getUnlockTime came earlier
25:       Iconfigurator public immutable configurator;

/// @audit function getClaimAbleUSD came earlier
178       modifier updateReward(address account) {
179           rewards[account] = earned(account);
180           userRewardPerTokenPaid[account] = rewardPerTokenStored;
181           _;
182:      }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L25

File: contracts/lybra/miner/stakerewardV2pool.sol

/// @audit function getUserBoost came earlier
18:       IERC20 public immutable stakingToken;

/// @audit function constructor came earlier
56        modifier updateReward(address _account) {
57            rewardPerTokenStored = rewardPerToken();
58            updatedAt = lastTimeRewardApplicable();
59    
60            if (_account != address(0)) {
61                rewards[_account] = earned(_account);
62                userRewardPerTokenPaid[_account] = rewardPerTokenStored;
63                userUpdatedAt[_account] = block.timestamp;
64            }
65            _;
66:       }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L18

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

/// @audit function fetchPrice came earlier
18:       IEUSD public immutable EUSD;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L18

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit function fetchPrice came earlier
14:       IPeUSD public immutable PeUSD;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L14

File: contracts/lybra/pools/LybraRETHVault.sol

/// @audit function deposit came earlier
18:       IRkPool rkPool = IRkPool(0xDD3f50F8A6CafbE9b31a427582963f465E745AF8);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L18

File: contracts/lybra/pools/LybraStETHVault.sol

/// @audit function submit came earlier
14:       uint256 public lidoRebaseTime = 12 hours;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L14

File: contracts/lybra/pools/LybraWstETHVault.sol

/// @audit function approve came earlier
22:       Ilido immutable lido;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L22

File: contracts/lybra/token/esLBR.sol

/// @audit function refreshReward came earlier
18:       Iconfigurator public immutable configurator;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L18

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit function onFlashLoan came earlier
30:       IEUSD public immutable EUSD;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L30

[N‑36] Interfaces should be indicated with an I prefix in the contract name

There are 2 instances of this issue:

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

9:    interface LbrStakingPool {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L9

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

21:   interface FlashBorrower {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L21

[N‑37] Control structures do not follow the Solidity Style Guide

See the control structures section of the Solidity Style Guide

There are 12 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

199:          if(IVault(pool).vaultType() == 0) {

291:          if(peUSDBalance >= 1e21) {

298:              if(!premiumTradingEnabled || price <= 1005000) {

339:          if(vaultBadCollateralRatio[pool] == 0) return vaultSafeCollateralRatio[pool] - 1e19;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L199

File: contracts/lybra/miner/EUSDMiningIncentives.sol

204:          if(useEUSD) {

211:              if(useEUSD) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L204

File: contracts/lybra/miner/ProtocolRewardsPool.sol

198:              if(reward > eUSDShare) {

201:                  if(peUSDBalance >= reward - eUSDShare) {

205:                      if(peUSDBalance > 0) {

231:          if(tokenType == 0) {

234:          } else if(tokenType == 1) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L198

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

197:          if(amount >= totalFee) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L197

[N‑38] mapping definitions do not follow the Solidity Style Guide

See the mappings section of the Solidity Style Guide

There is one instance of this issue:

File: contracts/lybra/governance/LybraGovernance.sol

33:       mapping (uint256 => ProposalExtraData) public proposalData;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L33

[N‑39] Expressions for constant values such as a call to keccak256(), should use immutable rather than constant

While it doesn't save any gas because the compiler knows that developers often make this mistake, it's still best to use the right tool for the task at hand. There is a difference between constant variables and immutable variables, and they should each be used in their appropriate contexts. constants should be used for literal values written into the code, and immutable variables should be used for expressions, or values calculated in, or passed into the constructor.

There are 7 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

76:       bytes32 public constant DAO = keccak256("DAO");

77:       bytes32 public constant TIMELOCK = keccak256("TIMELOCK");

78:       bytes32 public constant ADMIN = keccak256("ADMIN");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L76

File: contracts/lybra/governance/GovernanceTimelock.sol

10:       bytes32 public constant DAO = keccak256("DAO");

11:       bytes32 public constant TIMELOCK = keccak256("TIMELOCK");

12:       bytes32 public constant ADMIN = keccak256("ADMIN");

13:       bytes32 public constant GOV = keccak256("GOV");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L10

[N‑40] Numeric values having to do with time should use time units for readability

There are units for seconds, minutes, hours, days, and weeks, and since they're defined, they should be used

There are 2 instances of this issue:

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

/// @audit 86400
301:          return (poolTotalEUSDCirculation * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - lastReportTime)) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L301

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit 86400
238:          return (borrowed[user] * configurator.vaultMintFeeApy(address(this)) * (block.timestamp - feeUpdatedAt[user])) / (86400 * 365) / 10000;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L238

[N‑41] Consider using delete rather than assigning zero/false to clear values

The delete keyword more closely matches the semantics of what is being done, and draws more attention to the changing of state, which may lead to a more thorough audit of its associated logic

There are 9 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

196:              rewards[msg.sender] = 0;

209:              rewards[user] = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L196

File: contracts/lybra/miner/ProtocolRewardsPool.sol

120:          unstakeRatio[msg.sender] = 0;

121:          time2fullRedemption[msg.sender] = 0;

144:          unstakeRatio[msg.sender] = 0;

145:          time2fullRedemption[msg.sender] = 0;

193:              rewards[msg.sender] = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L120

File: contracts/lybra/miner/stakerewardV2pool.sol

114:              rewards[msg.sender] = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L114

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

198:              feeStored[_onBehalfOf] = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L198

[N‑42] Contracts should have full test coverage

While 100% code coverage does not guarantee that there are no bugs, it often will catch easy-to-find bugs, and will ensure that there are fewer regressions when the code invariably has to be modified. Furthermore, in order to get full coverage, code authors will often have to re-organize their code so that it is more modular, so that each component can be tested separately, which reduces interdependencies between modules and layers, and makes for code that is easier to reason about and audit.

There is one instance of this issue:

File: Various Files

[N‑43] Large or complicated code bases should implement invariant tests

Large code bases, or code with lots of inline-assembly, complicated math, or complicated interactions between multiple contracts, should implement invariant fuzzing tests. Invariant fuzzers such as Echidna require the test writer to come up with invariants which should not be violated under any circumstances, and the fuzzer tests various inputs and function calls to ensure that the invariants always hold. Even code with 100% code coverage can still have bugs due to the order of the operations a user performs, and invariant fuzzers, with properly and extensively-written invariants, can close this testing gap significantly.

There is one instance of this issue:

File: Various Files

Gas Optimizations

[G‑01] Reduce gas usage by moving to Solidity 0.8.19 or later

See this link for the full details

There are 21 instances of this issue:

see instances
File: contracts/lybra/Proxy/LybraProxy.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxy.sol#L3-L3

File: contracts/lybra/Proxy/LybraProxyAdmin.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxyAdmin.sol#L3-L3

File: contracts/lybra/configuration/LybraConfigurator.sol

15:  pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L15-L15

File: contracts/lybra/governance/AdminTimelock.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/AdminTimelock.sol#L3-L3

File: contracts/lybra/governance/GovernanceTimelock.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L3-L3

File: contracts/lybra/governance/LybraGovernance.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L3-L3

File: contracts/lybra/miner/EUSDMiningIncentives.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L3-L3

File: contracts/lybra/miner/ProtocolRewardsPool.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L3-L3

File: contracts/lybra/miner/esLBRBoost.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L3-L3

File: contracts/lybra/miner/stakerewardV2pool.sol

2:   pragma solidity ^0.8;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L2-L2

File: contracts/lybra/pools/LybraRETHVault.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L3-L3

File: contracts/lybra/pools/LybraStETHVault.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L3-L3

File: contracts/lybra/pools/LybraWbETHVault.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L3-L3

File: contracts/lybra/pools/LybraWstETHVault.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L3-L3

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L3-L3

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L3-L3

File: contracts/lybra/token/EUSD.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L3-L3

File: contracts/lybra/token/LBR.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L3-L3

File: contracts/lybra/token/PeUSD.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L3-L3

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

14:  pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L14-L14

File: contracts/lybra/token/esLBR.sol

3:   pragma solidity ^0.8.17;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L3-L3

[G‑02] Avoid updating storage when the value hasn't changed

If the old value is equal to the new value, not re-storing the value will avoid a Gsreset (2900 gas), potentially at the expense of a Gcoldsload (2100 gas) or a Gwarmaccess (100 gas)

There are 17 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

167      function setPremiumTradingEnabled(bool isActive) external checkRole(TIMELOCK) {
168          premiumTradingEnabled = isActive;
169:     }

186      function setRedemptionFee(uint256 newFee) external checkRole(TIMELOCK) {
187          require(newFee <= 500, "Max Redemption Fee is 5%");
188          redemptionFee = newFee;
189          emit RedemptionFeeChanged(newFee);
190:     }

246      function setMaxStableRatio(uint256 _ratio) external checkRole(TIMELOCK) {
247          require(_ratio <= 10_000, "The maximum value is 10000");
248          maxStableRatio = _ratio;
249:     }

253      function setFlashloanFee(uint256 fee) external checkRole(TIMELOCK) {
254          if (fee > 10_000) revert('EL');
255          emit FlashloanFeeUpdated(fee);
256          flashloanFee = fee;
257:     }

261      function setProtocolRewardsToken(address _token) external checkRole(TIMELOCK) {
262          stableToken = _token;
263:     }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L167-L169

File: contracts/lybra/miner/EUSDMiningIncentives.sol

84       function setToken(address _lbr, address _eslbr) external onlyOwner {
85           LBR = _lbr;
86           esLBR = _eslbr;
87:      }

93       function setPools(address[] memory _pools) external onlyOwner {
94           for (uint i = 0; i < _pools.length; i++) {
95               require(configurator.mintVault(_pools[i]), "NOT_VAULT");
96           }
97           pools = _pools;
98:      }

100      function setBiddingCost(uint256 _biddingRatio) external onlyOwner {
101          require(_biddingRatio <= 8000, "BCE");
102          biddingFeeRatio = _biddingRatio;
103:     }

105      function setExtraRatio(uint256 ratio) external onlyOwner {
106          require(ratio <= 1e20, "BCE");
107          extraRatio = ratio;
108:     }

110      function setPeUSDExtraRatio(uint256 ratio) external onlyOwner {
111          require(ratio <= 1e20, "BCE");
112          peUSDExtraRatio = ratio;
113:     }

119      function setRewardsDuration(uint256 _duration) external onlyOwner {
120          require(finishAt < block.timestamp, "reward duration not finished");
121          duration = _duration;
122:     }

124      function setEthlbrStakeInfo(address _pool, address _lp) external onlyOwner {
125          ethlbrStakePool = _pool;
126          ethlbrLpToken = _lp;
127:     }

128      function setEUSDBuyoutAllowed(bool _bool) external onlyOwner {
129          isEUSDBuyoutAllowed = _bool;
130:     }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L84-L87

File: contracts/lybra/miner/ProtocolRewardsPool.sol

58       function setGrabCost(uint256 _ratio) external onlyOwner {
59           require(_ratio <= 8000, "BCE");
60           grabFeeRatio = _ratio;
61:      }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L58-L61

File: contracts/lybra/miner/stakerewardV2pool.sol

121      function setRewardsDuration(uint256 _duration) external onlyOwner {
122          require(finishAt < block.timestamp, "reward duration not finished");
123          duration = _duration;
124:     }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L121-L124

File: contracts/lybra/pools/LybraStETHVault.sol

25       function setLidoRebaseTime(uint256 _time) external {
26           require(configurator.hasRole(keccak256("ADMIN"), msg.sender), "not authorized");
27           lidoRebaseTime = _time;
28:      }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L25-L28

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

72       function depositAssetToMint(uint256 assetAmount, uint256 mintAmount) external virtual {
73           require(assetAmount >= 1 ether, "Deposit should not be less than 1 stETH.");
74   
75           bool success = collateralAsset.transferFrom(msg.sender, address(this), assetAmount);
76           require(success, "TF");
77   
78           totalDepositedAsset += assetAmount;
79           depositedAsset[msg.sender] += assetAmount;
80           depositedTime[msg.sender] = block.timestamp;
81   
82           if (mintAmount > 0) {
83               _mintEUSD(msg.sender, msg.sender, mintAmount, getAssetPrice());
84           }
85           emit DepositAsset(msg.sender, address(collateralAsset), assetAmount, block.timestamp);
86:      }

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L72-L86

[G‑03] Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate

Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations.

There are 7 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

38        mapping(address => bool) public mintVault;
39        mapping(address => uint256) public mintVaultMaxSupply;
40        mapping(address => bool) public vaultMintPaused;
41        mapping(address => bool) public vaultBurnPaused;
42        mapping(address => uint256) vaultSafeCollateralRatio;
43        mapping(address => uint256) vaultBadCollateralRatio;
44        mapping(address => uint256) public vaultMintFeeApy;
45        mapping(address => uint256) public vaultKeeperRatio;
46        mapping(address => bool) redemptionProvider;
47:       mapping(address => bool) public tokenMiner;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L38-L47

File: contracts/lybra/miner/EUSDMiningIncentives.sol

46        mapping(address => uint256) public userRewardPerTokenPaid;
47        // User address => rewards to be claimed
48        mapping(address => uint256) public rewards;
49:       mapping(address => uint256) public userUpdatedAt;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L46-L49

File: contracts/lybra/miner/ProtocolRewardsPool.sol

33        mapping(address => uint) public userRewardPerTokenPaid;
34        // User address => rewards to be claimed
35        mapping(address => uint) public rewards;
36        mapping(address => uint) public time2fullRedemption;
37        mapping(address => uint) public unstakeRatio;
38:       mapping(address => uint) public lastWithdrawTime;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L33-L38

File: contracts/lybra/miner/stakerewardV2pool.sol

33        mapping(address => uint256) public userRewardPerTokenPaid;
34        // User address => rewards to be claimed
35        mapping(address => uint256) public rewards;
36:       mapping(address => uint256) public userUpdatedAt;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L33-L36

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

28        mapping(address => uint256) public depositedAsset;
29:       mapping(address => uint256) borrowed;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L28-L29

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

21        mapping(address => uint256) public depositedAsset;
22        mapping(address => uint256) borrowed;
23        mapping(address => uint256) feeStored;
24:       mapping(address => uint256) feeUpdatedAt;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L21-L24

File: contracts/lybra/token/EUSD.sol

51        mapping(address => uint256) private shares;
52    
53        /**
54         * @dev Allowances are nominated in tokens, not token shares.
55         */
56:       mapping(address => mapping(address => uint256)) private allowances;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L51-L56

[G‑04] State variables only set in the constructor should be declared immutable

Avoids a Gsset (20000 gas) in the constructor, and replaces the first access in each transaction (Gcoldsload - 2100 gas) and each access thereafter (Gwarmacces - 100 gas) with a PUSH32 (3 gas).

While strings are not value types, and therefore cannot be immutable/constant if not hard-coded outside of the constructor, the same behavior can be achieved by making the current contract abstract with virtual functions for the string accessors, and having a child contract override the functions with the hard-coded implementation-specific values.

There are 5 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit GovernanceTimelock (constructor)
81:           GovernanceTimelock = IGovernanceTimelock(_dao);

/// @audit curvePool (constructor)
82:           curvePool = ICurvePool(_curvePool);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L81

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit esLBR (constructor)
40:           esLBR = IesLBR(_esLBR);

/// @audit GovernanceTimelock (constructor)
41:           GovernanceTimelock = IGovernanceTimelock(address(timelock_));

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L40

File: contracts/lybra/miner/EUSDMiningIncentives.sol

/// @audit etherPriceFeed (constructor)
68:           etherPriceFeed = AggregatorV3Interface(_etherOracle);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L68

[G‑05] Using storage instead of memory for structs/arrays saves gas

When fetching data from a storage location, assigning the data to a memory variable causes all fields of the struct/array to be read from storage, which incurs a Gcoldsload (2100 gas) for each field of the struct/array. If the fields are read from the new memory variable, they incur an additional MLOAD rather than a cheap stack read. Instead of declearing the variable with the memory keyword, declaring the variable with the storage keyword and caching any fields that need to be re-read in stack variables, will be much cheaper, only incuring the Gcoldsload for the fields actually read. The only time it makes sense to read the whole struct/array into a memory variable, is if the full struct/array is being returned by the function, is being passed to a function that requires memory, or if the array/struct is being read from another memory array/struct

There is one instance of this issue:

File: contracts/lybra/miner/esLBRBoost.sol

40:           LockStatus memory userStatus = userLockStatus[msg.sender];

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L40

[G‑06] State variables should be cached in stack variables rather than re-reading them from storage

The instances below point to the second+ access of a state variable within a function. Caching of a state variable replaces each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.

There are 22 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit lybraProtocolRewardsPool on line 292
293:              lybraProtocolRewardsPool.notifyRewardAmount(peUSDBalance, 2);

/// @audit lybraProtocolRewardsPool on line 293
299:                  EUSD.transfer(address(lybraProtocolRewardsPool), balance);

/// @audit lybraProtocolRewardsPool on line 299
300:                  lybraProtocolRewardsPool.notifyRewardAmount(balance, 0);

/// @audit lybraProtocolRewardsPool on line 304
305:                  lybraProtocolRewardsPool.notifyRewardAmount(amount, 1);

/// @audit EUSD on line 295
299:                  EUSD.transfer(address(lybraProtocolRewardsPool), balance);

/// @audit peUSD on line 290
292:              peUSD.transfer(address(lybraProtocolRewardsPool), peUSDBalance);

/// @audit curvePool on line 297
302:                  EUSD.approve(address(curvePool), balance);

/// @audit curvePool on line 302
303:                  uint256 amount = curvePool.exchange_underlying(0, 2, balance, balance * price * 998 / 1e21);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L293

File: contracts/lybra/miner/esLBRBoost.sol

/// @audit esLBRLockSettings on line 26
27:           esLBRLockSettings.push(esLBRLockSetting(90 days, 30 * 1e18));

/// @audit esLBRLockSettings on line 27
28:           esLBRLockSettings.push(esLBRLockSetting(180 days, 50 * 1e18));

/// @audit esLBRLockSettings on line 28
29:           esLBRLockSettings.push(esLBRLockSetting(365 days, 100 * 1e18));

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L27

File: contracts/lybra/miner/EUSDMiningIncentives.sol

/// @audit duration on line 234
239:          finishAt = block.timestamp + duration;

/// @audit rewardRatio on line 231
233:              uint256 remainingRewards = (finishAt - block.timestamp) * rewardRatio;

/// @audit rewardRatio on line 234
237:          require(rewardRatio > 0, "reward ratio = 0");

/// @audit ethlbrLpToken on line 150
153:          uint256 etherInLp = (IEUSD(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2).balanceOf(ethlbrLpToken) * uint(etherPrice)) / 1e8;

/// @audit ethlbrLpToken on line 153
154:          uint256 lbrInLp = (IEUSD(LBR).balanceOf(ethlbrLpToken) * uint(lbrPrice)) / 1e8;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L239

File: contracts/lybra/miner/stakerewardV2pool.sol

/// @audit duration on line 137
142:          finishAt = block.timestamp + duration;

/// @audit rewardRatio on line 134
136:              uint256 remainingRewards = (finishAt - block.timestamp) * rewardRatio;

/// @audit rewardRatio on line 137
140:          require(rewardRatio > 0, "reward ratio = 0");

/// @audit totalSupply on line 75
79:           return rewardPerTokenStored + (rewardRatio * (lastTimeRewardApplicable() - updatedAt) * 1e18) / totalSupply;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L142

File: contracts/lybra/token/EUSD.sol

/// @audit _totalShares on line 312
315:              return _sharesAmount.mul(_totalSupply).div(_totalShares);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L315

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit userConvertInfo[<etc>].mintedPeUSD on line 115
117:          uint256 share = (userConvertInfo[msg.sender].depositedEUSDShares * peusdAmount) / userConvertInfo[msg.sender].mintedPeUSD;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L117

[G‑07] Multiple accesses of a mapping/array should use a local variable cache

The instances below point to the second+ access of a value inside a mapping/array, within a function. Caching a mapping's value in a local storage or calldata variable when the value is accessed multiple times, saves ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations. Caching an array's struct avoids recalculating the array offsets into memory/calldata

There are 13 instances of this issue:

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit proposalData[proposalId] on line 60
60:           return proposalData[proposalId].supportVotes[1] + proposalData[proposalId].supportVotes[2] >= quorum(proposalSnapshot(proposalId));

/// @audit proposalData[proposalId] on line 67
67:           return proposalData[proposalId].supportVotes[1] > proposalData[proposalId].supportVotes[0];

/// @audit proposalData[proposalId] on line 120
121:          againstVotes =  proposalData[proposalId].supportVotes[1];

/// @audit proposalData[proposalId] on line 121
122:          abstainVotes =  proposalData[proposalId].supportVotes[2];

/// @audit proposalData[proposalId] on line 130
131:          support = proposalData[proposalId].receipts[account].support;

/// @audit proposalData[proposalId] on line 131
132:          votes = proposalData[proposalId].receipts[account].votes;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L60

File: contracts/lybra/miner/esLBRBoost.sol

/// @audit userLockStatus[user] on line 58
59:           uint256 maxBoost = userLockStatus[user].miningBoost;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L59

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit userConvertInfo[user] on line 85
86:           userConvertInfo[user].mintedPeUSD += eusdAmount;

/// @audit userConvertInfo[<etc>] on line 115
/// @audit userConvertInfo[<etc>] on line 117
117:          uint256 share = (userConvertInfo[msg.sender].depositedEUSDShares * peusdAmount) / userConvertInfo[msg.sender].mintedPeUSD;

/// @audit userConvertInfo[<etc>] on line 117
118:          userConvertInfo[msg.sender].mintedPeUSD -= peusdAmount;

/// @audit userConvertInfo[<etc>] on line 118
119:          userConvertInfo[msg.sender].depositedEUSDShares -= share;

/// @audit userConvertInfo[user] on line 168
168:          return EUSD.getMintedEUSDByShares(userConvertInfo[user].depositedEUSDShares) - userConvertInfo[user].mintedPeUSD;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L86

[G‑08] The result of function calls should be cached rather than re-calling the function

The instances below point to the second+ call of the function within a single function

There is one instance of this issue:

File: contracts/lybra/pools/LybraStETHVault.sol

/// @audit configurator.distributeRewards() on line 73
87:               try configurator.distributeRewards() {} catch {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L87

[G‑09] <x> += <y> costs more gas than <x> = <x> + <y> for state variables

Using the addition operator instead of plus-equals saves 113 gas

There are 16 instances of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

122:          grabableAmount += burnAmount;

133:          grabableAmount -= amount;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L122

File: contracts/lybra/miner/stakerewardV2pool.sol

88:           totalSupply += _amount;

96:           totalSupply -= _amount;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L88

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

78:           totalDepositedAsset += assetAmount;

102:          totalDepositedAsset -= amount;

165:          totalDepositedAsset -= reducedAsset;

201:          totalDepositedAsset -= assetAmount;

241:          totalDepositedAsset -= collateralAmount;

266:          poolTotalEUSDCirculation += _mintAmount;

284:          poolTotalEUSDCirculation -= amount;

296:          feeStored += _newFee();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L78

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

182:          poolTotalPeUSDCirculation += _mintAmount;

207:          poolTotalPeUSDCirculation -= amount;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L182

File: contracts/lybra/token/EUSD.sol

425:          _totalSupply += _mintAmount;

444:          _totalSupply -= _burnAmount;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L425

[G‑10] internal functions only called once can be inlined to save gas

Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.

There is one instance of this issue:

File: contracts/lybra/miner/ProtocolRewardsPool.sol

69:       function stakedOf(address staker) internal view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L69

[G‑11] Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if-statement

require(a <= b); x = b - a => require(a <= b); unchecked { x = b - a }

There are 16 instances of this issue:

see instances
File: contracts/lybra/token/EUSD.sol

/// @audit require() on line 180
182:                  _approve(owner, spender, currentAllowance - amount);

/// @audit require() on line 271
273:              _approve(owner, spender, currentAllowance - subtractedValue);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L182

File: contracts/lybra/token/LBR.sol

/// @audit require() on line 21
22:           ld2sdRatio = 10 ** (decimals - _sharedDecimals);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L22

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit require() on line 59
60:           ld2sdRatio = 10 ** (decimals - _sharedDecimals);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L60

File: contracts/lybra/token/PeUSD.sol

/// @audit require() on line 13
14:           ld2sdRatio = 10 ** (decimals - _sharedDecimals);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L14

File: contracts/lybra/miner/ProtocolRewardsPool.sol

/// @audit if-condition on line 92
93:               total += unstakeRatio[msg.sender] * (time2fullRedemption[msg.sender] - block.timestamp);

/// @audit if-condition on line 156
157:              amount = block.timestamp > time2fullRedemption[user] ? unstakeRatio[user] * (time2fullRedemption[user] - lastWithdrawTime[user]) : unstakeRatio[user] * (block.timestamp - lastWithdrawTime[user]);

/// @audit if-condition on line 162
163:              amount = unstakeRatio[user] * (time2fullRedemption[user] - block.timestamp);

/// @audit if-condition on line 198
201:                  if(peUSDBalance >= reward - eUSDShare) {

/// @audit if-condition on line 198
202:                      peUSD.transfer(msg.sender, reward - eUSDShare);

/// @audit if-condition on line 198
203:                      emit ClaimReward(msg.sender, EUSD.getMintedEUSDByShares(eUSDShare), address(peUSD), reward - eUSDShare, block.timestamp);

/// @audit if-condition on line 198
209:                      uint256 tokenAmount = (reward - eUSDShare - peUSDBalance) * token.decimals() / 1e18;

/// @audit if-condition on line 198
211:                      emit ClaimReward(msg.sender, EUSD.getMintedEUSDByShares(eUSDShare), address(token), reward - eUSDShare, block.timestamp);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L93

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit if-condition on line 197
200:              PeUSD.burn(_provider, amount - totalFee);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L200

File: contracts/lybra/pools/LybraStETHVault.sol

/// @audit if-condition on line 69
75:               uint256 sharesAmount = EUSD.getSharesByMintedEUSD(payAmount - income);

/// @audit if-condition on line 69
78:                   sharesAmount = (payAmount - income);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L75

[G‑12] <array>.length should not be looked up in every loop of a for-loop

The overheads outlined below are PER LOOP, excluding the first loop

  • storage arrays incur a Gwarmaccess (100 gas)
  • memory arrays use MLOAD (3 gas)
  • calldata arrays use CALLDATALOAD (3 gas)

Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset

There are 3 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

236:          for (uint256 i = 0; i < _contracts.length; i++) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L236

File: contracts/lybra/miner/EUSDMiningIncentives.sol

94:           for (uint i = 0; i < _pools.length; i++) {

138:          for (uint i = 0; i < pools.length; i++) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L94

[G‑13] ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop

There are 3 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

236:          for (uint256 i = 0; i < _contracts.length; i++) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L236

File: contracts/lybra/miner/EUSDMiningIncentives.sol

94:           for (uint i = 0; i < _pools.length; i++) {

138:          for (uint i = 0; i < pools.length; i++) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L94

[G‑14] require()/revert() strings longer than 32 bytes cost extra gas

Each extra memory word of bytes past the original 32 incurs an MSTORE which costs 3 gas

There are 39 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

200:              require(newRatio >= 160 * 1e18, "eUSD vault safe collateralRatio should more than 160%");

202:              require(newRatio >= vaultBadCollateralRatio[pool] + 1e19, "PeUSD vault safe collateralRatio should more than bad collateralRatio");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L200

File: contracts/lybra/governance/LybraGovernance.sol

78:           require(state(proposalId) == ProposalState.Active, "GovernorBravo::castVoteInternal: voting is closed");

79:           require(support <= 2, "GovernorBravo::castVoteInternal: invalid vote type");

82:           require(receipt.hasVoted == false, "GovernorBravo::castVoteInternal: voter already voted");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L78

File: contracts/lybra/miner/esLBRBoost.sol

42:               require(userStatus.duration <= _setting.duration, "Your lock-in period has not ended, and the term can only be extended, not reduced.");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L42

File: contracts/lybra/miner/EUSDMiningIncentives.sol

193:          require(!isOtherEarningsClaimable(msg.sender), "Insufficient DLP, unable to claim rewards");

203:          require(isOtherEarningsClaimable(user), "The rewards of the user cannot be bought out");

205:              require(isEUSDBuyoutAllowed, "The purchase using EUSD is not permitted.");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L193

File: contracts/lybra/miner/ProtocolRewardsPool.sol

88:           require(block.timestamp >= esLBRBoost.getUnlockTime(msg.sender), "Your lock-in period has not ended. You can't convert your esLBR now.");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L88

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

73:           require(assetAmount >= 1 ether, "Deposit should not be less than 1 stETH.");

101:          require(depositedAsset[msg.sender] >= amount, "Withdraw amount exceeds deposited amount.");

157:          require(onBehalfOfCollateralRatio < badCollateralRatio, "Borrowers collateral ratio should below badCollateralRatio");

159:          require(assetAmount * 2 <= depositedAsset[onBehalfOf], "a max of 50% collateral can be liquidated");

160:          require(EUSD.allowance(provider, address(this)) > 0, "provider should authorize to provide liquidation EUSD");

189:          require((totalDepositedAsset * assetPrice * 100) / poolTotalEUSDCirculation < badCollateralRatio, "overallCollateralRatio should below 150%");

191:          require(onBehalfOfCollateralRatio < 125 * 1e18, "borrowers collateralRatio should below 125%");

192:          require(assetAmount <= depositedAsset[onBehalfOf], "total of collateral can be liquidated at most");

197:          require(EUSD.allowance(provider, address(this)) >= eusdAmount, "provider should authorize to provide liquidation EUSD");

233:          require(configurator.isRedemptionProvider(provider), "provider is not a RedemptionProvider");

234:          require(borrowed[provider] >= eusdAmount, "eusdAmount cannot surpass providers debt");

237:          require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");

292:          if (((depositedAsset[_user] * _assetPrice * 100) / borrowed[_user]) < configurator.getSafeCollateralRatio(address(this))) revert("collateralRatio is Below safeCollateralRatio");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L73

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

59:           require(assetAmount >= 1 ether, "Deposit should not be less than 1 collateral asset.");

128:          require(onBehalfOfCollateralRatio < configurator.getBadCollateralRatio(address(this)), "Borrowers collateral ratio should below badCollateralRatio");

130:          require(assetAmount * 2 <= depositedAsset[onBehalfOf], "a max of 50% collateral can be liquidated");

131:          require(PeUSD.allowance(provider, address(this)) > 0, "provider should authorize to provide liquidation EUSD");

158:          require(configurator.isRedemptionProvider(provider), "provider is not a RedemptionProvider");

159:          require(borrowed[provider] >= peusdAmount, "peusdAmount cannot surpass providers debt");

162:          require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");

213:          require(depositedAsset[_provider] >= _amount, "Withdraw amount exceeds deposited amount.");

227:              revert("collateralRatio is Below safeCollateralRatio");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L59

File: contracts/lybra/pools/LybraStETHVault.sol

64:           require(excessAmount > 0 && stETHAmount > 0, "Only LSD excess income can be exchanged");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L64

File: contracts/lybra/token/esLBR.sol

32:           require(totalSupply() + amount <= maxSupply, "exceeding the maximum supply quantity.");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L32

File: contracts/lybra/token/EUSD.sol

271:          require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L271

File: contracts/lybra/token/LBR.sol

21:           require(_sharedDecimals <= decimals, "OFT: sharedDecimals must be <= decimals");

27:           require(totalSupply() + amount <= maxSupply, "exceeding the maximum supply quantity.");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L21

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

59:           require(_sharedDecimals <= decimals, "OFT: sharedDecimals must be <= decimals");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L59

File: contracts/lybra/token/PeUSD.sol

13:           require(_sharedDecimals <= decimals, "OFT: sharedDecimals must be <= decimals");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L13

[G‑15] keccak256() should only need to be called on a specific string literal once

It should be saved to an immutable variable, and the variable used instead. If the hash is being used as a part of a function selector, the cast to bytes4 should also only be done once

There are 3 instances of this issue:

File: contracts/lybra/governance/LybraGovernance.sol

107:          require(GovernanceTimelock.checkOnlyRole(keccak256("TIMELOCK"), msg.sender), "not authorized");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L107

File: contracts/lybra/pools/LybraRETHVault.sol

42:           require(configurator.hasRole(keccak256("TIMELOCK"), msg.sender));

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L42

File: contracts/lybra/pools/LybraStETHVault.sol

26:           require(configurator.hasRole(keccak256("ADMIN"), msg.sender), "not authorized");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L26

[G‑16] Optimize names to save gas

public/external function names and public member variable names can be optimized to save gas. See this link for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted

There are 15 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

/// @audit get_dy_underlying(), exchange_underlying()
32:   interface ICurvePool{

/// @audit initToken(), setMintVault(), setMintVaultMaxSupply(), setBadCollateralRatio(), setProtocolRewardsPool(), setEUSDMiningIncentives(), setvaultBurnPaused(), setPremiumTradingEnabled(), setvaultMintPaused(), setRedemptionFee(), setSafeCollateralRatio(), setBorrowApy(), setKeeperRatio(), setTokenMiner(), setMaxStableRatio(), setFlashloanFee(), setProtocolRewardsToken(), becomeRedemptionProvider(), refreshMintReward(), distributeRewards(), getEUSDAddress(), getProtocolRewardsPool(), getSafeCollateralRatio(), getBadCollateralRatio(), isRedemptionProvider(), getEUSDMaxLocked()
37:   contract Configurator {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L32

File: contracts/lybra/governance/GovernanceTimelock.sol

/// @audit checkRole(), checkOnlyRole()
8:    contract GovernanceTimelock is TimelockController {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L8

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit proposals(), getReceipt()
9:    contract LybraGovernance is GovernorTimelockControl {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L9

File: contracts/lybra/miner/esLBRBoost.sol

/// @audit addLockSetting(), setLockStatus(), getUnlockTime(), getUserBoost()
7:    contract esLBRBoost is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L7

File: contracts/lybra/miner/EUSDMiningIncentives.sol

/// @audit setToken(), setLBROracle(), setPools(), setBiddingCost(), setExtraRatio(), setPeUSDExtraRatio(), setBoost(), setRewardsDuration(), setEthlbrStakeInfo(), setEUSDBuyoutAllowed(), stakedOf(), stakedLBRLpValue(), lastTimeRewardApplicable(), rewardPerToken(), refreshReward(), getBoost(), earned(), isOtherEarningsClaimable(), getReward(), purchaseOtherEarnings(), notifyRewardAmount()
27:   contract EUSDMiningIncentives is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L27

File: contracts/lybra/miner/ProtocolRewardsPool.sol

/// @audit setTokenAddress(), setGrabCost(), stake(), unstake(), withdraw(), unlockPrematurely(), grabEsLBR(), reStake(), getPreUnlockableAmount(), getClaimAbleLBR(), getReservedLBRForVesting(), earned(), getClaimAbleUSD(), refreshReward(), getReward(), notifyRewardAmount()
24:   contract ProtocolRewardsPool is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L24

File: contracts/lybra/miner/stakerewardV2pool.sol

/// @audit lastTimeRewardApplicable(), rewardPerToken(), stake(), getBoost(), earned(), getReward(), setRewardsDuration(), setBoost(), notifyRewardAmount()
16:   contract StakingRewardsV2 is Ownable {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L16

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

/// @audit depositEtherToMint(), depositAssetToMint(), withdraw(), liquidation(), superLiquidation(), excessIncomeDistribution(), rigidRedemption(), getBorrowedOf(), getPoolTotalEUSDCirculation(), getAsset(), getVaultType(), getAssetPrice()
17:   abstract contract LybraEUSDVaultBase {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L17

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

/// @audit totalDepositedAsset(), depositEtherToMint(), depositAssetToMint(), withdraw(), liquidation(), rigidRedemption(), getBorrowedOf(), getPoolTotalPeUSDCirculation(), getAsset(), getVaultType(), getAssetPrice()
13:   abstract contract LybraPeUSDVaultBase {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L13

File: contracts/lybra/pools/LybraStETHVault.sol

/// @audit setLidoRebaseTime(), getDutchAuctionDiscountPrice()
12:   contract LybraStETHDepositVault is LybraEUSDVaultBase {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L12

File: contracts/lybra/pools/LybraWbETHVault.sol

/// @audit exchangeRatio(), deposit()
9:    interface IWBETH {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L9

File: contracts/lybra/pools/LybraWstETHVault.sol

/// @audit stEthPerToken(), wrap()
9:    interface IWstETH {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L9

File: contracts/lybra/token/EUSD.sol

/// @audit getTotalShares(), sharesOf(), getSharesByMintedEUSD(), getMintedEUSDByShares(), transferShares(), burnShares()
37:   contract EUSD is IERC20, Context {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L37

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit convertToPeUSD(), convertToPeUSDAndCrossChain(), convertToEUSD(), executeFlashloan(), getFee(), getAccruedEUSDInterest()
29:   contract PeUSDMainnet is BaseOFTV2, ERC20 {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L29

[G‑17] Using bools for storage incurs overhead

    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27 Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from false to true, after having been true in the past

There are 7 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

38:       mapping(address => bool) public mintVault;

40:       mapping(address => bool) public vaultMintPaused;

41:       mapping(address => bool) public vaultBurnPaused;

46:       mapping(address => bool) redemptionProvider;

47:       mapping(address => bool) public tokenMiner;

61:       bool public premiumTradingEnabled;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L38

File: contracts/lybra/miner/EUSDMiningIncentives.sol

57:       bool public isEUSDBuyoutAllowed = true;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L57

[G‑18] Use a more recent version of solidity

Use a solidity version of at least 0.8.2 to get simple compiler automatic inlining Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value

There is one instance of this issue:

File: contracts/lybra/miner/stakerewardV2pool.sol

2:    pragma solidity ^0.8;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L2

[G‑19] Using > 0 costs more gas than != 0 when used on a uint in a require() statement

This change saves 6 gas per instance. The optimization works until solidity version 0.8.13 where there is a regression in gas costs.

There are 3 instances of this issue:

File: contracts/lybra/miner/stakerewardV2pool.sol

84:           require(_amount > 0, "amount = 0");

94:           require(_amount > 0, "amount = 0");

140:          require(rewardRatio > 0, "reward ratio = 0");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L84

[G‑20] >= costs less gas than >

The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=, which saves 3 gas

There are 2 instances of this issue:

File: contracts/lybra/miner/esLBRBoost.sol

66:               uint256 time = block.timestamp > finishAt ? finishAt : block.timestamp;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L66

File: contracts/lybra/pools/LybraStETHVault.sol

65:           uint256 realAmount = stETHAmount > excessAmount ? excessAmount : stETHAmount;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L65

[G‑21] ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too)

Saves 5 gas per loop

There are 3 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

236:          for (uint256 i = 0; i < _contracts.length; i++) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L236

File: contracts/lybra/miner/EUSDMiningIncentives.sol

94:           for (uint i = 0; i < _pools.length; i++) {

138:          for (uint i = 0; i < pools.length; i++) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L94

[G‑22] Splitting require() statements that use && saves gas

See this issue which describes the fact that there is a larger deployment gas cost, but with enough runtime calls, the change ends up being cheaper by 3 gas

There are 3 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

127:          require(newRatio >= 130 * 1e18 && newRatio <= 150 * 1e18 && newRatio <= vaultSafeCollateralRatio[pool] + 1e19, "LNA");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L127

File: contracts/lybra/pools/LybraStETHVault.sol

64:           require(excessAmount > 0 && stETHAmount > 0, "Only LSD excess income can be exchanged");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L64

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

115:          require(peusdAmount <= userConvertInfo[msg.sender].mintedPeUSD &&peusdAmount > 0, "PCE");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L115

[G‑23] Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead

When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.

https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Each operation involving a uint8 costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8) as compared to ones involving uint256, due to the compiler having to clear the higher bits of the memory word before operating on the uint8, as well as the associated stack operations of doing so. Use a larger size then downcast where needed

There is one instance of this issue:

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit uint8 support
131:          support = proposalData[proposalId].receipts[account].support;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L131

[G‑24] Using private rather than public for constants, saves gas

If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table

There are 8 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

76:       bytes32 public constant DAO = keccak256("DAO");

77:       bytes32 public constant TIMELOCK = keccak256("TIMELOCK");

78:       bytes32 public constant ADMIN = keccak256("ADMIN");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L76

File: contracts/lybra/governance/GovernanceTimelock.sol

10:       bytes32 public constant DAO = keccak256("DAO");

11:       bytes32 public constant TIMELOCK = keccak256("TIMELOCK");

12:       bytes32 public constant ADMIN = keccak256("ADMIN");

13:       bytes32 public constant GOV = keccak256("GOV");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L10

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

21:       uint256 public immutable badCollateralRatio = 150 * 1e18;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L21

[G‑25] Don't compare boolean expressions to boolean literals

if (<x> == true) => if (<x>), if (<x> == false) => if (!<x>)

There is one instance of this issue:

File: contracts/lybra/governance/LybraGovernance.sol

82:           require(receipt.hasVoted == false, "GovernorBravo::castVoteInternal: voter already voted");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L82

[G‑26] Don't use SafeMath once the solidity version is 0.8.0 or greater

Version 0.8.0 introduces internal overflow checks, so using SafeMath is redundant and adds overhead

There is one instance of this issue:

File: contracts/lybra/token/EUSD.sol

5:    import "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L5

[G‑27] require() or revert() statements that check input arguments should be at the top of the function

Checks that involve constants should come before checks that involve state variables, function calls, and calculations. By doing these checks first, the function is able to revert before wasting a Gcoldsload (2100 gas*) in a function that may ultimately revert in the unhappy case.

There are 2 instances of this issue:

File: contracts/lybra/governance/LybraGovernance.sol

/// @audit expensive op on line 78
79:           require(support <= 2, "GovernorBravo::castVoteInternal: invalid vote type");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L79

File: contracts/lybra/miner/ProtocolRewardsPool.sol

/// @audit expensive op on line 229
230:          require(amount > 0, "amount = 0");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L230

[G‑28] Empty blocks should be removed or emit something

The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract and the function signatures be added without any default implementation. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if (x) {...} else if (y) {...} else {...} => if (!x) { if (y) {...} else {...} }). Empty receive()/fallback() payable functions that are not used, can be removed to save deployment gas.

There are 20 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

216:                  try configurator.distributeRewards() {} catch {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L216

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

261:          try configurator.refreshMintReward(_provider) {} catch {}

280:          try configurator.refreshMintReward(_onBehalfOf) {} catch {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L261

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

177:          try configurator.refreshMintReward(_provider) {} catch {}

193:          try configurator.refreshMintReward(_onBehalfOf) {} catch {}

205:          try configurator.distributeRewards() {} catch {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L177

File: contracts/lybra/pools/LybraStETHVault.sol

73:               try configurator.distributeRewards() {} catch {}

87:               try configurator.distributeRewards() {} catch {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L73

File: contracts/lybra/token/esLBR.sol

33:           try IProtocolRewardsPool(configurator.getProtocolRewardsPool()).refreshReward(user) {} catch {}

40:           try IProtocolRewardsPool(configurator.getProtocolRewardsPool()).refreshReward(user) {} catch {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L33

[G‑29] Superfluous event fields

block.timestamp and block.number are added to event information by default so adding them manually wastes gas

There are 19 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

66:       event ProtocolRewardsPoolChanged(address indexed pool, uint256 timestamp);

67:       event EUSDMiningIncentivesChanged(address indexed pool, uint256 timestamp);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L66

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

34:       event DepositEther(address indexed onBehalfOf, address asset, uint256 etherAmount, uint256 assetAmount, uint256 timestamp);

36:       event DepositAsset(address indexed onBehalfOf, address asset, uint256 amount, uint256 timestamp);

38:       event WithdrawAsset(address sponsor, address asset, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

39:       event Mint(address sponsor, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

40:       event Burn(address sponsor, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

41:       event LiquidationRecord(address provider, address keeper, address indexed onBehalfOf, uint256 eusdamount, uint256 liquidateEtherAmount, uint256 keeperReward, bool superLiquidation, uint256 timestamp);

42:       event LSDValueCaptured(uint256 stETHAdded, uint256 payoutEUSD, uint256 discountRate, uint256 timestamp);

43:       event RigidRedemption(address indexed caller, address indexed provider, uint256 eusdAmount, uint256 collateralAmount, uint256 timestamp);

44:       event FeeDistribution(address indexed feeAddress, uint256 feeAmount, uint256 timestamp);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L34

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

26:       event DepositEther(address indexed onBehalfOf, address asset, uint256 etherAmount, uint256 assetAmount, uint256 timestamp);

28:       event DepositAsset(address indexed onBehalfOf, address asset, uint256 amount, uint256 timestamp);

29:       event WithdrawAsset(address sponsor, address indexed onBehalfOf, address asset, uint256 amount, uint256 timestamp);

30:       event Mint(address sponsor, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

31:       event Burn(address sponsor, address indexed onBehalfOf, uint256 amount, uint256 timestamp);

32:       event LiquidationRecord(address provider, address keeper, address indexed onBehalfOf, uint256 eusdamount, uint256 LiquidateAssetAmount, uint256 keeperReward, bool superLiquidation, uint256 timestamp);

34:       event RigidRedemption(address indexed caller, address indexed provider, uint256 peusdAmount, uint256 assetAmount, uint256 timestamp);

35:       event FeeDistribution(address indexed feeAddress, uint256 feeAmount, uint256 timestamp);

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L26

[G‑30] Use custom errors rather than revert()/require() strings to save gas

Custom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they're hit by avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas

There are 111 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

127:          require(newRatio >= 130 * 1e18 && newRatio <= 150 * 1e18 && newRatio <= vaultSafeCollateralRatio[pool] + 1e19, "LNA");

187:          require(newFee <= 500, "Max Redemption Fee is 5%");

200:              require(newRatio >= 160 * 1e18, "eUSD vault safe collateralRatio should more than 160%");

202:              require(newRatio >= vaultBadCollateralRatio[pool] + 1e19, "PeUSD vault safe collateralRatio should more than bad collateralRatio");

214:          require(newApy <= 200, "Borrow APY cannot exceed 2%");

225:          require(newRatio <= 5, "Max Keeper reward is 5%");

247:          require(_ratio <= 10_000, "The maximum value is 10000");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L127

File: contracts/lybra/governance/LybraGovernance.sol

78:           require(state(proposalId) == ProposalState.Active, "GovernorBravo::castVoteInternal: voting is closed");

79:           require(support <= 2, "GovernorBravo::castVoteInternal: invalid vote type");

82:           require(receipt.hasVoted == false, "GovernorBravo::castVoteInternal: voter already voted");

107:          require(GovernanceTimelock.checkOnlyRole(keccak256("TIMELOCK"), msg.sender), "not authorized");

152:         require(clock() == block.number, "Votes: broken clock mode");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L78

File: contracts/lybra/miner/esLBRBoost.sol

42:               require(userStatus.duration <= _setting.duration, "Your lock-in period has not ended, and the term can only be extended, not reduced.");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L42

File: contracts/lybra/miner/EUSDMiningIncentives.sol

95:               require(configurator.mintVault(_pools[i]), "NOT_VAULT");

101:          require(_biddingRatio <= 8000, "BCE");

106:          require(ratio <= 1e20, "BCE");

111:          require(ratio <= 1e20, "BCE");

120:          require(finishAt < block.timestamp, "reward duration not finished");

193:          require(!isOtherEarningsClaimable(msg.sender), "Insufficient DLP, unable to claim rewards");

203:          require(isOtherEarningsClaimable(user), "The rewards of the user cannot be bought out");

205:              require(isEUSDBuyoutAllowed, "The purchase using EUSD is not permitted.");

215:                  require(success, "TF");

229:          require(amount > 0, "amount = 0");

237:          require(rewardRatio > 0, "reward ratio = 0");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L95

File: contracts/lybra/miner/ProtocolRewardsPool.sol

59:           require(_ratio <= 8000, "BCE");

88:           require(block.timestamp >= esLBRBoost.getUnlockTime(msg.sender), "Your lock-in period has not ended. You can't convert your esLBR now.");

114:          require(block.timestamp + exitCycle - 3 days > time2fullRedemption[msg.sender], "ENW");

132:          require(amount > 0, "QMG");

230:          require(amount > 0, "amount = 0");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L59

File: contracts/lybra/miner/stakerewardV2pool.sol

84:           require(_amount > 0, "amount = 0");

86:           require(success, "TF");

94:           require(_amount > 0, "amount = 0");

122:          require(finishAt < block.timestamp, "reward duration not finished");

140:          require(rewardRatio > 0, "reward ratio = 0");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L84

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

73:           require(assetAmount >= 1 ether, "Deposit should not be less than 1 stETH.");

76:           require(success, "TF");

99:           require(onBehalfOf != address(0), "TZA");

100:          require(amount > 0, "ZERO_WITHDRAW");

101:          require(depositedAsset[msg.sender] >= amount, "Withdraw amount exceeds deposited amount.");

127:          require(onBehalfOf != address(0), "MINT_TO_THE_ZERO_ADDRESS");

128:          require(amount > 0, "ZERO_MINT");

141:          require(onBehalfOf != address(0), "BURN_TO_THE_ZERO_ADDRESS");

157:          require(onBehalfOfCollateralRatio < badCollateralRatio, "Borrowers collateral ratio should below badCollateralRatio");

159:          require(assetAmount * 2 <= depositedAsset[onBehalfOf], "a max of 50% collateral can be liquidated");

160:          require(EUSD.allowance(provider, address(this)) > 0, "provider should authorize to provide liquidation EUSD");

189:          require((totalDepositedAsset * assetPrice * 100) / poolTotalEUSDCirculation < badCollateralRatio, "overallCollateralRatio should below 150%");

191:          require(onBehalfOfCollateralRatio < 125 * 1e18, "borrowers collateralRatio should below 125%");

192:          require(assetAmount <= depositedAsset[onBehalfOf], "total of collateral can be liquidated at most");

197:          require(EUSD.allowance(provider, address(this)) >= eusdAmount, "provider should authorize to provide liquidation EUSD");

233:          require(configurator.isRedemptionProvider(provider), "provider is not a RedemptionProvider");

234:          require(borrowed[provider] >= eusdAmount, "eusdAmount cannot surpass providers debt");

237:          require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");

260:          require(poolTotalEUSDCirculation + _mintAmount <= configurator.mintVaultMaxSupply(address(this)), "ESL");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L73

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

59:           require(assetAmount >= 1 ether, "Deposit should not be less than 1 collateral asset.");

62:           require(collateralAsset.balanceOf(address(this)) >= preBalance + assetAmount, "");

83:           require(onBehalfOf != address(0), "TZA");

84:           require(amount > 0, "ZA");

97:           require(onBehalfOf != address(0), "TZA");

98:           require(amount > 0, "ZA");

111:          require(onBehalfOf != address(0), "TZA");

112:          require(amount > 0, "ZA");

128:          require(onBehalfOfCollateralRatio < configurator.getBadCollateralRatio(address(this)), "Borrowers collateral ratio should below badCollateralRatio");

130:          require(assetAmount * 2 <= depositedAsset[onBehalfOf], "a max of 50% collateral can be liquidated");

131:          require(PeUSD.allowance(provider, address(this)) > 0, "provider should authorize to provide liquidation EUSD");

158:          require(configurator.isRedemptionProvider(provider), "provider is not a RedemptionProvider");

159:          require(borrowed[provider] >= peusdAmount, "peusdAmount cannot surpass providers debt");

162:          require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");

174:          require(poolTotalPeUSDCirculation + _mintAmount <= configurator.mintVaultMaxSupply(address(this)), "ESL");

213:          require(depositedAsset[_provider] >= _amount, "Withdraw amount exceeds deposited amount.");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L59

File: contracts/lybra/pools/LybraRETHVault.sol

28:           require(msg.value >= 1 ether, "DNL");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L28

File: contracts/lybra/pools/LybraStETHVault.sol

26:           require(configurator.hasRole(keccak256("ADMIN"), msg.sender), "not authorized");

38:           require(msg.value >= 1 ether, "DNL");

41:           require(sharesAmount > 0, "ZERO_DEPOSIT");

64:           require(excessAmount > 0 && stETHAmount > 0, "Only LSD excess income can be exchanged");

71:               require(success, "TF");

86:               require(success, "TF");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L26

File: contracts/lybra/pools/LybraWbETHVault.sol

21:           require(msg.value >= 1 ether, "DNL");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L21

File: contracts/lybra/pools/LybraWstETHVault.sol

30:           require(msg.value >= 1 ether, "DNL");

33:           require(sharesAmount > 0, "ZERO_DEPOSIT");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L30

File: contracts/lybra/token/esLBR.sol

31:           require(configurator.tokenMiner(msg.sender), "not authorized");

32:           require(totalSupply() + amount <= maxSupply, "exceeding the maximum supply quantity.");

39:           require(configurator.tokenMiner(msg.sender), "not authorized");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L31

File: contracts/lybra/token/EUSD.sol

80:           require(configurator.mintVault(msg.sender), "RCP");

84:           require(!configurator.vaultMintPaused(msg.sender), "MPP");

88:           require(!configurator.vaultBurnPaused(msg.sender), "BPP");

180:              require(currentAllowance >= amount, "ERC20: insufficient allowance");

271:          require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");

367:          require(_owner != address(0), "APPROVE_FROM_ZERO_ADDRESS");

368:          require(_spender != address(0), "APPROVE_TO_ZERO_ADDRESS");

392:          require(_sender != address(0), "TRANSFER_FROM_THE_ZERO_ADDRESS");

393:          require(_recipient != address(0), "TRANSFER_TO_THE_ZERO_ADDRESS");

396:          require(_sharesAmount <= currentSenderShares, "TRANSFER_AMOUNT_EXCEEDS_BALANCE");

412:          require(_recipient != address(0), "MINT_TO_THE_ZERO_ADDRESS");

441:          require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS");

460:          require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS");

466:          require(_sharesAmount <= accountShares, "BURN_AMOUNT_EXCEEDS_BALANCE");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L80

File: contracts/lybra/token/LBR.sol

21:           require(_sharedDecimals <= decimals, "OFT: sharedDecimals must be <= decimals");

26:           require(configurator.tokenMiner(msg.sender), "not authorized");

27:           require(totalSupply() + amount <= maxSupply, "exceeding the maximum supply quantity.");

33:           require(configurator.tokenMiner(msg.sender), "not authorized");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L21

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

43:           require(configurator.mintVault(msg.sender), "RCP");

47:           require(!configurator.vaultMintPaused(msg.sender), "MPP");

51:           require(!configurator.vaultBurnPaused(msg.sender), "BPP");

59:           require(_sharedDecimals <= decimals, "OFT: sharedDecimals must be <= decimals");

64:           require(to != address(0), "TZA");

80:           require(_msgSender() == user || _msgSender() == address(this), "MDM");

81:           require(EUSD.balanceOf(address(this)) + eusdAmount <= configurator.getEUSDMaxLocked(),"ESL");

83:           require(success, "TF");

115:          require(peusdAmount <= userConvertInfo[msg.sender].mintedPeUSD &&peusdAmount > 0, "PCE");

134:          require(success, "TF");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L43

File: contracts/lybra/token/PeUSD.sol

13:           require(_sharedDecimals <= decimals, "OFT: sharedDecimals must be <= decimals");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L13

[G‑31] Functions guaranteed to revert when called by normal users can be marked payable

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost

There are 26 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

98:       function initToken(address _eusd, address _peusd) external onlyRole(DAO) {

109:      function setMintVault(address pool, bool isActive) external onlyRole(DAO) {

119:      function setMintVaultMaxSupply(address pool, uint256 maxSupply) external onlyRole(DAO) {

126:      function setBadCollateralRatio(address pool, uint256 newRatio) external onlyRole(DAO) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L98

File: contracts/lybra/miner/esLBRBoost.sol

33:       function addLockSetting(esLBRLockSetting memory setting) external onlyOwner {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L33

File: contracts/lybra/miner/EUSDMiningIncentives.sol

84:       function setToken(address _lbr, address _eslbr) external onlyOwner {

89:       function setLBROracle(address _lbrOracle) external onlyOwner {

93:       function setPools(address[] memory _pools) external onlyOwner {

100:      function setBiddingCost(uint256 _biddingRatio) external onlyOwner {

105:      function setExtraRatio(uint256 ratio) external onlyOwner {

110:      function setPeUSDExtraRatio(uint256 ratio) external onlyOwner {

115:      function setBoost(address _boost) external onlyOwner {

119:      function setRewardsDuration(uint256 _duration) external onlyOwner {

124:      function setEthlbrStakeInfo(address _pool, address _lp) external onlyOwner {

128:      function setEUSDBuyoutAllowed(bool _bool) external onlyOwner {

226       function notifyRewardAmount(
227           uint256 amount
228:      ) external onlyOwner updateReward(address(0)) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L84

File: contracts/lybra/miner/ProtocolRewardsPool.sol

52:       function setTokenAddress(address _eslbr, address _lbr, address _boost) external onlyOwner {

58:       function setGrabCost(uint256 _ratio) external onlyOwner {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L52

File: contracts/lybra/miner/stakerewardV2pool.sol

121:      function setRewardsDuration(uint256 _duration) external onlyOwner {

127:      function setBoost(address _boost) external onlyOwner {

132:      function notifyRewardAmount(uint256 _amount) external onlyOwner updateReward(address(0)) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L121

File: contracts/lybra/token/EUSD.sol

411:      function mint(address _recipient, uint256 _mintAmount) external onlyMintVault MintPaused returns (uint256 newTotalShares) {

440:      function burn(address _account, uint256 _burnAmount) external onlyMintVault BurnPaused returns (uint256 newTotalShares) {

459:      function burnShares(address _account, uint256 _sharesAmount) external onlyMintVault BurnPaused returns (uint256 newTotalShares) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L411

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

63:       function mint(address to, uint256 amount) external onlyMintVault MintPaused returns (bool) {

69:       function burn(address account, uint256 amount) external onlyMintVault BurnPaused returns (bool) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L63

[G‑32] Constructors can be marked payable

Payable functions cost less gas to execute, since the compiler does not have to add extra checks to ensure that a payment wasn't provided. A constructor can safely be marked as payable, since only the deployer would be able to pass funds, and the project itself would not pass any funds.

There are 20 instances of this issue:

see instances
File: contracts/lybra/configuration/LybraConfigurator.sol

80:       constructor(address _dao, address _curvePool) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L80

File: contracts/lybra/governance/AdminTimelock.sol

8:        constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) TimelockController(minDelay, proposers, executors, admin) {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/AdminTimelock.sol#L8

File: contracts/lybra/governance/GovernanceTimelock.sol

15:       constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) TimelockController(minDelay, proposers, executors, admin) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L15

File: contracts/lybra/governance/LybraGovernance.sol

38:         constructor(string memory name_, TimelockController timelock_, address _esLBR) GovernorTimelockControl(timelock_)  Governor(name_) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/LybraGovernance.sol#L38

File: contracts/lybra/miner/esLBRBoost.sol

25        constructor() {
26:           esLBRLockSettings.push(esLBRLockSetting(30 days, 20 * 1e18));

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/esLBRBoost.sol#L25-L26

File: contracts/lybra/miner/EUSDMiningIncentives.sol

64:       constructor(address _config, address _boost, address _etherOracle, address _lbrOracle) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L64

File: contracts/lybra/miner/ProtocolRewardsPool.sol

48:       constructor(address _config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L48

File: contracts/lybra/miner/stakerewardV2pool.sol

49:       constructor(address _stakingToken, address _rewardToken, address _boost) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L49

File: contracts/lybra/pools/base/LybraEUSDVaultBase.sol

46:       constructor(address _collateralAsset, address _etherOracle, address _configurator) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L46

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

37:       constructor(address _peusd, address _etherOracle, address _collateral, address _configurator) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L37

File: contracts/lybra/pools/LybraRETHVault.sol

22        constructor(address _peusd, address _config, address _rETH, address _oracle, address _rkPool)
23:           LybraPeUSDVaultBase(_peusd, _oracle, _rETH, _config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraRETHVault.sol#L22-L23

File: contracts/lybra/pools/LybraStETHVault.sol

18:       constructor(address _config, address _stETH, address _oracle) LybraEUSDVaultBase(_stETH, _oracle, _config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L18

File: contracts/lybra/pools/LybraWbETHVault.sol

17        constructor(address _peusd, address _oracle, address _asset, address _config)
18:           LybraPeUSDVaultBase(_peusd, _oracle, _asset, _config) {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWbETHVault.sol#L17-L18

File: contracts/lybra/pools/LybraWstETHVault.sol

25:       constructor(address _lido, address _peusd, address _oracle, address _asset, address _config) LybraPeUSDVaultBase(_peusd, _oracle, _asset,_config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraWstETHVault.sol#L25

File: contracts/lybra/Proxy/LybraProxy.sol

9:        constructor(address _logic,address _admin,bytes memory _data) TransparentUpgradeableProxy(_logic, _admin, _data) {}

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/Proxy/LybraProxy.sol#L9

File: contracts/lybra/token/esLBR.sol

22:       constructor(address _config) ERC20Permit("esLBR") ERC20("esLBR", "esLBR") {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/esLBR.sol#L22

File: contracts/lybra/token/EUSD.sol

92:       constructor(address _config) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L92

File: contracts/lybra/token/LBR.sol

18:       constructor(address _config, uint8 _sharedDecimals, address _lzEndpoint) ERC20("LBR", "LBR") BaseOFTV2(_sharedDecimals, _lzEndpoint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L18

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

55:       constructor(address _config, uint8 _sharedDecimals, address _lzEndpoint) ERC20("peg-eUSD", "PeUSD") BaseOFTV2(_sharedDecimals, _lzEndpoint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L55

File: contracts/lybra/token/PeUSD.sol

11:       constructor(uint8 _sharedDecimals, address _lzEndpoint) ERC20("peg-eUSD", "peUSD") BaseOFTV2(_sharedDecimals, _lzEndpoint) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L11

[G‑33] Don't use _msgSender() if not supporting EIP-2771

Use msg.sender if the code does not implement EIP-2771 trusted forwarder support

There are 17 instances of this issue:

File: contracts/lybra/token/EUSD.sol

154:          address owner = _msgSender();

201:          address owner = _msgSender();

227:          address spender = _msgSender();

249:          address owner = _msgSender();

269:          address owner = _msgSender();

335:          address owner = _msgSender();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L154

File: contracts/lybra/token/LBR.sol

50:           address spender = _msgSender();

62:           address spender = _msgSender();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/LBR.sol#L50

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

80:           require(_msgSender() == user || _msgSender() == address(this), "MDM");

103:          convertToPeUSD(_msgSender(), eusdAmount);

104:          sendFrom(_msgSender(), dstChainId, toAddress, eusdAmount, callParams);

142:          address spender = _msgSender();

185:          address spender = _msgSender();

197:          address spender = _msgSender();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L80

File: contracts/lybra/token/PeUSD.sol

32:           address spender = _msgSender();

44:           address spender = _msgSender();

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSD.sol#L32

[G‑34] Not using the named return variables anywhere in the function is confusing

Consider changing the variable to be an unnamed one, since the variable is never assigned, nor is it returned by name. If the optimizer is not turned on, leaving the code as it is will also waste gas for the stack variable.

There is one instance of this issue:

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

/// @audit eusdAmount
165       function getAccruedEUSDInterest(
166           address user
167:      ) public view returns (uint256 eusdAmount) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L165-L167

Invalid Issues

The issues below may be reported by other wardens, but can be ignored since either the rule or the specified instances are invalid

[I‑01] Do not calculate constant variables, which will save gas

The compiler automatically expands simple expressions into their literal values, so manually doing the expansion doesn't save gas, and this finding is invalid

There are 7 instances of this issue:

File: contracts/lybra/configuration/LybraConfigurator.sol

76:      bytes32 public constant DAO = keccak256("DAO");

77:      bytes32 public constant TIMELOCK = keccak256("TIMELOCK");

78:      bytes32 public constant ADMIN = keccak256("ADMIN");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/configuration/LybraConfigurator.sol#L76-L76

File: contracts/lybra/governance/GovernanceTimelock.sol

10:      bytes32 public constant DAO = keccak256("DAO");

11:      bytes32 public constant TIMELOCK = keccak256("TIMELOCK");

12:      bytes32 public constant ADMIN = keccak256("ADMIN");

13:      bytes32 public constant GOV = keccak256("GOV");

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L10-L10

[I‑02] Using delete instead of setting mapping/state variable

Using delete instead of assigning zero to state variables does not save any extra gas - they both refund the same amount, so this finding is invalid

There are 10 instances of this issue:

File: contracts/lybra/miner/EUSDMiningIncentives.sol

196:             rewards[msg.sender] = 0;

209:             rewards[user] = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/EUSDMiningIncentives.sol#L196-L196

File: contracts/lybra/miner/ProtocolRewardsPool.sol

120:         unstakeRatio[msg.sender] = 0;

121:         time2fullRedemption[msg.sender] = 0;

144:         unstakeRatio[msg.sender] = 0;

145:         time2fullRedemption[msg.sender] = 0;

193:             rewards[msg.sender] = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/ProtocolRewardsPool.sol#L120-L120

File: contracts/lybra/miner/stakerewardV2pool.sol

114:             rewards[msg.sender] = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/miner/stakerewardV2pool.sol#L114-L114

File: contracts/lybra/pools/LybraStETHVault.sol

82:              feeStored = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/LybraStETHVault.sol#L82-L82

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

198:             feeStored[_onBehalfOf] = 0;

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L198-L198

[I‑03] Change public function visibility to external to save gas

Both public and external functions use the same amount of gas (both deployment and runtime gas), so this finding is invalid

There are 18 instances of this issue:

File: contracts/lybra/governance/GovernanceTimelock.sol

25:      function checkRole(bytes32 role, address _sender) public view  returns(bool){

29:      function checkOnlyRole(bytes32 role, address _sender) public view  returns(bool){

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/governance/GovernanceTimelock.sol#L25-L25

File: contracts/lybra/pools/base/LybraPeUSDVaultBase.sol

44:      function totalDepositedAsset() public view returns (uint256) {

257:     function getPoolTotalPeUSDCirculation() public view returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L44-L44

File: contracts/lybra/token/EUSD.sol

99:      function name() public pure returns (string memory) {

107:     function symbol() public pure returns (string memory) {

114:     function decimals() public pure returns (uint8) {

124:     function totalSupply() public view returns (uint256) {

134:     function balanceOf(address _account) public view returns (uint256) {

153:     function transfer(address _recipient, uint256 _amount) public returns (bool) {

200:     function approve(address _spender, uint256 _amount) public returns (bool) {

226:     function transferFrom(address from, address to, uint256 amount) public returns (bool) {

248:     function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) {

285:     function getTotalShares() public view returns (uint256) {

292:     function sharesOf(address _account) public view returns (uint256) {

334:     function transferShares(address _recipient, uint256 _sharesAmount) public returns (uint256) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/EUSD.sol#L99-L99

File: contracts/lybra/token/PeUSDMainnetStableVision.sol

129:     function executeFlashloan(FlashBorrower receiver, uint256 eusdAmount, bytes calldata data) public payable {

165      function getAccruedEUSDInterest(
166          address user
167:     ) public view returns (uint256 eusdAmount) {

https://github.com/code-423n4/2023-06-lybra/blob/dc901a3560b71ed2376feb6418b3d81e3d067fb9/contracts/lybra/token/PeUSDMainnetStableVision.sol#L129-L129

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment