Skip to content
$1,000,000 in security audit grants are live now, Apply here →

Security review · February 2025

Impermax V3

for Impermax

Impermax engaged Guardian to review the security of the Impermax V3 system allowing for tokenized LP collateral. From the 2nd of January to the 9th of January, a team of 6 auditors reviewed the source code in scope.

Published
Review window
January 2 to 9, 2025
Language
Solidity
Chains
Arbitrum
Sector
Lending
  • 1 Critical
  • 3 High
  • 6 Medium
  • 22 Low
  • 0 Informational

10 resolved · 1 partially resolved · 21 acknowledged

Scope

Overview

Impermax engaged Guardian to review the security of the Impermax V3 system allowing for tokenized LP collateral. From the 2nd of January to the 9th of January, a team of 6 auditors reviewed the source code in scope.

Issues Detected Throughout the engagement 4 High/Critical issues were uncovered and promptly addressed by the Impermax team.

Security Recommendation Given the number of High and Critical issues detected as well as additional findings reported during remediation review, Guardian recommends that an independent security review of the protocol at a finalized frozen commit is conducted before deployment. Furthermore, Guardian recommends the testing infrastructure to be expanded to include all user flows such as the reinvest functionality. The developed fuzzing suite can be used to port over the codebase to Foundry from Truffle.

Findings 32

  1. C-01 Critical Collateral-Free Borrows Reentrancy Resolved
    Location
    ImpermaxV3Borrowable.sol

    Description

    Currently the borrow function is at risk of cross-contract reentrancy. Consider the following scenario:

    (1) ImpermaxV3Borrowable.borrow with borrowAmount > 0 with an NFTLP collateral that is enough to cover the borrow.

    (2) Callback impermaxV3Borrow is called before tokenId's borrow balance is updated. At this point in time, the account's borrowed is 0. (3) Call ImpermaxV3Collateral.redeem with percentage=1e18 to get back the NFTLP. This is still in the context of the callback.

    (4) require(IBorrowable(borrowable0).borrowBalance(tokenId) = 0 and require(IBorrowable(borrowable1).borrowBalance(tokenId) = 0 should pass successfully as the account wasn't updated yet.

    (5) Back in ImpermaxV3Borrowable.borrow, canBorrow would be called, but the NFTLP position still has enough liquidity to cover the borrow and the getPositionData function would still return the proper values, even if Alice now holds the NFT instead of the ImpermaxV3Collateral contract.

    (6) Ultimately, Alice borrowed a non-zero amount but also holds the entirety of her collateral NFTLP.

    Recommendation

    Ensure the ImpermaxV3Collateral contract holds the NFTLP collateral when there is an active borrow.

    Resolution

    Impermax Team: The issue was resolved in commit d71e5b6.

  2. H-01 High Auto-Compounding Can Lead To Liquidations Validation Partially resolved
    Location
    TokenizedUniswapV3Position.sol: 257-305

    Description

    Proof of concept: PoC

    The auto-compounding feature should help borrowers be more capital efficient by automatically reinvesting fees earned on uniswap. As the caller of the reinvest function receives a bounty for doing the work, the position's collateral value decreases through auto-compounding.

    The reinvest function does not implement safety checks for the position's health. Therefore, it is possible that calling the reinvest function leads to positions being liquidatable, which is definitely not in the borrower's interest and should therefore be prevented.

    It is also possible to auto-compound liquidatable positions and therefore potentially make them go underwater.

    Recommendation

    Revert at the end of the reinvest flow if the position is liquidatable. It would also make sense to let borrowers decide up to which point they want to auto-compound so that reinvestors can not push them to the edge of liquidation.

    Resolution

    Impermax Team: The issue was resolved in commit af10809.

  3. H-02 High Oracle Price DoS DoS Resolved
    Location
    TokenizedUniswapV3Position.sol: 75

    Description

    The function oraclePriceSqrtX96 aims to calculate the oracle price by gathering the TWAP across all Uniswap pools with a specific (token0, token1) pair and calculating the mean.

    The pre-condition for a successful call to oraclePriceSqrtX96 is that for each Uniswap pool in the poolsList, the consult function does not revert.

    However, if a pool was just created, there would not be an observation that was ORACLE_T seconds ago and Uniswap's observeSingle would revert: "dev Reverts if an observation at or before the desired observation timestamp does not exist"

    Ultimately, a user can DoS the calculation of oracle pricing for an entire period just by deploying a different fee tier, which would prevent positionData retrieval and DoS other areas of the codebase such as function isUnderwater and consequently restructureBadDebt.

    Recommendation

    Consider wrapping the call to Uniswap's observe in a try-catch and then adjusting the number of observations by how many calls were successful.

    Resolution

    Impermax Team: The issue was resolved in commit 6f6ab04.

  4. H-03 High Restructure Debt Locks Up Funds Logical Error Resolved
    Location
    ImpermaxV3Borrowable.sol

    Description

    When a position’s debt is restructured, the debt is forgiven, the losses socialized, and the position remains in the system. In certain cases, the position can become liquidatable after restructuring and be liquidated, and other times the position can become fully healthy and remain.

    This incongruent behavior may be unexpected for the protocol, since some positions will effectively get a bail-out and remain. This can be used by malicious borrower’s to keep lender’s funds locked up indefinitely.

    Recommendation

    Consider if previously underwater positions should remain in the system after restructuring and allow them to be liquidated.

    Resolution

    Impermax Team: The issue was resolved in commit 92796e2.

    Guardian Team: The owner of a position can frontrun the liquidator to call restructureBadDebt first so that the position is healthy again and then stuff the block so that the block gas limit is hit before the liquidator's transaction goes through. Afterwards the blockOfLastRestructureOrLiquidation check will fail.

  5. M-01 Medium Arbitrary NFTLP Code Can Be Used Validation Acknowledged
    Location
    Global

    Description

    The ImpermaxFactory contract allows for the creation of lending pools with a completely arbitrary NFTLP address. Consequently, a malicious user may create a lending pool with a malicious tokenized position which could lead to loss of user data and assets.

    Recommendation

    Validate that the NFTLP's passed into the ImpermaxFactory functions have been deployed through the respective tokenized position factory contracts.

    Resolution

    Impermax Team: Acknowledged. Validation is done through the whitelisting process at a higher level (generally in the UI).

  6. M-02 Medium Interest Lost On Low Decimal Tokens Rounding Acknowledged
    Location
    BInterestRateModel.sol: 72

    Description

    In the accrueInterest function, the interest calculation interestFactor.mul(_totalBorrows).div(1e18) can round down to zero for low-decimal tokens (such as USDC), particularly when the borrow rate or total borrows are low.

    Specifically, when the product of interestFactor and _totalBorrows is less than 1e18, the division results in zero. This leads to a loss of interest for lenders, as the interestAccumulated is zero.

    Furthermore, this can cause a discrepancy between totalBorrows and accountBorrows, since accountBorrows does not experience the same precision loss.

    Recommendation

    Use a higher precision for the rate values to accommodate tokens with fewer decimals, ensuring that the computed interest does not round to zero.

    Resolution

    Impermax Team: Acknowledged.

  7. M-03 Medium Borrow Rate Gaming Logical Error Acknowledged
    Location
    ImpermaxV3Borrowable.sol: 62, 154

    Description

    The currentBorrowBalance and trackBorrow functions accrue interest and therefore update the totalBorrows which would influence the utilizationRate and therefore the borrowRate. However, they do not have the _update modifier and therefore do not update the borrowRate.

    Therefore the system potentially deals with a stale borrowRate and the lenders receive less yield than they should. Furthermore, the system allows for interest gaming, since calling sync() every second will provide a different debt accumulated than calling sync() once over the same timespans.

    For example, with a decreasing _kinkBorrowRate every sync the borrow rates will also decrease and cause less to be repaid over the borrow’s lifetime, which in turn is less yield for lenders.

    Recommendation

    Add the _update modifier to the currentBorrowBalance and trackBorrow functions. Furthermore, re-consider if the system show allow for varying sync times to lead to different costs on users.

    Resolution

    Impermax Team: Acknowledged. We call calculateBorrowRate when there is a supply/demand change in the contract.

  8. M-04 Medium Interest Not Accumulated Before Admin Changes Logical Error Acknowledged
    Location
    BSetter.sol: 47-51

    Description

    Interest should always be accrued before updating parameters that will impact the outcome of the next update to fairly calculate the accumulated interest.

    The _setAdjustSpeed function in the BSetter contract for example can update the adjustSpeed variable that will influence the borrowRate, but it does not accrue interest before updating this variable.

    Therefore the next time the borrowRate is updated it applies the updated adjustSpeed value on the whole timeElapsed since the last update while in reality a part of the timeElapsed should be calculated with the old adjustSpeed value to fairly update the borrowRate.

    Recommendation

    Accrue interest before updating parameters that will impact the outcome of interest related calculations.

    Resolution

    Impermax Team: Acknowledged.

  9. M-05 Medium ERC-777 Reentrancy In reinvest Logical Error Resolved
    Location
    UniswapV3AC01.sol: 148-149

    Description

    When the bounty is sent to the given bountyTo address with an ERC-777 token the receiver can re-enter the system. At this point, the fee growth values of the position were already reset, but the position had not received the liquidity yet.

    Therefore the collateral value of the position is smaller than it is in reality. This could lead to the system seeing the position as liquidatable or underwater when the caller reenters the system.

    Therefore a malicious actor can potentially abuse this state to either:

    • Liquidate the position to steal from its owner
    • Call restructureBadDebt to reduce the debt of the position and steal from the lenders (could be

    abused by the owner of the position)

    Recommendation

    Transfer the bounty to the given bountyTo address after all state changes occurred.

    Resolution

    Impermax Team: The issue was resolved in commit 33126d8.

  10. M-06 Medium Frontrun Restructure Bad Debt Frontrunning Acknowledged
    Location
    ImpermaxV3Borrowable.sol

    Description

    When restructureBadDebt is called, the exchangeRate will immediately decrease due to the reduction in _totalBalance without a proportional reduction in pool token supply. A user can frontrun the restructuring to redeem before the exchange rate drop to avoid the penalty.

    The LP exploiting this receives yield without risk while increasing the risk of all the other LP as the bad debt is socialized among all other LPs. Furthermore, the LP taking advantage of the stepwise jump in the exchange rate can then mint the same amount of PoolTokens for a fraction of the price.

    Recommendation

    Consider a 2 step deposit/redeem process.

    Resolution

    Impermax Team: Acknowledged. I think the only real solution to this would be to introduce an unbonding period for redeem. But this would ruin the UX for a marginal benefit.

  11. L-01 Low Liquidators Receive Unexpected Values Logical Error Acknowledged
    Location
    ImpermaxV3Collateral.sol: 112

    Description

    The ImpermaxV3Collateral contract utilizes a 30-minute TWAP to determine the value of collateral and debt during the liquidation process. This approach helps provide a stable price by averaging out short-term market fluctuations.

    However, when the liquidated tokens are claimed, Uniswap uses the spot price. This discrepancy between the TWAP and the spot price can lead to differences in the expected versus actual value received by liquidators.

    For instance, if the spot price is lower than the TWAP, a liquidator may receive fewer tokens than anticipated, resulting in a possible loss.

    Recommendation

    Clearly document potential discrepancies between TWAP and spot pricing so users understand the associated risks

    Resolution

    Impermax Team: Acknowledged. Since liquidations will be handled by external contracts, all the PNL logic and liquidations strategy will be handled by the liquidator.

  12. L-02 Low Unnecessary Rounding Increment Logical Error Resolved
    Location
    TokenizedUniswapV3Position.sol: 237

    Description

    In the join function 1 wei is added to the resulting newFeeGrowthInside0LastX128 of the joined position to avoid fee over estimations.

    However in cases where the newFeeGrowthInside0LastX128 result does not have precision loss this is an unnecessary addition. Instead rounding up can occur only when precision loss would occur.

    Recommendation

    Consider implementing tA0.add(tB0).add(newLiquidity - 1).div(newLiquidity) Instead of the existing tA0.add(tB0).div(newLiquidity).add(1) to accurately only round up when precision loss would occur.

    Resolution

    Impermax Team: The issue was resolved in commit 5d38704.

  13. L-03 Low Safety Margin Updates Causes Liquidations Warning Acknowledged
    Location
    CSetter.sol: 39

    Description

    The safetyMarginSqrt plays a crucial role when determining the liquidatable state of a position, as it's used to calculate the LOWEST and HIGHEST price as a factor of the oracle TWAP price.

    Therefore, healthy position can become instantly liquidatable if this factor is increased by the admin. The same issue applies when updating the liquidationIncentive and liquidationFee.

    Recommendation

    Introduce a time lock feature so that these admin state changes include a delay, to allow users to take action before they are applied.

    Resolution

    Impermax Team: Acknowledged.

  14. L-04 Low Liquidate Can Be Called With Zero Repay Validation Acknowledged
    Location
    Global

    Description

    Functions throughout the codebase allow for an input of zero, e.g. functions ImpermaxV3Borrowable.liquidate for repayAmount and ImpermaxV3Collateral.redeem for percentage.

    This would ultimately leads to events being emitted when no actual actions have been taken on a Position.

    Recommendation

    Consider validating against zero inputs.

    Resolution

    Impermax Team: Acknowledged.

  15. L-05 Low Functions Naming Convention Best Practices Acknowledged
    Location
    Global

    Description

    There are multiple public/external functions with names starting with an underscore. Some examples:

    • TokenizedUniswapV3Factory._setPendingAdmin
    • CSetter._initialize
    • BSetter._setReserveFactor

    However, this naming style goes against the solidity convention for external/public vs internal/private functions, more details here:

    https://docs.soliditylang.org/en/latest/style-guide.html#underscore-prefix-for-non-external-function

    s-and-variables

    Additionally, this can create confusion for the reader, or allow bugs to be introduced, declaring a function external when it's suppose to be private/internal.

    Recommendation

    Consider adapting to the function naming convention, according to the solidity docs shared above.

    Resolution

    Impermax Team: Acknowledged.

  16. L-06 Low Incompatible Types Warning Resolved
    Location
    IUniswapV3AC01.sol

    Description

    Within the IUniswapV3AC01 the interface there are numerous functions where the return type does not match the expected return type.

    For example, function PROTOCOL_SHARE() external view returns (address); expected an address to be returned in the interface definition but the PROTOCOL_SHARE is a uint.

    Recommendation

    Correct the interface definitions so the return types match.

    Resolution

    Impermax Team: The issue was resolved in commit 8a88634.

  17. L-07 Low Black Swan Events Lead To Value Theft Validation Acknowledged
    Location
    ImpermaxV3Borrowable.sol: 105-126

    Description

    • The borrow function allows to borrow up to the point of being liquidatable therefore a tiny price

    change afterward will make the position liquidatable

    • The system uses TWAP prices at the moment to calculate the value of collateral and debt

    This could be problematic in black swan events when prices drop or rise very quickly. It could lead to a situation where the TWAP price is off by more than the safety margin + liquidation fees compared to the current price.

    In this case, anyone would be able to borrow funds that are worth more than the deposited collateral, use these funds to buy more collateral, and repeat the process to drain the protocol.

    Recommendation

    There are multiple things that can decrease the likelihood of this edge case:

    • Add a percentage buffer on top of the liquidation threshold so that users are not able to borrow up

    to the point of being liquidatable

    • Use a different price oracle that would be more accurate in such an edge case

    Resolution

    Impermax Team: Acknowledged.

  18. L-08 Low Multiple NFTLPs Owned By ReservesManager Logical Error Acknowledged
    Location
    ImpermaxV3Collateral.sol: 138

    Description

    During liquidations, the NFTLP token will we split twice, one for the liquidator, one for the reservesManager. Even though each tokenId can be in different ranges, the reservesManager will end up with hundreds of NFTLPs that will later need to be redeemed to collect the underlying.

    Recommendation

    Consider redeeming the NFTLP to receive the underlying tokens.

    Resolution

    Impermax Team: Acknowledged.

  19. L-09 Low Invalid Price Validations Validation Resolved
    Location
    UniswapV3CollateralMath.sol

    Description

    UniswapV3CollateralMath.newPosition validates that paSqrtX96 > Q32 and pbSqrtX96 < Q160 However, Q32 is below Uniswap's MIN_SQRT_RATIO and Q160 is above Uniswap's MAX_SQRT_RATIO, which leads to potentially invalid position objects being created.

    Recommendation

    Align the validation with Uniswap's min and max prices.

    Resolution

    Impermax Team: The issue was resolved in commit 672084e.

  20. L-10 Low Protocol Revenue Affected By Liquidations Logical Error Acknowledged
    Location
    ImpermaxV3Borrowable.sol: 129

    Description

    The current implementation of ImpermaxV3Borrowable.liquidate allows users to partially repay the current borrowed balance. However, depending on the previous health state, a partial repay can make the position healthy post liquidation.

    This means that both the protocol ad the user could have received more fees during a full liquidation.

    If the user has both tokens borrowed from the pool, and based on the liquidity structure of the position, there are cases where repaying one of the tokens first will allow the liquidator to trigger a second liquidation with the other token.

    Recommendation

    Protocol should be aware of the fees they are missing out with partial liquidations. Additionally, document this behavior, so users are aware of the impact of partial liquidations.

    Resolution

    Impermax Team: Acknowledged. Partial liquidations make us miss out on fees, but they make the protocol safer.

  21. L-11 Low Redundant Function Calls In ImpermaxV3Factory Best Practices Resolved
    Location
    ImpermaxV3Factory.sol: 54, 63, 72

    Description

    The createCollateral, createBorrowable0, and createBorrowable1 functions call the _getTokens function in the beginning without using the function's return values. Therefore, the call is redundant and can be removed.

    Recommendation

    Remove the redundant function calls. If there should be a check to ensure the two token addresses are set add a require statement instead.

    Resolution

    Impermax Team: The issue was resolved in commit 74c85cf.

  22. L-12 Low Repay Window Created By TWAP Logical Error Acknowledged
    Location
    ImpermaxV3Borrowable.sol: 105

    Description

    Due to the lagging nature of TWAP price, borrowers will have a time window to repay their loans, once they notice the price went against them, but the TWAP price has not catch up yet.

    Therefore, liquidators will have a hard time finding liquidatable positions, as users will know ahead of time due to the pool price action.

    Recommendation

    Document this behavior to the users and liquidators.

    Resolution

    Impermax Team: Acknowledged.

  23. L-13 Low Zero Liquidity Positions Are Permitted Validation Acknowledged
    Location
    TokenizedUniswapV3Position.sol

    Description

    There is no zero check in the mint function of the TokenizedUniswapV3Position contract therefore zero liquidity positions are permitted.

    It is also possible to split 0% of a position to create a new position with 0 liquidity. Such unexpected states should not occur and might lead to vulnerabilities with future updates.

    Recommendation

    Add zero checks to prevent the creation of zero liquidity positions.

    Resolution

    Impermax Team: Acknowledged. Through the router it’s easier to create a leveraged position by first minting a position with 0 liquidity.

  24. L-14 Low Missing Reinvestor Protection Validation Acknowledged
    Location
    TokenizedUniswapV3Position.sol: 257-305

    Description

    If multiple people call reinvest at the same time, the transactions of the users who paid less gas might be successful and the users have to pay the full gas costs, but the transaction does not have any necessary effect and the users will not receive a bounty:

    • Bob calls reinvest
    • Alice calls reinvest
    • Bob paid more gas and the transaction went through first
    • The position's fees are reinvested
    • Bob receives a bounty for his work
    • Alice's transaction went through and in between some fees were accrued on Uniswap
    • A dust amount or even no fees are reinvested
    • Alice does not receive a bounty or the bounty that does not compensate for her gas costs

    This does also allow a griefing vector, a malicious actor could front-run the reinvest call on his position and split the NFTLP into two positions so that the reinvest caller wastes gas to reinvest a dust amount of fees.

    Recommendation

    Add a lastReinvest slippage check at the beginning of the reinvest function, or document that this function should be called over a contract that implements such a check.

    Resolution

    Impermax Team: Acknowledged.

  25. L-15 Low Direct Interactions May Risk User Funds Frontrunning Acknowledged
    Location
    Global

    Description

    The protocol relies on a two-step process for most of its depositing functionality. Users send funds to the contract or a Uniswap position first, and then call a function that mints the corresponding tokens or positions.

    This works well for those who use the periphery contracts, since both actions occur atomically. However, users who interact directly with the protocol’s core contracts may risk losing their funds if, for instance, the second transaction is frontrun.

    Recommendation

    Make it clear in the documentation that this risk exists and advise users to use the protocol’s periphery contracts.

    Resolution

    Impermax Team: Acknowledged. No user should ever interact with the core directly.

  26. L-16 Low Inconsistent Split Percentages Validation Resolved
    Location
    Global

    Description

    TokenizedUniswapV2Position prevents a split percentage of 100% but TokenizedUniswapV3Position allows it.

    Recommendation

    Consider making the validation symmetrical.

    Resolution

    Impermax Team: The issue was resolved in commit 2b519ec.

  27. L-17 Low NFTLP positions Not Compatible With Router Logical Error Acknowledged
    Location
    ITokenizedUniswapV3Position.sol: 29

    Description

    The current implementation of TokenizedUniswapV3Position contains a Position struct that stores position data by tokenId. However, this struct will not be compatible with the periphery contracts, and the unclaimedFees0 and unclaimedFees1 are unexpected returned params.

    Recommendation

    Be aware of this issue, and update the periphery contracts and avoid integration issues

    Resolution

    Impermax Team: Acknowledged. We are aware of this, we will update the periphery once the audit for the core is completed.

  28. L-18 Low Unsafe Mint Function Used Validation Resolved
    Location
    TokenizedUniswapV3Position.sol: 138

    Description

    The ERC721 mint function is used multiple times in the codebase instead of the safeMint function. If the receiver is a contract and is not capable of handling NFT-related actions and/or calling other functions in the system, the NFTs will be stuck.

    Recommendation

    Consider using the safeMint function instead of the mint function to make sure the receiver is capable of handling NFTs.

    Resolution

    Impermax Team: The issue was resolved in commit 44b3100.

  29. L-19 Low Split NFT Receiver Is Always The Owner Logical Error Acknowledged
    Location
    TokenizedUniswapV3Position.sol: 198

    Description

    When calling the split function in the TokenizedUniswapV3Position contract, the receiver of the new NFT is always the owner.

    The function call could come from an approved actor who wants to receive a part of the NFT which is not possible due to this hardcoded behavior

    The approved actor is therefore allowed to receive the whole NFT but not a part of it.

    Recommendation

    Add a to parameter to the split function as in the mint function.

    Resolution

    Impermax Team: Acknowledged.

  30. L-20 Low Lack Of Minimum Borrow Size Validation Acknowledged
    Location
    ImpermaxV3Borrowable.sol

    Description

    Currently there isn't a minimum on the size of the borrow, which would require a very small collateral amount. In such a case, there may be not enough incentive for a liquidator to liquidate the borrower, and the protocol risks accumulation of bad debt.

    Recommendation

    Consider enforcing a minimum borrow size.

    Resolution

    Impermax Team: Acknowledged.

  31. L-21 Low DoS Between Liquidatable & Underwater DoS Acknowledged
    Location
    ImpermaxV3Collateral.sol: 119-120

    Description

    A position is not liquidatable if the position is underwater (has acquired bad debt). At this point anyone needs to call restructureDebt to forgive the debt and make the position liquidatable again. This can lead to DoS when prices are around the position's bad debt threshold and fluctuate slightly.

    A liquidator could call liquidate and between the creation of the transaction and its execution, the position could go underwater as the prices changed slightly and the liquidate call reverts.

    Then the liquidator would call restructureDebt but between the creation of the transaction and its execution the position could be healthy enough again to be liquidated without forgiving debt as the prices changed slightly again causing the restructureDebt call to revert.

    This is not a big problem but it could be a bad user experience and delay the liquidation process, a process that should happen as fast as possible to avoid further damage.

    Recommendation

    Merge the restructureDebt and liquidate flows into one function, so that the restructureDebt flow is executed if the position is underwater before continuing with the liquidate flow.

    Resolution

    Impermax Team: Acknowledged. Before calling liquidate, the liquidator contract can check if the position is underwater. If it is, it can call restructureDebt before calling liquidate.

  32. L-22 Low Configuration Leads To Gaming Configuration Acknowledged
    Location
    CSetter.sol

    Description

    According to the CSetter, the minimum safety margin SAFETY_MARGIN_SQRT_MIN is 1e18.

    With this setting, a user can borrow up to about ~1x post-liquidation collateral ratio and then become both liquidatable and underwater simultaneously, introducing bad debt into the collateral very quickly.

    This also differs from the whitepaper constraints that the safetyMargin is between 150% and 250%.

    Furthermore, in the case that the liquidation fee is zero, a liquidatable position owner can self-liquidate their position to take advantage of the discount instead of repaying their borrow, since self-liquidation would require less collateral for the same amount of assets due to the liquidationIncentive.

    Recommendation

    Firstly, adjust the minimum sqrt safety margin validation according to the whitepaper. Secondly, ensure that a liquidation fee is active.

    Resolution

    Impermax Team: Acknowledged.

Invariants 9

The review's fuzzing suite asserted 9 invariants. 7 held and 2 did not.

Every invariant tested
IDInvariantResult
COLL-01TokenizedUniswapV3Position.redeem should never revertHeld
LIQUI-01After a successful call to restructureBadDebt function, the position should be liquidatableHeld
LIQUI-02After a successful reinvest call position should not be liquidatableBroken
LIQUI-03After a successful call to restructureBadDebt function, the position should NOT be underwater.Held
BORROW-01After borrow the user's position is never liquidatableHeld
BORROW-02After borrow the user's position is never underwaterHeld
BORROW-03After borrow, the borrowBalance must increase by the borrowAmountHeld
BORROW-04When borrowAmount is 0, borrowedBalance should remain unchangedHeld
GLOB-01Positions should always have > 0 liquidityBroken

More from Impermax

  1. Tokenized Aerodrome Position

    11 findings1 high 11 findings: 1 high, 2 medium, 6 low, 2 informational

Put your code through the same review.

This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.

Get a quote