Impossible Finance

QuantstampFiles named in the report

Quantstamp reviewed Impossible Finance on 7 Mar 2024: 13 findings, 0 critical; 8 marked fixed, 5 acknowledged.

No open critical findings
Open the reportOpen Impossible Finance’s security record

Report hosted on certificate.quantstamp.com.

Trustblock does not review code.

Findings13

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

SeverityOpenAcknowledgedFixed
Critical000
High001
Medium001
Low056
LowChecks-Effects-Interactions Pattern ViolationAcknowledged

The [Checks-Effects-Interactions](https://solidity.readthedocs.io/en/latest/security-considerations.html#use-the-checks-effects-interactions-pattern) coding pattern is meant to mitigate any chance of other contracts manipulating the state of the blockchain in unexpected and possibly malicious ways before control is returned to the original contract. As the name implied, only after checking whether appropriate conditions are met and acting internally on those conditions should any external calls to, or interactions with, other contracts be done. The CEI pattern should be followed in `IFFundable.cash()`.

LowConfusing Variable Naming in the CodebaseAcknowledged

There are various instances of variable and function naming that can lead to confusion. Here is a non-exhaustive list: - `salePrice`: This variable indicates how many purchase tokens one needs to buy a sale token. Specifically, `salePrice/SALE_PRICE_DECIMALS` is the amount of purchase token needed to buy one sale token. - `saleTokenPurchased`: This variable doesn't keep track of the number of sale tokens purchased, but the number of purchase tokens spent to buy sale tokens. It may be better to name this `totalPaymentReceived`, like in `IFSale.sol`. Note that `totalPaymentReceived` in `IFSale.sol` is tracking the same thing as `saleTokenPurchased` in `IFPurchasable.sol`. - `minTotalPayment`: This variable represents the minimum amount of payment amount one needs to pay to purchase sale tokens (per purchase). It may be more reasonable to name it `minPaymentPerPurchase`. - `maxTotalPurchasable`: Rather than the maximum amount of sale tokens one can purchase, this variable is denominated in payment tokens, representing the number of maximum payment tokens one can use to purchase sale tokens. For example, it may be more reasonable to rename this to `maxTotalPurchasableInPaymentToken`. In general, when dealing with a sell token and purchase token, as well as the relative price between the pair of tokens, having variable names that are consistent and indicative of the token denomination will help improve readability and maintainability. For example, it will be much clearer if we rename `allocation` to `allocationOfSaleToken`.

LowPossible Sybil Attack Circumventing Purchase WhitelistAcknowledged

We want to raise awareness of the fact that in case `IFFixedSale.publicAllocation` is set to a non-zero amount there is no sybil protection, effectively circumventing the whitelist mechanism. When a fixed allocation of the token is purchasable by individual addresses that are not whitelisted via `IFFixesale.whitelistPurchase()` or `IFFixedSale.whitelistPurchaseWithCode()`. So, a savvy user could quickly sweep the funded tokens by calling these functions from many different addresses, getting the fixed allocation for each. Furthermore, an arbitrary amount of codes can be used that way, circumventing the unique code limit for each user set in `maxPromoCodePerUser`.

LowPotentially Inaccurate "Principal" Tokens CalculationAcknowledged

The `IFFundable.cash()` function uses the following logic to calculate the `principal` variable: ``` // Get the amount of sale token on the contract uint256 saleTokenBal = saleToken.balanceOf(address(this)); // Get the amount of tokens sold uint256 totalTokensSold = getSaleTokensSold(); // Determine principal (the greater of sale amount or amount on contract) uint256 principal = saleAmount < saleTokenBal ? saleTokenBal : saleAmount; ``` The intent, as discussed with the team, is to enable the project team to retrieve whatever is on the contract, excluding the tokens already sold. The `saleTokenBal` accounts for scenarios where there are unexpected transfers of the sale token to the contract, making `saleAmount` an inaccurate reflection of the contract's total sale token balance. A concern arises because `saleToken.balanceOf(address(this))` might not accurately represent the tokens available for withdrawal after users have made withdrawals. Once a withdrawal occurs, the accounting may become inaccurate. We consider the severity of this issue to be relatively low because the locked funds are funds that are not meant to be in the contract in the first place (e.g. accidental transfer).

LowPrivileged Roles and OwnershipAcknowledged

All privileged permissions should be clearly documented for users. The privileged permissions of the audited contracts are documented below: **IFFixedSale.sol** * Owner * Via `setVestedGiveaway()`, the owner toggle between can making the giveaway a standard fixed payout-giveaway or making it a vested-giveaway, activating the vesting logic for the giveaway. * Via `setPublicAllocation()`, the owner can set the public allocation granted to all users in case users are not on the white list. **IFSale.sol** * Owner * Via `setWithdrawDelay()`, the owner can set an additional withdraw delay after the sale period. * Via `setLinearVestingEndTime()`, the owner can activate and define the terms of the vesting schedule. This can deactivate a previous cliff schedule. * Via `setCliffPeriod()`, the owner can activate and define the terms of the cliff schedule. This can deactivate a previous vesting schedule. **IFVestable.sol** * Owner * Via `setVestingEditable()`, the owner can toggle a value that can enable continuing to switch between the cliff and vesting schedule, even if the withdrawal period has already started. * Via `setLinearVestingEndTime()`, the owner can change and adjust the end time of the vesting schedule, before the withdrawal period or if `vestingEditable` is enabled. * Via `setCliffPeriod()`, the owner can change to and adjust the end time of the cliff schedule, before the withdrawal period or if `vestingEditable` is enabled. **IFFundable.sol** * Owner * Via `setCasher()`, the owner can update the casher address at all times. * Via `setFunder()`, the owner can update the funder address at all times. * Via `setWithdrawDelay()`, before the sale period, the owner can add and adjust an additional withdraw delay, which can not exceed five years. * Via `emergencyTokenRetrieve()`, after the sale period, the owner can withdraw funds from arbitrary tokens which are not the saleToken. * The owner shares all privileges of Casher. This is notable as `cash()` and `cashPaymentToken()` send the funds to `msg.sender`, not the funder address. So the owner could technically front-run the Casher address. * Casher * Via `cash()`, after the sale period, the casher can withdraw all payment token and unsold saleToken. * Via `cashPaymentToken()`, the casher can withdraw up to the whole balance of payment token the contract has received. * Funder * Via `fund()`, the funder can add additional tokens for sale up until the start time of sale. **IFPurchasable.sol** * Owner * Via `setIsPurchaseHalted()`, the owner can pause all purchasing activities. * Via `setMinTotalPayment()`, the owner can set an optional minimum payment a user has to make in order to purchase saleTokens. * Via `setMaxTotalPurchasable()`, the owner can set an optional maximum payment a user can make to limit the amount of purchasable tokens. **IFWhitelistable.sol** * Owner * Via `setWhitelistSetter()`, the owner can set an address to hold the WhitelistSetter-role. * The owner shares all privileges with the WhitelistSetter. * WhitelistSetter * Via `setWhitelist()`, the WhitelistSetter can set and unset the root of the Merkle tree used for the whitelisting feature at all times.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (6)

  • IFPurchasable.sol
  • IFVestable.sol
  • IFFundable.sol
  • IFWhitelistable.sol
  • IFSale.sol
  • IFFixedSale.sol

Part of Impossible Finance’s security record

Impossible Finance
Audits1 audit by 1 firmLast audit Mar 2024, by Quantstamp.
Critical findingsNo open critical findingsIn 1 report.
IncidentIncident 20 Jun 2021Source: De.Fi incident database.
Open Impossible Finance’s security record

Security firm

Quantstamp

236 projects reviewed · 332 reports · latest Oct 2026

See Quantstamp’s audits

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