CertiK reviewed Vemate on 22 Sep 2022: 28 findings, 0 critical; 26 marked fixed, 2 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 | 2 | 0 | 0 |
| Medium | 0 | 0 | 0 |
| Low | 0 | 0 | 26 |
In line 969, the `_currentAllowance` is confirmed to be at least as large as the input `amount` through the `require` check. Hence, the SafeMath library inherent to the solidity compiler version, which protects against underflows and overflows, is not necessary here. Similarly, in line 1008, `_currentAllowance` is confirmed to be at least as large as the `subtractedValue`.
The storage variable `maxTxAmount` is initialized inline to be equivalent to the `_totalSupply` of contract tokens. Effectively, this means that at initialization, there is no bound on the number of tokens that can be transferred in a single transaction.
The function `checkSwapFrequency()` only checks the address of the `msg.sender`, which can be a contract or an externally owned account. It is easy for a user to set up interactions between multiple contracts and bypass this anti-bot feature by initiating from one contract, using that contract to call a separate contract which then interacts with the `Vemate` contract successfully within the time-lock since it does not have the same address. With this in mind, the `checkSwapFrequency()` function may not have its intended effect.
In commit [c55fd618892a47ec40e875ceb0d1b67a444532d8](https://github.com/kausar75/vemate_token/tree/c55fd618892a47ec40e875ceb0d1b67a444532d8), significant changes have been made to the functionality of file `Vemate.sol` outside the recommendations found in the audit. Below is a brief list of notable changes made from the original file. - In the struct `FeePercent`, the following `uint8` values have been removed: `lp`, `dev`, and `marketing`. The `uint8` value `treasury` has been added. - The struct outlined above initially had the following fee percent distribution: `lp` was 2, `dev` was 1, `marketing` was 1, and `charity` was 1. In the update, `treasury` is now 4 while `charity` is 1. - The symbol of the token has been changed from `V` to `VMT`. - A privileged-status function `setAutomatedMarketMakerPair()` was added. In this function, the owner of the contract can set a new pair address for use in determining fees on transfers - The internal function `_transfer()` has been altered. The function call to `swapAndLiquify()` only occurs on token sells. - The function `swapAndLiquify()` has been altered. Most notably, the calculation of fees differs because there is no longer a portion sent to `addLiquidity()`. Instead, the function now takes the entire contract token balance as the amount to swap, rather than the previous threshold amount `numTokensSellToAddToLiquidity`. This amount of tokens is swapped for `BNB` and the entire amount of `BNB` in the contract is divided into fees, 80% going to `treasury` address and 20% going to `charity` address. - The `addLiquidity()` function has been removed from the contract. This contract no longer has an automated liquidity acquisition feature.
The commented out code is not relevant to the function, `addLiquidity()`.
Boolean constants can be used directly and do not need to be compared to true or false. File: Vemate.sol (Line 752, Function `Vemate.addPrivilegedWallet`) ```solidity require(_isPrivileged[newPrivilegedAddress] != true, "already privileged"); ``` --- File: Vemate.sol (Line 759, Function `Vemate.removePrivilegedWallet`) ```solidity require(_isPrivileged[prevPrivilegedAddress] != false, "not privileged address"); ```
`Vemate` contract code size exceeds 24576 bytes, so the contract may not be deployable on the mainnet.
One or more declarations do not conform to the [Solidity style guide](https://solidity.readthedocs.io/en/v0.7.3/style-guide.html#naming-conventions) with regards to its naming convention. Particularly: - `camelCase`: Should be applied to function names, argument names, local and state variable names, modifiers - `UPPER_CASE`: Should be applied to `constant` variables - `CapWords`: Should be applied to contract names, struct names, event names and enums --- File: Vemate.sol (Line 640, Contract `Vemate`) ```solidity uint8 public constant maxFeePercent = 5; ``` - Constant variable `maxFeePercent` is not in `UPPER_CASE`.
The function `setSwapTolerancePercent()` allows for the storage variable `swapSlippageTolerancePercent` to be set to as high as 100%. If it is set to this maximum value, users could lose 100% of their expected BNB output to slippage.
The `Vemate` contract switches between referencing ETH and BNB within multiple functions, variables, and comments. The following function declared within the `Vemate` contract includes references to ETH: - `swapTokensForEth()` The following local variables include references to ETH: - `ethAmount` - `minETHAmount`
State variables are inline initialized using either non-constant state variable or function calls that are not pure/constant. Since inline initialization occurs before constructor call, some non-constant state variables may not be initialized and non-constant functions may behave in an unexpected way. File: Vemate.sol (Line 649, Contract `Vemate`) ```solidity uint256 private _totalSupply = 150000000 * 10**_decimals; // 150 million; ``` --- File: Vemate.sol (Line 658, Contract `Vemate`) ```solidity uint256 public maxTxAmount = _totalSupply; ``` --- File: Vemate.sol (Line 659, Contract `Vemate`) ```solidity uint256 public numTokensSellToAddToLiquidity = 10000 * 10**_decimals; // 10 Token ```
The storage variable `lockedBetweenSells` is initialized at 60, but can be updated with the function, `setLockTimeBetweenSells()`. This function requires that the new input for `lockedBetweenSells` is no more than 30.
The comment in line 659 looks like it is saying that `numTokensSellToAddToLiquidity` should be 10, but instead, this value is set to 10,000.
There should always be events emitted in the sensitive functions that are controlled by centralization roles or when important updates are made to the contract.
For the functions `setMaxTxAmount()`, `updateTokenPrice()`, and `setMinTokenToSwapAndLiquify()`, there is no validation check in place to verify that the input for updated variable meets an expected standard. Since all three functions accept type `uint256`, the input can be any number within this range, which could make the contract behave unexpectedly. For instance, it is possible the `numTokensSellToAddToLiquidity` could be set to 0, meaning a transfer of any amount causes `swapAndLiquify()` to be called. Additionally, it's also possible to input a value for `maxTxAmount` that is greater than the `_totalSupply` value, which would not make sense.
Addresses should be checked before assignment or external call to make sure they are not zero addresses. File: Vemate.sol (Line 872, Function `Vemate.withdrawResidualBNB`) ```solidity payable(newAddress).transfer(address(this).balance); ``` - `newAddress` is not zero-checked before being used.
For each of the functions, `setLpFeePercent`, `setDevFeePercent`, `setMarketingFeePercent`, and `setCharityFeePercent`, the whole storage variable `fee` is updated during each execution of the functions, when only one of the objects (`fee.lp`, `fee.dev`, `fee.marketing`, or `fee.charity`) is actually being changed during the function call. Storage variables are expensive to update, and should be minimized whenever possible.
A local variable is shadowing another component defined elsewhere. File: Vemate.sol (Line 1186, Function `Vemate._approve`) ```solidity function _approve(address owner, address spender, uint256 amount) internal { ``` - Local variable `owner` shadows the function `owner` in `Ownable`. File: Vemate.sol (Line 123, Contract `Ownable`) ```solidity function owner() public view virtual returns (address) { ``` --- File: Vemate.sol (Line 937, Function `Vemate.allowance`) ```solidity function allowance(address owner, address spender) external override view returns (uint256) { ``` - Local variable `owner` shadows the function `owner` in `Ownable`. File: Vemate.sol (Line 123, Contract `Ownable`) ```solidity function owner() public view virtual returns (address) { ```
Literals with many digits are difficult to read and review. File: Vemate.sol (Line 649, Function `Vemate.slitherConstructorVariables`) ```solidity uint256 private _totalSupply = 150000000 * 10**_decimals; // 150 million; ```
```solidity require(owner() != address(0), "Owner must be set"); ``` The `require` code here is unnecessary since, upon construction, the owner is set to the address that deploys the contract. It is not possible for `address(0)` to deploy a contract.
The return value of an external call is not stored in a local or state variable. File: Vemate.sol (Line 1141-1148, Function `Vemate.addLiquidity`) ```solidity uniswapV2Router.addLiquidityETH{value: ethAmount}( address(this), tokenAmount, minTokenAmount, minETHAmount, address(this), getCurrentTime() ); ```
The following state variable is never used in the codebase. Variable `blockTimestampLast` in `Vemate` is never used in `Vemate`. File: Vemate.sol (Line 645, Contract `Vemate`) ```solidity uint32 private blockTimestampLast; ```
Since there was a check that the input `amount` for this function does not exceed `_balances[sender]` in the internal function `_transfer()`, the update to `_balances[sender]` can be safely declared inside `unchecked{}`. The difference, `_balances[sender] - amount` will not underflow, and this will optimize gas savings.
`block.timestamp` is used for comparison, which can be risky since timestamp can be influenced by miners. That means the miner creating the block can manipulate the `block.timestamp`, to some degree, and change the outcome of the transaction. File: Vemate.sol (Line 1198-1199, Function `Vemate.checkSwapFrequency`) ```solidity require(currentTime - lastSwapTime >= lockedBetweenSells, "Lock time has not been released from last swap" ); ```
In the event `Transfer`, `msg.sender` is used rather than the inherited function `_msgSender()`.
The linked variables could be declared as `constant` since these state variables are never modified.
| Address | Chain | Source code |
|---|---|---|
| 0x1f18…24b90x1f1855a2cee5fd8af65446d2ac01ffe458d924b9 | Chain: BNB Chain | Source code: Verified source |
| 0xe615…8e510xe615c5e7219f9801c3b75bc76e45a4dab3c38e51 | Chain: BNB Chain | Source code: Verified source |
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