CertiK reviewed Mazimatic (Mazimatic - New Audit) on 27 Mar 2023: 20 findings, 0 critical; 16 marked fixed, 4 open.
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 | 0 | 2 |
| Low | 4 | 0 | 14 |
Transfers to the `pairAddress` when executing `_transfer()` calls function `_botManager()` to calculate the value of `amount2` to be one of the following, depending on the timing in relation to the liquidityTimestamp: 1. 10% of amount 2. 5% of amount 3. 0 After everything is completed in the `_botManager()` and `antisnipe.assureCanTransfer()` functions, another 5% of `amount` will be added to `amount2`. In the last line of function `_transfer()`, the value of `amount` is compared with `amount2` to decide which value to use when performing the transfer. ```solidity=133 super._transfer(from, to, amount2 > amount ? amount : amount2); ``` As shown in the previous line, since the calculation of `amount2` is always based on a percentage of `amount`, `amount2` will always be less than `amount`. Even after the extra 5% is added onto `amount2`, the max value of `amount2` would be 15% of `amount` (if 10% of `amount` returned by `_botManager()` function). ```solidity=132 amount2 += (amount * 500) / 10000; ``` This would mean that the function `super._transfer()` will always transfer an amount less than the `amount` used as the input parameter for function `_transfer()` and in almost all cases the `amount` is never transferred. The audit team would like to understand the rationale and logic behind this implementation.
The function `_botManager()` will return 0 in the case when `liquidityTimestamp + 24 hours = block.timestamp`, since it falls into the else statement criteria. There is currently no case that handles this situation in `_botManager()`. This would mean that the amount transferred to the `pairAddress` might be less than originally intended. ```solidity=139 if (block.timestamp < liquidityTimestamp + 24 hours) { return (amount * 1000) / 10000; } else if ( liquidityTimestamp + 24 hours < block.timestamp && block.timestamp < liquidityTimestamp + 48 hours ) { return (amount * 500) / 10000; } ```
The `__createUniswapPair()` function executes the `IUniswapV2Factory(_factory).createPair()` method, which in some rare cases may return the zero address due to the fact that `create2` assembly opcode may fail when creating the pair. If the zero address is assigned to `pairAddress` at deployment, there is no way to update it and the contract will not work as intended and the contract needs to be redeployed.
The constructor contains a call to `_disableInitializers()` to prevent the initializer from being called on the logic contract but the code is commented out. In this way, an attacker can call the initializer and assume ownership of the logic contract, whereby she can perform privileged operations that trick unsuspecting users into believing that she is the owner of the upgradeable contract.
The functions `setAntibot()` and `bulkAntiBot()` can be used to both add or remove addresses from the array `_isBot` by either setting the `state` to true or false. The events `AntiBotAdded` and `BulkAntiBotsAdded` seem to imply that all addresses were set as true.
There is no check in function `setMaxTxAmount()` to ensure that the input parameter `_maxTxAmount` is lower than or equal to the current value of the total supply.
The function `updateCoolDownSettings()` allows the owner to edit the `coolDownEnabled` and `coolDownTime` state variables. If `coolDownEnabled` is set to `true` then there must be a check to ensure that the new value of `coolDownTime` is not zero.
There should always be events emitted in the sensitive functions that are controlled by centralization roles.
The **require** can be used to check for conditions and throw an exception if the condition is not met. It is better to provide a string message containing details about the error that will be passed back to the caller.
Inside the '_transfer()' function, the input addresses 'from' and 'to' are zero-checked twice: at the beginning of the function and inside the `if` condition in lines 126 & 127. In particular the checks inside the `if` condition are redundant: ```solidity=126 from != address(0) && to != address(0) && ```
The return value of the `transfer()` call is not checked. ```solidity=203 IERC20Upgradeable(_tokenAddr).transfer(_to, _amount); ```
When executing the `_transfer()` function with particular inputs the outcome may not be as desired. Suppose: - the user calls `transfer(pairAddress, 1e9 * 10 ** 18)` with the intent to transfer 1_000_000 Mazi tokens to the `pairAddress`; - `_transfer(msg.sender, pairAddress, 1e9 * 10 ** 18)` is invoked; - the return value of `_botManager(pairAddress, 1e9 * 10 ** 18)` call is assigned to `amount2`. Assuming that ```solidity block.timestamp > liquidityTimestamp + 48 hours ``` we expect that the return value assigned to `amount2` is 0 and therefore the transfer to `pairAddress` must consist of 0 tokens - execution of the `_transfer()` function resumes and `amount2` is overwritten with the value ```solidity amount2 += (1e9 * 10 ** 18 * 500) / 10000 ``` - consequence of this is that a large number of Mazi tokens will still be transferred to the `pairAddress`
There is no need to override the function `totalSupply()` inherited from `ERC20Upgradeable` with the intent of returning a fixed value for the totalSupply() since the actual implementation will return an incorrect value if new tokens will be minted in the future.
The function `airdropTokens()` use the `payable` modifier twice: - for the function signature - for the input `recipients` This modifier is not necessary in both cases since no ETH should be transferred to the contract during the function's execution: its goal is to transfer only ERC20 tokens.
The following event ```solidity=38 event LiquidityAddedBool(); ``` is declared in `Mazimatic` but never emitted.
It is not recommended to use Solidity's `transfer()` and `send()` functions for transferring Ether, since some contracts may not be able to receive the funds. Those functions forward only a fixed amount of gas (2300 specifically) and the receiving contracts may run out of gas before finishing the transfer. Also, EVM instructions' gas costs may increase in the future. Thus, some contracts that can receive now may stop working in the future due to the gas limitation. ```solidity=192 payable(owner()).transfer(weiAmount); ``` - `Mazimatic.rescueETH` uses `transfer()`.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (1)
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