Qrkita Exchange

CertiK1 address on BNB Chain

CertiK reviewed Qrkita (Qrkita Exchange) on 30 May 2023: 17 findings, 0 critical; 13 marked fixed, 2 acknowledged, 2 open.

No open critical findings
Open the reportOpen Qrkita’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
High022
Medium004
Low207
HighCentralized risk in `addLiquidity`Fixed

```solidity=1043 // add the liquidity uniswapV2Router.addLiquidityETH{value: ethAmount}( address(this), tokenAmount, 0, // slippage is unavoidable 0, // slippage is unavoidable owner(), block.timestamp ); ``` The `addLiquidity` function calls the `uniswapV2Router.addLiquidityETH` function with the `to` address specified as `owner()` for acquiring the generated LP tokens from the `QRT-BNB` pool. As a result, over time the `_owner` address will accumulate a significant portion of LP tokens. If the `_owner` is an EOA (Externally Owned Account), mishandling of its private key can have devastating consequences to the project as a whole.

HighContract gains non-withdrawable BNB via the `swapFixed

The `swapAndLiquify` function converts half of the `contractTokenBalance` QRT tokens to BNB. The other half of QRT tokens and part of the converted BNB are deposited into the QRT-BNB pool on pancakeswap as liquidity. For every `swapAndLiquify` function call, a small amount of BNB leftover in the contract. This is because the price of QRT drops after swapping the first half of QRT tokens into BNBs, and the other half of QRT tokens require less than the converted BNB to be paired with it when adding liquidity. The contract doesn't appear to provide a way to withdraw those BNB, and they will be locked in the contract forever.

Medium`_previousBurnFee` is updated to `_taxFee` in mulFixed

The following 4 functions set different fee rates for the 4 types of fee, and updates the corresponding "previous fee" variable. During the process, `_previousBurnFee` is updated to `_taxFee` instead of `_burnFee`. - `enableDefaultFees()` - `enableLowFees()` - `enableHighFees()` - `disableAllFees()` ```solidity=1133 function enableDefaultFees() external onlyOwner() { _taxFee = 12; _previousTaxFee = _taxFee; _liquidityFee = 5; _previousLiquidityFee = _liquidityFee; _burnFee = 4; _previousBurnFee = _taxFee; _marketingFee = 3; // Marketing fee is to energize the token development and also a buyback & burn program. _previousmarketingFee = _marketingFee; inSwapAndLiquify = true; emit SwapAndLiquifyEnabledUpdated(true); } ```

Medium`restoreAllFee()` sets fee rates to default fee rFixed

In function `_tokenTransfer()`, if the sender or receiver is excluded from fees, the code will call `removeAllFee()` to set all the fee to 0 before the transfer. When token transfer finishes, the code will call `restoreAllFee()` to set the fees back. Function `restoreAllFee()` does not restore the fees from the 4 "previous fees"; instead, it updates the fee to a fixed value. This set of values seem to be the default rate, as it matches the setting in function `enableDefaultFees()`. This could be a problem because the contract also allows for other sets of fee rates. Once an excluded account makes/receives a transfer, the fee rate will be reset to default, whatever the previous fee rate. ```solidity=949 function restoreAllFee() private { _taxFee = 12; _liquidityFee = 5; _burnFee = 4; _marketingFee = 3; } ```

MediumPancake Pair not Excluded From RewardsFixed

Generally, deflationary tokens are incompatible with DEX and special rules need to be coded for DEX addresses eg. excluding them from reward. Otherwise, a hacker can exploit the protocol using the reflection mechanism.

MediumProblematic design of `_burnFee`Fixed

Contract `QrkitaToken` introduces `_burnFee` and `_marketingFee` along with the tax fee and liquidity fee. In function `_tokenTransfer`, the corresponding percentage of burn fee and marketing fee is deducted from the total transfer amount. Marketing fee is then transferred to `marketingWallet` without fees. On the other hand, no action is taken on burn fee, and it'll stay in the sender's wallet. For example, for a `_burnFee` of 4, only 96% of the requested transfer amount will be transferred out to the recepient or collected as fees; the remaining 4% will stay in the sender's wallet.

LowComment inconsistent with codeFixed

At the beginning of the contract, the comment describes a 4% fee, which does not match with the code. ```solidity=3 /** Website: https://qrkita.exchange # qrkita features: ⤏ 1% fee distributed to all holders every transaction ⤏ 1% fee auto added to the liquidity pool every transaction ⤏ 1% Partnerships wallet ⤏ 1% Charity Wallet */ ```

LowMinor typosFixed

There are several typos in the code and comments. 1. Event `SwapAndLiquify`: `tokensIntoLiqudity` should be `tokensIntoLiquidity`. ```solidity=724 event SwapAndLiquify( uint256 tokensSwapped, uint256 ethReceived, uint256 tokensIntoLiqudity ); ``` 2. Comment on line 876: `recieve` should be `receive` and `swaping` should be `swapping`. ```solidity=876 //to recieve ETH from uniswapV2Router when swaping ``` 3. Function on line 455: `geUnlockTime()` should be `getUnlockTime()`. ```solidity=455 function geUnlockTime() public view returns (uint256) { return _lockTime; } ``` 4. Require statement on line 851: "Account is already excluded" should be "Account is already included". ```solidity=850 function includeInReward(address account) external onlyOwner() { require(_isExcluded[account], "Account is already excluded"); ... ```

LowPossible to gain ownership after renouncing the cFixed

An owner is possible to gain ownership of the contract even if they calls function `renounceOwnership` to renounce the ownership. This can be achieved by performing the following operations: 1. Call `lock` to lock the contract. The variable `_previousOwner` is set to the current owner. 2. Call `unlock` to unlock the contract. 3. Call `renounceOwnership` to leave the contract without an owner. 4. Call `unlock` to regain ownership.

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: - `uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens()` - `uniswapV2Router.addLiquidityETH()`

Show 3 more
LowRedundant codeFixed

In function `_tokenTransfer`, the condition `!_isExcluded[sender] && !_isExcluded[recipient]` can be included in `else` . ```solidity=1067 if (_isExcluded[sender] && !_isExcluded[recipient]) { _transferFromExcluded(sender, recipient, (amount.sub(burnAmt).sub(marketingAmt))); } else if (!_isExcluded[sender] && _isExcluded[recipient]) { _transferToExcluded(sender, recipient, (amount.sub(burnAmt).sub(marketingAmt))); } else if (!_isExcluded[sender] && !_isExcluded[recipient]) { _transferStandard(sender, recipient, (amount.sub(burnAmt).sub(marketingAmt))); } else if (_isExcluded[sender] && _isExcluded[recipient]) { _transferBothExcluded(sender, recipient, (amount.sub(burnAmt).sub(marketingAmt))); } else { _transferStandard(sender, recipient, (amount.sub(burnAmt).sub(marketingAmt))); } ```

LowVariable `_rOwned[account]` Not Updated in FunctiFixed

```solidity function includeInReward(address account) external onlyOwner() { require(_isExcluded[account], "Account is already included"); for (uint256 i = 0; i < _excluded.length; i++) { if (_excluded[i] == account) { _excluded[i] = _excluded[_excluded.length - 1]; _tOwned[account] = 0; _isExcluded[account] = false; _excluded.pop(); break; } } } ``` Variable `_rOwned[account]` is not updated in the function `includeInReward()`, which will make the accounts included siphon off the tokens out of the balances of all token holders. The Rate was higher at the moment of the `excludeFromReward(account)` call, so the `_rOwned[account] / _tOwned[account]` ratio is bigger than expected for accounts included in the reward.

LowVariables can be declared as constantFixed

The following variables could be declared as `constant` since these state variables are never to be changed. A big advantage of constant variables is that reading them is significantly cheaper than reading from regular state variables since will not be stored in storage. Still, values will directly insert the values into the runtime code. - `_tTotal` - `numTokensSellToAddToLiquidity` - `_name` - `_symbol` - `_decimals`

Contracts in scope1

AddressChainSource code
0x72b6887a46043c1299d3dae707893123d47cf73dChain: BNB ChainSource code: Verified source

Part of Qrkita’s security record

Qrkita
Audits1 audit by 1 firmLast audit May 2023, by CertiK.
Critical findingsNo open critical findingsIn 1 report.
Open Qrkita’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