Idle Finance security record

Arbitrum, Ethereum, Optimism, Polygon (POS), Polygon zkEVMidle.financeXGitHub

As of 30 Oct 2026, Idle Finance has 3 audit reports by 2 security firms on Trustblock; the latest is by Consensys, dated 1 Jun 2021. Those reports list no open critical findings.

Critical findings
No open critical findings
Across 3 reports.
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.

Audits3

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Idle FinanceSecurity firm: ConsensysDate: Scope: Files named in the reportNo open critical findingsOpen · diligence.security
Idle FinanceSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com
Idle GovernanceSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com

Findings56

Statuses are the security firm’s own, from each report.

SeverityOpenAcknowledgedFixed
Critical000
High000
Medium404
Low81624
Medium`redeemIdleToken()` may fail if `fee` is reset to zeroIdle Finance · Quantstamp · 23 Apr 2021Fixed

Assume that: A1: `userNoFeeQty[msg.sender]` can only accumulated when `fee` is set to `0` (according to the `_updateAvgPrice()` function). A2: the price of idleToken is `5` and does not change a lot (this happens when the `balanceUnderlying` is large). Consider the following scenario for some `user1`: 1. `user1` deposits `100` underlying token when `fee` is set to `0`. The `user1` will obtain `100/5 = 20` idleToken, and we noted that `userNoFeeQty[user1]` equals to `20` 2. Then the idleFinance team decides to change the `fee` from `0` to `1000`. 3. When the `user1` later deposit again, with another `100` underlaying token, the `user1` will obtain `100/5 = 20` idleToken again. In addition to the formerly obtained `20` idleToken, now the `user1` has `20 + 20 = 40` idleTokens on hand. However, since `fee != 0` now, the `userNoFeeQty[user1]` will remains equal to `20` instead of equal to `20 + 20 = 40`. 4. Then the idleFinance team decides to change the `fee` from `1000` to `0` again. 5. Finally, when `user1` decides to redeem idleTokens through function `redeemIdleToken()` by passing the parameter `_amount = 40`, we have that the `_amount` is `40` but the `userNoFeeQty[user1]` is `20`. This will cause the revert of the function due to the statement: `userNoFeeQty[msg.sender] = userNoFeeQty[msg.sender].sub(_amount);`.

Open the report
MediumCentralization of PowerIdle Finance · Quantstamp · 23 Apr 2021Fixed

Smart contracts will often have `owner` variables to designate the person with special privileges to make modifications to the smart contract. In several contracts, the associated tokens may be changed by the owner. If the balances of the contracts are non-zero, users may not be able to retrieve funds or interact with the contract in a proper manner. In particular: * In `IdleFulcrum` and `IdleCompound`, tokens may be updated by `setToken()` and `setUnderlying()`. * In `IdleRebalancer.sol`, `setIdleToken()`, `setCToken()`, `setIToken()`, `setCTokenWrapper()`, and `setITokenWrapper()` may update underlying addresses. * In `IdleTokenV3` and `IdleRebalancerV3.sol`, the owner may add new token wrappers arbitrarily (which may not correspond to actual lending protocols). Additionally, the owner may pause/unpause certain functionalities, such as rebalancing.

Open the report
MediumUser may not be able to redeem Idle tokensIdle Finance · Quantstamp · 23 Apr 2021Fixed

If the `_tokenPrice()` is lower than the `userAvgPrices` for that user, then the `sub` method call on L911 in `_getFee` will throw an error and revert the transaction. Given that the `_getFee` function is only called in `redeemIdleToken` it will lead to users not being able to redeem Idle tokens as long as the current price is lower than the `userAvgPrices` for that user.

Open the report
MediumUnintended Revert in Function `claimIdle`Idle Governance · Quantstamp · 26 Oct 2020Fixed

In `contracts\IdleController.sol`, the function `claimIdle` will loop through all the combinations of `holders` and `idleTokens` and pass into the function `distributeIdle`. However, in the function `distributeIdle` on `L119` will revert all the transactions that pass in any `supplier != idleToken`.

Open the report
Low`newIdleToken()` may overwrite `underlyingToIdleTokenMap[_token]`Idle Finance · Quantstamp · 23 Apr 2021Fixed

If `newIdleToken()` is called with an existing `_token` address, the `IdleToken` contract referenced in the `underlyingToIdleTokenMap` will be overwritten. It is not clear if this is intended functionality.

Open the report
LowClone-and-OwnIdle Finance · Quantstamp · 23 Apr 2021Fixed

The clone-and-own approach involves copying and adjusting open source code at one's own discretion. From the development perspective, it is initially beneficial as it reduces the amount of effort. However, from the security perspective, it involves some risks as the code may not follow the best practices, may contain a security vulnerability, or may include intentionally or unintentionally modified upstream libraries. In `IdleMcdBridge.sol`, there are several libraries that could be imported: `IERC20`, `SafeMath`, `Context`, and `Address`.

Open the report
LowFunction `rebalance()` may be blocked due to Fulcrum failureIdle Finance · Quantstamp · 23 Apr 2021Fixed

On `L508` of `IdleTokenV3.sol`, the modifier `whenITokenPriceHasNotDecreased` checks that function `_rebalance` can only be executed when the iToken price has not decreased. However, since `Fulcrum` could get hacked (or the price of collateral may drop), it might not always be true. When this happens, the system would not be able to rebalance/reallocate funds for a period of time.

Open the report
LowGas constants may be affected by new EVM forksIdle Finance · Quantstamp · 23 Apr 2021Fixed

In `GST2Consumer.sol`, several constants are defined related to gas usage. Since op-code gas costs may be updated in new forks, this may cause unforeseen gas issues in future forks.

Open the report
LowGas Usage / `for` Loop ConcernsIdle Finance · Quantstamp · 23 Apr 2021Fixed

Gas usage is a main concern for smart contract developers and users, since high gas costs may prevent users from wanting to use the smart contract. Even worse, some gas usage issues may prevent the contract from providing services entirely. For example, if a `for` loop requires too much gas to exit, then it may prevent the contract from functioning correctly entirely. It is best to break such loops into individual functions as possible. In particular, the rebalancing functions may require several loops in the bisection algorithm.

Open the report
LowInconsistent array lengths breaks invariantsIdle Finance · Quantstamp · 23 Apr 2021Fixed

The length of the `allAvailableTokens` array and the `lastRebalancerAllocations` and `lastAllocations` arrays may diverge after calling `setAllAvailableTokensAndWrappers`, even if they were the same length after `manualInitialize`. This is because the allocations are not adjusted or checked to be of the same length with the `protocolTokens` or `wrappers` input arrays. This means that the owner can remove tokens from the `allAvailableTokens` array and the sum of all corresponding allocations would not be 100% after that call.

Open the report
Show 10 more
LowIncorrect average price computationIdle Finance · Quantstamp · 23 Apr 2021Fixed

The `userNoFeeQtyFrom` part of the `qty` input parameter of the`_updateUserFeeInfo` function is subtracted twice from `totBalance`: on deposits on L889 and L892. See the following code snippet: ``` 889: uint256 totBalance = balanceOf(usr).sub(userNoFeeQty[usr]); 890: // noFeeQty should not be counted here 891: // (avgPrice * oldBalance) + (currPrice * newQty)) / totBalance 892: userAvgPrices[usr] = userAvgPrices[usr].mul(totBalance.sub(qty)).add(price.mul(qty)).div(totBalance); ``` This happens because `userNoFeeQtyFrom` was already added to `userNoFeeQty[usr]`, which is first subtracted on L889. This leads to an incorrect `userAvgPrice` for that user. <br> Additionally, the `price` should not be multiplied by `qty` on L892, because on transfers, the amount that is actually transfered to `usr` is equal to `userNoFeeQtyFrom`.

Open the report
LowLength of input arrays can be differentIdle Finance · Quantstamp · 23 Apr 2021Fixed

There are multiple occurrences of this issue: 1. There is no check in place inside the `redeemAllNeeded` function inside `IdleTokenV3_1`, which checks if the length of the `tokenAddresses`, `amounts` and the `newAmounts` input arrays are equal. Since the for-loop inside this function goes up to `amounts.length` it would be problematic if the lengths of the other arrays would be different (shorter or longer). 1. There is no check in place inside the `_mintWithAmounts` function inside `IdleTokenV3_1`, which checks if the length of the `tokenAddresses` and the `protocolAmounts` input arrays are equal. Since the for-loop inside this function goes up to `protocolAmounts.length` it would be problematic if the lengths of the other array would be different (shorter or longer). 1. There is no check in place inside the `setAllAvailableTokensAndWrappers` function inside `IdleTokenV3_1`, which checks if the length of the `protocolTokens` and the `allAvailableTokens` arrays have the same length. This could lead to removing or adding tokens and/or changing the order of the tokens w.r.t. the `lastAllocations` array order.

Open the report
LowLoss of precision due to truncationIdle Finance · Quantstamp · 23 Apr 2021Fixed

The computation of the average APR inside the `getAvgAPR()` function, is performed by normalizing (dividing by `total`) the APR for each token separately and adding the normalized values together. Due to the limited precision and truncation of the division operation, there might be a loss of precision in this computation. Similarly the division by `10**18` can be moved outside of the for-loop in the `_getCurrentPoolValue` function.

Open the report
LowMissing `onlyIdle` modifier on `mint()` and `redeem()`Idle Finance · Quantstamp · 23 Apr 2021Fixed

For the functions `IdleCompoundV2.mint()` and `IdleCompoundV2.redeem()`, there is no `onlyIdle` modifier, whereas the modifier exists in the corresponding functions in `IdleCompound.sol`, `IdleFulcrum.sol`, and `IdleFulcrumV2.sol`. This would allow funds stored in the `IdleCompoundV2` wrapper contract to be sent to an arbitrary address. Although the typical dApp workflow does not store funds directly in the wrapper contract (in favor of storing balances in `IdleToken`, users interacting directly with the `IdleCompoundV2` wrapper contract may mistakenly add funds to the contract directly. Adding the `onlyIdle` modifier to these functions would mitigate these incorrect interactions.

Open the report
LowOutdated `govToken` could be used to influence the average APRIdle Finance · Quantstamp · 23 Apr 2021Fixed

The following condition in `_getAvgAPR`, on L358: `if (govTokens.length > 0 && currGov != address(0))` only checks if the length of `govTokens` is greater than zero. However, it does not check if the length of the `govTokens` is greater than `i` (the loop iterator) or if the `currGov` is in the `govTokens` array. Due to the way in which the `setGovTokens` function works, it may be the case that `currGov != address(0)` but `currGov` is not included in the `govTokens` array. This could have very severe consequences because any user is allowed to call `openRebalance`, which changes the allocations based on the results obtained from calling `_getAvgAPR`. The `_getAvgAPR` function would return the wrong results, because it would take into consideration removed `govTokens`.

Open the report
LowPotential flash loans attack vectors to claim COMP tokensIdle Finance · Quantstamp · 23 Apr 2021Fixed

After discussion with the Idle team, it appears that there may exist attack vectors that claim COMP tokens using flash loans, if a rebalance or redeem has not been invoked in a long time. This attack could occur if mint and redeem are invoked with a large balance in the same transaction (via a flash loan).

Open the report
LowThe `flashLoanFee` is not settableIdle Finance · Quantstamp · 23 Apr 2021Fixed

The `flashLoanFee` cannot be changed by a function call after the contract is deployed. The only way to change it is to upgrade/redeploy the contract.

Open the report
LowUnchecked constructor and setter address argumentsIdle Finance · Quantstamp · 23 Apr 2021Fixed

* In `IdleRebalancerV3.sol`, on L28, the constructor arguments `_yxToken` and `_rebalancerManager` were not checked to be non-zero. * In `IdleTokenV3.sol`, the constructor and all setter functions should check that addresses are non-zero.

Open the report
LowUnclear functionality in `_getFee`Idle Finance · Quantstamp · 23 Apr 2021Fixed

* The functionality of `L907`: `userNoFeeQty[msg.sender] = noFees ? noFeeQty.sub(amount) : 0;`, is unclear. It seems that what we want to achieve here is more like `userNoFeeQty[msg.sender] = balanceOf(msg.sender).sub(_amount);` when `fee == 0` and `userNoFeeQty[msg.sender] = noFeeQty.sub(amount)` when `noFeeQty >= amount`.

Open the report
LowUnclear update to `userAvgPrices` mappingIdle Finance · Quantstamp · 23 Apr 2021Fixed

In the function `_updateAvgPrice`, the mapping `userAvgPrices` is not updated if the `fee == 0`. It is not clear why the mapping is not updated in this case, but since this case is not covered, the user's average price may not be correct in all scenarios.

Open the report
Show 8 more
LowUndocumented magic constantsIdle Finance · Quantstamp · 23 Apr 2021Fixed

There are several defined constants in the code that were unclear, and would benefit from added inline documentation: * In `IdleAave.sol`, L161: the number 29; * In `IdleAave.sol`, the constant on L143 of `getApr()`: `100/10^9`; * In `GST2Consumer.sol`, all numerical constants on L15, 19-20; * In `IdleRebalancerV3.sol`, on L32, it is not immediately clear that the constant 100000 is 100%.

Open the report
LowUnlocked PragmaIdle Finance · Quantstamp · 23 Apr 2021Fixed

Every Solidity file specifies in the header a version number of the format `pragma solidity (^)0.4.*`. The caret (`^`) before the version number implies an unlocked pragma, meaning that the compiler will use the specified version _and above_, hence the term "unlocked." The file `IdleMcdBridge.sol` has several instances of unlocked pragmas throughout.

Open the report
LowUse of ABIEncoderV2 still experimentalIdle Finance · Quantstamp · 23 Apr 2021Fixed

Until solidity 0.6.0, the ABIEncoderV2 feature is still technically in experimental state. Although there are no known security risks associated with it, these features should be used judiciously.

Open the report
Low`_moveDelegates()` May Not Behave Correctly After Token TransfersIdle Governance · Quantstamp · 26 Oct 2020Fixed

In `contracts\Idle.sol`, The function `_delegate()` invokes `_moveDelegates()` with the delegator's full balance instead of remaining undelegated balance. This can cause users to lose delegation ability if additional Idle tokens are acquired without minting (i.e., via transfers). Consider the following scenario: 1. Alice has `10` Idle , which is delegated to Bob. 2. Alice acquires `1` additional Idle from a transfer. 3. If Alice attempts to re-delegate her `11` Idle tokens to Carol, it will fail due to the `SafeMath` check on `L195`; effectively, the function will attempt to undelegate `11` tokens from Bob instead of `10`, and revert. In general, if Alice's balance is ever more than the number of tokens minted toward her account (due to transfers), she will not be able to delegate. This can be mitigated by Alice by simply transferring the excess tokens out of her account, however this scenario may not be clear to end-users from a UX-perspective.

Open the report
Low`delegateBySig()` Should Validate the `v` and `s` ParametersIdle Governance · Quantstamp · 26 Oct 2020Fixed

For `contracts\Idle.sol`, `delegateBySig()` should validate the `v` and `s` parameters as in `ECDSA.sol` (See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/2bb06b1af4d57cf47c700992b327a08bebf64879/contracts/cryptography/ECDSA.sol#L46).

Open the report
LowInteger Overflow / UnderflowIdle Governance · Quantstamp · 26 Oct 2020Fixed

Integer overflow/underflow occur when an integer hits its bit-size limit. Every integer has a set range; when that range is passed, the value loops back around. A clock is a good analogy: at 11:59, the minute hand goes to 0, not 60, because 59 is the largest possible minute. Integer overflow and underflow may cause many unexpected kinds of behavior and was the core reason for the `batchOverflow` attack. Here's an example with `uint8` variables, meaning unsigned integers with a range of `0..255`. ``` function under_over_flow() public { uint8 num_players = 0; num_players = num_players - 1; // 0 - 1 now equals 255! if (num_players == 255) { emit LogUnderflow(); // underflow occurred } uint8 jackpot = 255; jackpot = jackpot + 1; // 255 + 1 now equals 0! if (jackpot == 0) { emit LogOverflow(); // overflow occurred } } ``` In particular, for `contracts\PriceOracle.sol`, there is a potential underflow on `L70`: `... 10**(18-tokenDecimals) ...`. It is recommended to use `SafeMath` for this operation.

Open the report
LowMissing Address SanitizationIdle Governance · Quantstamp · 26 Oct 2020Fixed

For `contracts\IdleController.sol`, the values inside the `priceOracle_` input parameter is not checked to be different from `0x0` inside the `_setPriceOracle` function.

Open the report
LowPossible Truncation in Calculating APR PrecisionIdle Governance · Quantstamp · 26 Oct 2020Fixed

For `contracts/PriceOracle.sol`, in function `getCompApr`, the computed pair will always return a result that has the last two digits as `0`, in `L58` due to division before multiplication `div(cTokenNAV).mul(100)`.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="idle-finance"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us