Organization
- @OpenTrade
Engagement Type
Cantina Reviews
Period
-
Researchers
Findings
Medium Risk
2 findings
2 fixed
0 acknowledged
Low Risk
8 findings
6 fixed
2 acknowledged
Informational
7 findings
6 fixed
1 acknowledged
Gas Optimizations
2 findings
2 fixed
0 acknowledged
Medium Risk2 findings
Missing necessary status checks
State
- Fixed
PR #2
Severity
- Severity: Medium
Submitted by
Akshay Srivastav
Description
Various functions of protocol contracts are missing necessary protocol/account status checks.
LYTPool.processRedemption: MissingwithdrawStateActivemodifier.LYTPool.depositOffChain: MissingdepositStateActivemodifier.LYTPool.depositFromTransfer: MissingdepositStateActivemodifier.LYTPool.changeRedemptionDestination: MissingwithdrawStateActivemodifier.LYTPool.processRedemption: Missing blacklist check onfundsDestinationaddress.LYTPool.changeRedemptionDestination: Missing blacklist check onfundsDestinationaddress.LYTPool.setIndicativeAndCollateralRates: MissingatState(ILYTPoolLifeCycleState.Active)modifier.LYTPool.setExchangeRate: MissingatState(ILYTPoolLifeCycleState.Active)modifier.LYTPool.maxRedeemRequest: MissingonlyNotPausedmodifier.LYTPool.maxRedeemRequest: MissingatState(ILYTPoolLifeCycleState.Active)modifier.
Recommendation
Consider adding all the mentioned status checks.
LYTPool: Pool tokens which are currently in active withdrawal queue can be burned.
State
- Fixed
PR #2
Severity
- Severity: Medium
≈
Likelihood: Low×
Impact: High Submitted by
Akshay Srivastav
Description
In
LYTPoolcontract it is possible to burn LYTPools tokens which are currently in active withdrawal queue.Scenario:
- A market maker holds 100 pool tokens.
- Market maker requests a withdrawal of 50 tokens.
- Issuer calls
addAdjustmentAmountand burns 60 tokens of market maker. - Now since 60 tokens have already been burned, the redemption of 50 tokens from step 2 cannot be performed. The
processRedemptioncall reverts atL396. - 40 pool tokens of market maker becomes unusable.
Recommendation
Add a
maxRedeemRequestcheck inaddAdjustmentAmountfunction.function addAdjustmentAmount( ... ) public ... { ... if (debit > 0) {- if (debit > assetBalanceOf(lender)) {- revert DebitGreaterThanAssets();- } uint256 shares = convertToShares(debit);+ if (shares > maxRedeemRequest(lender)) {+ revert BurnExceedsBalance();+ } _burn(lender, shares); emit AccountDebit(lender, debit); } else if (credit > 0) { ... } else { revert InvalidAccess(); } }
Low Risk8 findings
getActiveWithdraws can be gas consuming
State
- Acknowledged
Severity
- Severity: Low
≈
Likelihood: Low×
Impact: Low Submitted by
ladboy233
Description
The
getActiveWithdrawsfunction iterates over all active withdrawal requests and returns the full list. If a large number of redeemers submit withdrawal requests, this approach can result in high gas consumption, making the function inefficient and potentially impractical to call on-chain.Recommendation
Introduce pagination (e.g., via index ranges or batching) to limit the number of withdrawal requests returned per call. This will reduce gas costs, improve scalability, and make the function safer to use when handling a large volume of requests.
Blocklisted users can create unprocessable redeem requests
Severity
- Severity: Low
≈
Likelihood: Low×
Impact: Low Submitted by
ladboy233
Description
Currently, blocklisted users are still able to create redeem requests, which are then added to the
activeWithdrawRequestlist. However, when the protocol attempts to process these requests, the transaction reverts at the step where it tries to burn the blocklisted lender’s token.This behavior leads to a situation where
getActiveWithdrawRequestincludes requests that can never be executed, causing inconsistencies and breaking assumptions for off-chain bots or automation that rely on this function to reflect executable withdrawals.Recommendation
Prevent blocklisted users from creating redeem requests in the first place. Adding a validation check before requests are added to
activeWithdrawRequestwill ensure the list only contains valid and executable entries, avoiding stuck or unprocessable states.LYTPoolServiceConfiguration.setLiquidityAsset duplicate liquidity asset entries can be added
State
- Fixed
PR #2
Severity
- Severity: Low
Submitted by
Akshay Srivastav
Description
In
LYTPoolServiceConfiguration.setLiquidityAssetfunction duplicate liquidity asset entries can be added toliquidityAssetKeysstate.Recommendation
Consider reverting if
isLiquidityAsset[addr]is already set tovalue.LYTPoolAccessControlFactory.create: Missing paused status check of _serviceConfiguration
State
- Fixed
PR #2
Severity
- Severity: Low
Submitted by
Akshay Srivastav
Description
The
LYTPoolAccessControlFactory.createfunction does not check thepausedstatus of_serviceConfigurationRecommendation
Consider adding the check.
LYTPool.deposit: Breaking checks-effects-interaction pattern
State
- Fixed
PR #2
Severity
- Severity: Low
Submitted by
Akshay Srivastav
Description
The
LYTPool.depositfunction breaks the CEI pattern and performs an external call before updating its internal storage states.Recommendation
Consider performing the
_mintcall before the_liquidityAsset.safeTransferFromcall.LYTPoolServiceConfiguration: Incorrect IFactoryType enum datatype
State
- Fixed
PR #2
Severity
- Severity: Low
Submitted by
Akshay Srivastav
Description
The
IFactoryTypeenum datatype does not containLYTPoolControllerFactorytype. Instead it incorrectly containsFeeCollectortype.Recommendation
Consider replacing
FeeCollectorwithLYTPoolControllerFactoryinIFactoryTypeenum.LYTPool.previewWithdrawRequest rounds down the shares amount
State
- Fixed
PR #2
Severity
- Severity: Low
Submitted by
Akshay Srivastav
Description
The
LYTPool.previewWithdrawRequestfunction rounds down the calculatedsharesamount. This rounding direction favors the users instead of pool contract.As a security practice it is always recommended to always round in the direction which favors the pool contract.
Recommendation
Consider rounding up the
sharesvalue inpreviewWithdrawRequestfunction.LYTPool: Market makers can hit the 100 active withdrawal request threshold
State
- Acknowledged
Severity
- Severity: Low
Submitted by
Akshay Srivastav
Description
The
LYTPool.requestRedeemExecutefunction enforces a threshold of100active withdrawal requests per market maker address. Since aLYTPoolwill only have a limited number of whitelisted market makers which will perform all the pool token mints and burns, it is possible that those market makers may hit the100active requests threshol which will block further redemption requests by such market makers.Recommendation
As market makers are whitelisted entities, the threshold of
100requests can be removed or increased to a larger limit value.
Informational7 findings
setIndicativeAndCollateralRates missing event emission
Severity
- Severity: Informational
≈
Likelihood: Low×
Impact: Low Submitted by
ladboy233
Description
setIndicativeAndCollateralRatesmissing event emission so the offchain service cannot track_indicativeInterestRateand_collateralRatechange.Recommendation
function setIndicativeAndCollateralRates( uint256 _indicativeInterestRate, uint256 _collateralRate ) public onlyPoolController { _accounting.indicativeInterestRate = _indicativeInterestRate; _accounting.collateralRate = _collateralRate; emit IndicativeAndCollateralRatesChanged(_indicativeInterestRate, _collateralRate); }LYPool.sol cannot trigger updatePoolData
Severity
- Severity: Informational
≈
Likelihood: Low×
Impact: Low Submitted by
ladboy233
Description
The
updatePoolDatafunction is protected by theonlyRegisteredPoolmodifier. However, the LYPool.sol contract does not have a direct way to triggerupdatePoolData.Recommendation
Introduce a function in the
controllercontract that allows the controller to call intoLYPoolto callupdatePoolDataCode implementations are not consistent with the spec
Description
The comments says that the functions listed below are only callable by protocol admin, but the modifier is
onlyIssuer, notonlyProtocolAdmin.addAdjustmentAmountsetFeeCollectorAddresssetIndicativeAndCollateralRates
Recommendation
Make sure Code implementations are consistent with the spec
LYTPoolAccessControl: Discrepancy in event names
State
- Fixed
PR #2
Severity
- Severity: Informational
Submitted by
Akshay Srivastav
Description
In
LYTPoolAccessControlcontract- the natspec of
allowParticipantspecifiesAllowedParticipantListUpdatedevent butParticipantAllowedevent is emitted - the natspec of
removeParticipantspecifiesAllowedParticipantListUpdatedevent butParticipantRemovedevent is emitted
Recommendation
Consider fixing the natspec comments.
Inconsistent version function across contracts
State
- Fixed
PR #2
Severity
- Severity: Informational
Submitted by
Akshay Srivastav
Description
Multiple protocol contracts implements
versionfunction but its implementation is inconsistent across those contracts. In some contractsversionreturns257while in some it returns256or512.Recommendation
Consider removing the
versionfunction from all contracts or implement it in a consistent way across protocol.Incorrect Comments
State
- Fixed
PR #2
Severity
- Severity: Informational
Submitted by
Akshay Srivastav
Description
-
LYTPoolController.sol?lines=367,368: Incorrect comment asactivatedAtvalue is never updated.
Recommendation
Consider fixing the comments
LYTPool: Users can avoid pool token burn adjustments by transferring pool tokens
State
- Acknowledged
Severity
- Severity: Informational
Submitted by
Akshay Srivastav
Description
The
LYTPooltokens can be freely transferred by token holders. Those holders can avoid burn adjustments by transferring theirLYTPooltokens to other addresses just before theaddAdjustmentAmounttransaction gets executed. Repeated execution of this mechanism can prevent burn adjustments from happening.Recommendation
This could be an accepted risk. If a mitigation is required then token transfers can be paused before making a burn adjustment.
Gas Optimizations2 findings
Unused Code
Description
These code instances are present in the codebase but are never used. Hence they can be removed.
-
LYTPool.sol?lines=197,197:isPermittedLenderis not used inLYTPool.sol. -
LYTPoolServiceConfiguration.sol?lines=52,59: TheonlyProtocolAdminandonlyIssuermodifiers are never used insideLYTPoolServiceConfigurationcontract. -
LYTPoolRegistry.sol?lines=24,24: TheonlyOperatormodifier is never used in LYTPoolRegistry contract. -
LYTPoolController.sol?lines=81,83: Unused modifiers:onlyProtocolAdminOrIssuer,onlyProtocolAdminOrIssuerOrAutomation&atState. -
ILYTPoolStructures.sol?lines=50,55:InitializedandDisruptionOrDefaultstates are never used. -
ILYTPoolStructures.sol?lines=10,10:LYTPoolSettingsstruct is never used. -
ILYTPoolStructures.sol?lines=67,67:ILYTPoolWithdrawStage.Repaidis never used. -
ILYTPoolStructures.sol?lines=73,73:ILYTPoolDepositType.CrossChainDepositis never used. -
IPoolStructures.sol:IPoolStructures.solfile is never used. -
IERC4626.sol:IERC4626.solfile is never used.
Recommendation
Remove the unused code to save gas.
-
LYTPool.requestRedeemExecute: Redundant withdrawStateActive modifier
State
- Fixed
PR #2
Severity
- Severity: Gas optimization
Submitted by
Akshay Srivastav
Description
The
withdrawStateActivemodifier can be removed fromrequestRedeemExecutefunction as it is already present onrequestRedeemfunction.Recommendation
Consider removing the modifier from
requestRedeemExecutefunction.