Ice - Audit 1

CertiKFiles named in the report

CertiK reviewed Ice Open Network (Ice - Audit 1) on 10 Jan 2024: 17 findings, 0 critical; 15 marked fixed, 2 acknowledged.

No open critical findings
Open the reportOpen Ice Open Network’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings17

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

SeverityOpenAcknowledgedFixed
Critical000
High024
Medium001
Low0010
HighIncorrect Usage of SlippageFixed

In the `_addLiquidity()` function, the contract sets the minimum amount of the native token and the `ICE` token. However, it is noted that the minimum amount is calculated by the current corresponding balance in the contract, which is possibly inconsistent with the current token price in the pair and causes the failure to add liquidity. In the `_swapTokensForEth()` function, the contract uses this value `(tokenAmount * (100 - _slippage)) / 100` as the `amountOutMin` of `swapExactTokensForETHSupportingFeeOnTransferTokens()`, which is incorrect since the the output ETH amount is determined by the price in the pair.

HighPausing Centralization RiskFixed

In the contract `ICEToken`, the role `_owner` has authority to pause/resume the functionality of token transfer. Any compromise to the private key of the `owner` may allow hackers to take advantage of this authority and disable or enable the transfer.

HighPotential Dos AttackFixed

It is noted that the contract calls `_swapBack()` in every sell or normal transfer transaction. In the `_swapBack()` function, the contract will try to add liquidity if `totalTokensToSwap == 0` and `contractBalance != 0`. However, if a malicious holder transfers some tokens to the current token contract when `tokensForLiquidity = 0` and `tokensForOperations = 0`, the normal transfer transaction and sale will fail due to the `INSUFFICIENT_LIQUIDITY_MINTED` error. Although the `totalTokensToSwap` and `address(this).balance` can be changed by buying operations, it still can cause side effects to the project due to the following code. ```solidity=702 tokensForLiquidity = 0; tokensForOperations = 0; ... if (address(this).balance > 0) { (success,) = address(operationsAddress).call{value: address(this).balance}(""); } ```

HighPotential Flashloan AttackFixed

The contract takes an extra amount of tokens as the fee from the sender when buying, not directly deducting the fee from the transfer amount, and it is also noted that the contract supports more than one pool. However, we found that current implementation is vulnerable to the flashloan attack. For example, the malicious can use a flashloan and combination of calling `skim()` and `sync()` functions to decrease the pool liquidity and make a profit.

MediumMissing Input Validation in `setUniswapV2LiquiditFixed

The pointed input parameters are not validated. In particular, the following checks should be added: - Check if `pairAddress` already exists in `uniswapV2LiquidityPools` - Check if `routerAddress` is a zero address Moreover, there are no upper boundaries for **setUniswapV2LiquidityPool()** which is used to set the liquidity/operation fee of buy/sell. It is possible to set the total fee rate up to any arbitrary amount, which is unreasonable and may cause the loss of users' assets. - `buyOperationsFee` plus `buyLiquidityFee` should lie in (0, 100) according to the function `_transfer()`. - `sellOperationsFee` plus `sellLiquidityFee` should lie in (0, 100) according to the function `_transfer()`.

Low`botsCaught` Will Always be ZeroFixed

The state variable `botsCaught` is used to record caught bots with a default value of zero. However, per the function `_transfer()`, if a bot is caught, the function will raise a `NoBots` error, thus botsCaught won't be updated and will remain zero forever. ```solidity function _transfer(address from, address to, uint256 amount) internal { //... if (bots[from] || bots[to]) { botsCaught++; revert NoBots(); } //... } ```

LowFrequent call to `_swapBack()`Fixed

It is noted that the contract calls `_swapBack()` on every normal transfer and sell transaction, which is too frequent and unnecessary especially when the token amount in the token contract is very small.

LowICE token should be excluded from `transferForeigFixed

The function `transferForeignToken()` allows the owner to transfer any ERC20 token to any address. ```solidity function transferForeignToken(address _token, address _to) external onlyOwner returns (bool _sent) { require(_token != address(0), "_token address cannot be 0"); uint256 _contractBalance = IERC20(_token).balanceOf(address(this)); _sent = IERC20(_token).transfer(_to, _contractBalance); emit TransferForeignToken(_token, _contractBalance); } ``` However, per the function name, only foreign tokens except the' ICE' token can pass in. The owner can pass the ICE token address and transfer all the fee tokens to an arbitrary address.

LowMissing Break In LoopFixed

```solidity for (uint i = 0; i < uniswapV2LiquidityPools.length; i++) { if (uniswapV2LiquidityPoolSlots[uniswapV2LiquidityPools[i]].router == msg.sender) { interactingToRouter = true; } } ``` If `msg.sender` is found as a router, the loop can be finished and popped to save gas.

LowMissing Check Input AmountFixed

It is noted that the function `_swapTokensForEth()/_addLiquidity()` doesn't check if the amount variable is above zero before executing the `swapExactTokensForETHSupportingFeeOnTransferTokens()` or `addLiquidityETH()`, which cause the transaction fails. Since these functions are called in the normal transfer/sell/buy transactions, their side effects are amplified in current contract.

Show 5 more
LowPotential Sandwich AttacksFixed

A sandwich attack might happen when an attacker observes a transaction swapping tokens or adding liquidity without setting restrictions on slippage or minimum output amount. The attacker can manipulate the exchange rate by frontrunning (before the transaction being attacked) a transaction to purchase one of the assets and make profits by backrunning (after the transaction being attacked) a transaction to sell the asset. The following functions are called without setting restrictions on slippage or minimum output amount, so transactions triggering these functions are vulnerable to sandwich attacks, especially when the input amount is large: - `swapExactTokensForETHSupportingFeeOnTransferTokens()` - `addLiquidityETH()`

LowRedundant CodeFixed

It is noted that the contract calls `transferOwnership()` to transfer ownership to `operationsAddress`, which has been set to `msg.sender` in the previous statement. However, the `msg.sender` has been set to the owner of the contract in the `Ownable(msg.sender)`. ```solidity=168 constructor() ERC20("ICE", "ICE") Ownable(msg.sender) { operationsAddress = msg.sender; transferOwnership(operationsAddress); ... } ```

LowUnchecked value from low-level callFixed

Ignores return value of low-level calls. ```solidity=668 (success,) = address(operationsAddress).call{value: address(this).balance}(""); ``` ```solidity=682 (success,) = address(msg.sender).call{value: address(this).balance}(""); ```

LowUnchecked Value of ERC-20 `transfer()`/`transferFFixed

The linked `transfer()` invocation does not check the return value of the function call which should yield a `true` result in case of a proper ERC-20 implementation.

LowUnused Return ValueFixed

The smart contract does not check or store the return value of an external call in a local or state variable, which may introduce vulnerabilities due to the unhandled outcome. ```solidity=651 IDEXRouter(receiver.router).addLiquidityETH{value: ethAmount}( address(this), tokenAmount, 0, // slippage is unavoidable 0, // slippage is unavoidable address(0xdead), block.timestamp ); ```

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 (3)

  • contracts/ICEToken.sol
  • contracts/IDEXFactory.sol
  • contracts/IDEXRouter.sol

Part of Ice Open Network’s security record

Ice Open Network
Audits1 audit by 1 firmLast audit Jan 2024, by CertiK.
Critical findingsNo open critical findingsIn 1 report.
Open Ice Open Network’s security record

Security firm

CertiK

1,044 projects reviewed · 1,375 reports · latest May 2025

See CertiK’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