CertiK reviewed Genie Swap (GenieSwap) on 26 Jan 2023: 11 findings, 0 critical; 10 marked fixed, 1 acknowledged.
Report hosted on skynet.certik.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 0 |
| Medium | 0 | 1 | 1 |
| Low | 0 | 0 | 9 |
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`.
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.
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; ```
A sophisticated user is able to reenter the `_mintToken` function. Currently, this reentrancy is not known to cause a loss of funds.
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.
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 ```
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; ```
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'); ```
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} $$
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.**
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (4)
1,044 projects reviewed · 1,375 reports · latest May 2025
See CertiK’s auditsSomething 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