GenieSwap

CertiKFiles named in the report

CertiK reviewed Genie Swap (GenieSwap) on 26 Jan 2023: 11 findings, 0 critical; 10 marked fixed, 1 acknowledged.

No open critical findings
Open the reportOpen Genie Swap’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings11

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

SeverityOpenAcknowledgedFixed
Critical000
High000
Medium011
Low009
MediumDenial of Service on ReferralFixed

In the function `_mintToken`, if the variable `flushOnTransaction` is set to the `true` and the input address `token` is an ERC20 then the contract can revert unintentionally. This leads to a denial of service on the Genieswap.sol contract when calling the function `_mintToken`.

LowHidden Assumption for SwapRouter03Fixed

The main functionality of `SwapRouter03` is to charge a fee for swapping by removing a small portion of acquired funds. However it should be noted that a user is able to completely bypass these fees by using another router contract.

LowMissing Zero Address ValidationFixed

The `flushAddress` variable is only set by a privileged account. If this address is set to the zero address all potential future accrued tokens will be lost. ```solidity=60 flushAddress = _flush; ``` --- ```solidity=211 flushAddress = to; ```

LowMulti-function Reentrancy CallFixed

A sophisticated user is able to reenter the `_mintToken` function. Currently, this reentrancy is not known to cause a loss of funds.

LowPossible Integer Underflow and OverflowFixed

In the function `processAmountOut` of the `SwapRouter03.sol` contract, the mathematical statement defined below is able to underflow. ```solidity=109 uint256 fee = _calculateFee(amount); amountOut = amount - fee; ``` This occurs if and only if the variable amount is equivalent to fee. The calculation of fee is dependent the equation: ```solidity=103 return (amount * feeSchedule) / feeBasis ``` This underflow occurs only if `feeSchedule` is equal to `feeBasis`. Respectively an overflow can occur in line 103, however the amount needed to overflow would be close to the upper range $2^{256} - 1$. The resulting fee would be negligible in this case. However, this is unlikely to have any critical effects since the amount of tokens needed to trade would far exceed the current amount. For example, the approximate amount of ether needed to cause an overflow would be the following: $$115792089237316203707617735395386539918674240093853421928448$$ However, there exists approximately 120 million ether.

LowRedundant Return StatementFixed

The function `_mintRate` returns the current rate based on the current `window`. For the following code block, whether the window is 0 or 1 the return value is the same. ```solidity if(window < 1) { return 10; } // Month 1: 0.010 if(window < 2) { return 10; } // Month 2: 0.010 ```

LowState Variable Should Be Declared ConstantFixed

The state variable `twapInterval` never changes. In this case, if this variable is declared as `constant` it will save gas. ```solidity=70 int32 public twapInterval = 60 minutes; ```

LowUnreachable Require StatementFixed

The function `setLaunchDay` updates the state variable `launchDay` given the following conditions: 1. The number of days, determined by the function `_currentDay`, is less than 30 days; 2. The `mintPhaseClosed` has not been updated. However the variable `mintPhaseClosed` can only be set to true if `_currentDay` is more than 365. Therefore the following conditions hold: 1. If `_currentDay` is less than 30 days then mintPhaseClosed is `False`; 2. If `_currentDay` is larger than 365 days and `mintPhaseClosed` is true then `setLaunchDay` reverts before reaching the fact that mintPhaseClosed is True. This implies the second require statement, seen below, is never triggered. ```solidity // @dev allow owner to set the launch date function setLaunchDay() external onlyOwner{ // Restrict to first 30 days require(_currentDay() < 30, 'Minting phase has started'); // Only closable once require(!mintPhaseClosed, 'Minting already closed'); launchDay = _today(); } ``` A similar issue occurs in the function `_mintToken()` at the third require statement. ```solidity // @dev mint token using TWAP function _mintToken(address token, uint256 amount, address to, address referrer) internal returns ( uint256 value, uint256 rate, uint256 minted ) { // Require at least something require(amount > 0, 'Amount must be > 0'); // Restrict to launch days require(_currentDay() < launchDays, 'Minting phase has ended'); // Only closable once require(!mintPhaseClosed, 'Minting already closed'); ```

LowVerification of Price Calculation from Tick MathFixed

The function `_getSqrtTwapX96()` calculates the 60 minute time-weighted average price for a given UniswapV3 pool. The output of this function is dependent on the output of `getSqrtRatioAtTick()`. The output of the utility function `getSqrtRatioAtTick` is the sqrt price with respect to token0 and token 1. This is modeled by the following equation: $$sqrtPriceX96 = \sqrt{token0/token1} * 2^{96} $$ The function `_getPriceX96FromSqrtPriceX96` uses the output of the function `_getSqrtTwapX96() to obtain the standard price. However the computation is given by the following line of code: ```solidity return FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, FixedPoint96.Q96) ``` This computation returns the following computation: $$ PriceQ96 = \sqrt{token0/token1} * \sqrt{token0/token1} * 2^{96} $$

LowVerification of ValueFixed

This is an informational finding that verifies correct computation of prices through multiple functions such as: -`_quoteToken` -`_getPriceX96FromSqrtPriceX96` -`_mintToken` Within the function `_quoteToken` the variable `value` is computed. This variable represents the amount of tokens that will be transferred in terms of USDC value. There are three possible cases to consider when computing the variable `value`: 1. The input address `token` is equivalent to `USDC` 2. The input address `token` is not `USDC` but `USDC` is the first token in UniswapV3Pool 3. The input address `token` is not `USDC` but `USDC` is the second token in UniswapV3Pool ### Case 1. If the address `token` is equivalent to `USDC` then value is equivalent to amount of `USDC` that will be transferred. ### Case 2. If `USDC` is the first token in UniswapV3Pool then value is defined by the following equation: $value = (amount * 2 ^ {96}) / price$, where the `price` is calculated by the function `_getPriceX96FromSqrtPriceX96`. The `price` is represented by the equation, $token1/token0 * 2^{96}$, where `token1/token0` represents the number of `token1` per `token0`. Therefore, `value` is defined to be the amount of `token1` multiplied by the number of `token0` per `token1`. ### Case 3. If `USDC` is the second token in UniswapV3Pool then value is defined by the following equation: $value = (amount * price) / 2 ^ {96}$. The `price` is calculated by the function `_getPriceX96FromSqrtPriceX96` and is represented to be the following ratio: $token1/token0 * 2^{96}$. Therefore, value is defined to be the amount of `token0` multiplied by the number of `token1` per `token0`. **Summary - The `value` variable represents USDC value of transferred tokens based on price of UniswapV3 pool TWAP over 60 minutes.**

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

  • contracts/lib/TickMath.sol
  • contracts/SwapRouter03.sol
  • contracts/GenieSwap.sol
  • contracts/lib/FullMath.sol

Part of Genie Swap’s security record

Genie Swap
Audits3 audits by 2 firmsLast audit Jan 2024, by Hacken.
Critical findingsNo open critical findingsAcross the 3 reports, 1 critical finding was reported. It is marked fixed by the firm that reported it.
Open Genie Swap’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