Kochi Ken security record

BNB Chainkochiken.com

As of 3 Nov 2026, Kochi Ken has 1 audit report on Trustblock, by CertiK, dated 3 Mar 2023. That report lists no open critical findings.

Critical findings
No open critical findings
In that report, 2 critical findings were reported. Each is marked fixed by the firm that reported it. See the findings
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.

Audits1

Newest first

AuditSecurity firmDateScopeCritical findingsReport
KochikenSecurity firm: CertiKDate: Scope: Files named in the report2 critical findings, fixedOpen · skynet.certik.com

Findings19

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

SeverityOpenAcknowledgedFixed
Critical002
High401
Medium003
Low009
CriticalIncorrect calculation of tokens to be claimed inKochiken · CertiK · 3 Mar 2023Fixed

In the `KochiInvest.sol` contract, a certain party can create a launchpad to sell their tokens. Users can buy this token via the `buy` function and claim the bought tokens via the `claim()` function. However, when it is a fair launch, in the `claim()` function, the value of tokens that can be claimed is miscalculated due to the misuse of "softcap". Thus, users will always get the incorrect amount of tokens. In the `claim()` function, the `require` statement in L217 checks if the soft cap has been reached. The soft cap is the minimum amount of tokens the launch pad owner expects to raise. ```solidity=217 require(presaleMetadata[id][EPresaleMetadata.total_invested] >= presales[id].soft_cap, "ERROR: the softcap has not been reached"); ``` However, the formula in L221 which calculate the amount of tokens that a user can claim ```solidity=221 if (presales[id].presale_type == EPresaleType.fairlaunch) tokens = SafeMath.div(SafeMath.mul(presales[id].soft_cap, invested), presaleMetadata[id][EPresaleMetadata.total_invested]); // softcap * (invested / total invested) ``` This calculation is incorrect since it uses `softcap` as the multiplier. The `softcap` value is the amount of tokens **users paid** for a launch pad instead of the amount of tokens that **should be distributed to users**(`i.e., `presales[id].total_tokens`). **Example:**\ Suppose there is a launch pad for 100 `A_Token` where users can buy `A_Token` tokens with ETH and the softcap is 1000 ETH 1. Alice calls the `buy()` function to invest 100 ETH to buy `A_Token`. 2. Bob calls the `buy()` function to invest 900 ETH to buy `A_token`. 3. The soft cap is reached (i.e., in total raised 1000 ETH) and 100 `A_Token` was sold. 4. Alice called `claim()` to claim his `A_Token` token. Since the calculation in L221 uses the `softcap` amount, Alice tries to get 1000 * (1000 / 1900) = 526.3 `A_Token` tokens but failed since there are only 100 `A_Token` tokens.

Open the report
CriticalTokens can be excessively claimedKochiken · CertiK · 3 Mar 2023Fixed

If a token has referral tokens to distribute, users can designate an address as a referrer. The referrer will earn referral tokens based on the following calculation: ```solidity=230 if (userMetadata[id][_msgSender()][EUserMetadata.referrals] > 0) tokens += SafeMath.div(SafeMath.mul(presales[id].referral_tokens, userMetadata[id][_msgSender()][EUserMetadata.referrals]), presaleMetadata[id][EPresaleMetadata.total_referrals]); ``` This formula is written in simpler terms in the comment on line 228: ```solidity=228 // referral forumla = (total_referrals_tokens * user_number_of_referrals / total_number_of_referrals) ``` To designate an address as a referrer, users can call the `setReferrer()` function. Each address can only designate one address as a referrer but an address can have multiple referrals. The referral counts are managed according to the following code: ```solidity=360 bool replace = userReferrer[id][_msgSender()] == address(0); if (replace) { // increment the presale total and the referrer's total presaleMetadata[id][EPresaleMetadata.total_referrals]++; userMetadata[id][referrer][EUserMetadata.referrals]++; } // referrer is already set else { // decrement the old referrer, and increment the new one userMetadata[id][userReferrer[id][_msgSender()]][EUserMetadata.referrals]--; userMetadata[id][referrer][EUserMetadata.referrals]++; } ``` If the referrer can be set after claiming begins, the following scenario can occur: 1. total_referrals_tokens is 200 and Alice is a referrer; 2. Alice claims referral tokens equal to 200 * 1 / 1 = 200 tokens; 3. Bob is set as a referrer and total referrals increase to 2; 4. Bob claims referral tokens equal to 200 * 1 / 2 = 100 tokens; 5. Total of 300 referral tokens are claimed despite only 200 should have been claimed. Scenario 2: 1. total_referrals_tokens is 200 and Alice and Bob are referrers; 2. Alice claims referral tokens equal to 200 * 1 / 2 = 100 tokens; 3. Alice's referee changes referrer from Alice to Bob; 4. Bob's referral increases to 2 but total referral does not increase; 5. Bob claims referral tokens equal to 200 * 2 / 2 = 200 tokens; 6. Total of 300 referral tokens are claimed despite only 200 should have been claimed. The above scenario 1 exists for the calculation in Line 221 if users can buy tokens after claiming begins. **[CertiK, 12/08/2022]** *The below description is based on the new version contracts on 12/08/2022.* As it is mentioned above scenario 1 still exists for the calculation of `tokens` in the `claim()` function when the `presale_type` is `fairlaunch`. Recommend adding a check to restrict buying after claiming begins for the `presale_type` is `fairlaunch` in the private codebase.

Open the report
HighThe Potential Denial-of-service attack on `sendEtKochiken · CertiK · 3 Mar 2023Fixed

In `KochiBulkSender.sol`, the `sendETH()` function distributes/airdrops all the received ETH to the recipient addresses. In L63, the `require` statement ensures all the ETH in the contract is sent to the recipient. ```solidity=46 function sendEth(address[] memory _recipients, uint256[] memory _amounts) external payable override whenNotPaused nonReentrant { require(_recipients.length == _amounts.length, "KochiAirdropper: Invalid input"); uint256 sum = 0; for (uint256 i = 0; i < _amounts.length; i++) { sum += _amounts[i]; } require(msg.value == sum, "KochiAirdropper: Insufficient value sent"); for (uint256 i = 0; i < _recipients.length; i++) { bool ok; (ok, ) = _recipients[i].call{value: _amounts[i]}(""); require(ok, "KochiAirdropper: Failed to send value to recipient"); } // contract has no receive function, so it will not receive any ETH. require(address(this).balance == 0, "KochiAirdropper: Invalid final balance, something went wrong."); } ``` However, ETH can be forcibly sent to an address using the `selfdestruct` method. Since the function requires the balance of the contract to equal zero, if Ether is forcibly sent to this contract, the function will always revert. In this case, the contract will suffer a Denial-of-service situation where the contract can never use `sendEth()` to airdrop ETHs. Exploit scenario: 1. The attacker deploys the following contract ```solidity= import "./CBulksender.sol"; contract Attack { KochiBulkSender airdrop_contract; constructor(KochiBulkSender _airdrop_contract) { airdrop_contract = KochiBulkSender(_airdrop_contract); } function attack() public payable { address payable addr = payable(address(airdrop_contract)); selfdestruct(addr); } } ``` 2. The attacker call the `attack()` function with 1 WEI. 3. The `selfdestruct()` function will force to send 1 WEI to the victim airdrop contract, which is `KochiBulkSender` contract. 4. Since the balance of the `KochiBulkSender` contract will never be zero, the `sendEth()` will always revert.

Open the report
MediumIncorrect `lpAmountLocked` mapping updateKochiken · CertiK · 3 Mar 2023Fixed

In the contract`CKochiLock.sol`, `lpAmountLocked[]` is used to store the total amount of tokens locked in the corresponding Pair. `lpUnlock()` is used to retrieve locked LP tokens, so the amount of locked tokens in this LP token should be decreased by corresponding data stored in `lpUserLocks[_msgSender()][i]`, which are `metadata.amount0` and `metadata.amount1`. However, in the following code snippets, the `lpAmountLocked` mapping is incorrectly updated: ```solidity=239 if (metadata.deadline < block.timestamp && metadata.liquidity > 0 && metadata.lp_pair == pair) { lpAmountLocked[metadata.token0] -= lpAmountLocked[metadata.token0] - metadata.amount0; lpAmountLocked[metadata.token1] -= lpAmountLocked[metadata.token1] - metadata.amount1; liquidity += metadata.liquidity; ``` Therefore, it could lead to a display error when acquiring the value of `lpAmountLocked`.

Open the report
MediumRemaining `token0` Or `token1` Can Not Be WithdraKochiken · CertiK · 3 Mar 2023Fixed

If a pair exists, it's possible that not all `token0` or `token1` are added into pair as liquidity. The actual amounts of `token0` and `token1` can be computed by `IUniswapV2Router02(DEXs[dex].router).quote()`. Therefore, there could be some `token0` or `token1` remaining in `CKochiLock`. Plus, there is no extra operation or function to handle these remaining tokens. Only the remaining LP tokens will be sent to the beneficiary at the end of `lpLock()` and `lpLockETH()`.

Open the report
MediumWrong state assigned to the botsKochiken · CertiK · 3 Mar 2023Fixed

The `CKochi.sol` contract tries to implement a feature to detect the bots, who transfer tokens in 10 blocks from the `startingBlock`. However, the implementation of it assigns the wrong value, `false`, to the potential bot, `bots[from]`, as shown below: ```solidity=83 if (block.number < botLimit + startingBlock) { bots[from] = false; } ``` It is known that the default value of `bots[from]` is false, thus, its value should be `true` if it is detected as a bot, to apply a different tax for the bots.

Open the report
LowAdd a token recover functionKochiken · CertiK · 3 Mar 2023Fixed

`KOCHI` tokens could be left in the contract after the `_addLiquidity()` function, thus, consider adding a recover function to withdraw the potentially locked `Kochi` token.

Open the report
LowApproving With Max AllowanceKochiken · CertiK · 3 Mar 2023Fixed

The check used in the function `createLaunchpad()` checks whether the user has approved all his allowance to the contract. The function `createLaunchpad()` is used to create a presale for the given parameters. The amount of the `user_token` transferred from the user is calculated by the given parameters. In general, it may be less than the `totalsupply` and only need to approve the allowance for the `required_amount`.

Open the report
LowConditions for determining whether it is a buyingKochiken · CertiK · 3 Mar 2023Fixed

The `CKochi.sol` contract uses the `pair` and `router` to decide whether the transaction is a buying transaction, the condition will work well for only one DEX, what if the `Kochi` is listed in another DEX, if so, the condition fails to detect the buying transaction on another DEX since the `pair` and `router` of another DEX is different.

Open the report
LowIncompatibility With Deflationary TokensKochiken · CertiK · 3 Mar 2023Fixed

When transferring standard ERC20 deflationary tokens, the input amount may not be equal to the received amount due to the charged transaction fee. For example, if a user stakes 100 deflationary tokens (with a 10% transaction fee) to create a launchpad, only 90 tokens actually arrive in the contract. However, the total amount of tokens to be presaled is still 100 tokens, which may cause misbehaviors of the contract and lead to unexpected revert if there are no enough tokens to transfer. **[CertiK, 12/08/2022]** *The below description is based on the new version contracts on 12/08/2022.* The below `require` will revert if Bob tries to create a launch pad after the Alice'creation of the launch pad: ```solidity=145 require( IERC20(parameters.user_token).balanceOf(address(this)) == required_amount, "ERROR: Looks like your token may be deflationary, taxed, or otherwise not compatible with this contract. Please whitelist your token with us and try again." // CKI-03 ); ``` Example: - Alice creates a launch pad by calling the `createLaunchpad` with `required_amount` 100, then the contract's balance is 100, and the `require` check will pass for a normal ERC-20 token. - Bob tries to create a launch pad by calling the `createLaunchpad` with `required_amount` 200, then the contract's balance is 300(100 + 200) instead of 200, and the `require` check will revert.

Open the report
Show 5 more
LowLack of check on the relation of `factory` and `rKochiken · CertiK · 3 Mar 2023Fixed

The `_addDEX()` will add a `factory` and a `router` as a pair in the `CKochiLock` contract, without checking whether they have a real pair relationship, i.e., lack of the below check: ```solidity require(IUniswapV2Router02(router).factory() == factory,"the factory and the router are not a pair"); ``` On the other hand, for the Uniswap V2, the router has a public `factory` state variable. [See here](https://github.com/Uniswap/v2-periphery/blob/0335e8f7e1bd1e8d8329fd300aea2ef2f36dd19f/contracts/UniswapV2Router02.sol#L15).

Open the report
LowPotential Sandwich AttacksKochiken · CertiK · 3 Mar 2023Fixed

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: - `router.swapExactTokensForETHSupportingFeeOnTransferTokens(amount, 0, path0, address(this), block.timestamp);` - `router.swapExactETHForTokens{value: address(this).balance}(0, path1, address(this), block.timestamp + 60);` - `_addLiquidity(uint256 tokenAmount, uint256 baseAmount)`

Open the report
LowUnnecessary Use of SafeMathKochiken · CertiK · 3 Mar 2023Fixed

The `SafeMath` library is used unnecessarily. With Solidity compiler versions 0.8.0 or newer, arithmetic operations will automatically revert in case of integer overflow or underflow. ```solidity=165 uint256 tokens = SafeMath.mul(amount, conversion); ``` - `SafeMath.mul` is called in `buy` function of `KochiInvest` contract. *Note: Only a sample of 1 `SafeMath` library usage in this contract (out of 6) are shown above.*

Open the report
LowVerification might be bypassedKochiken · CertiK · 3 Mar 2023Fixed

The `verify` modifier ensures the input data are signed by a designated address. ```solidity=47 modifier verify(IKochiInvest.SVerify memory verification) { require(getMessageHash(verification.encoded_message) == verification.message_hash, "The message hash doesn't match the original!"); bytes32 ethSignedMessageHash = getEthSignedMessageHash(verification.message_hash); address recoveredSigner = recoverSigner(ethSignedMessageHash, verification.signature); require(recoveredSigner == signer, "Invalid signature!"); require(!usedSignatures[verification.signature], "Signature already used!"); _; usedSignatures[verification.signature] = true; } } ``` However, since the function doesn't check if the recovered address isn't zero address, if the signer address is mistakenly marked as address(0), the attacker may bypass the verification by using an unintended v value.

Open the report
LowWrong values in the EventKochiken · CertiK · 3 Mar 2023Fixed

The `LockedLiquidity` event emitted with wrong parameters in the `_setMetadataAndGetRemainingLiquidity()` function when the `lock_per_mille == 0`. In the `else` branch, that means no tokens to be locked, the parameters passed to the `LockedLiquidity` event should be zero for parameters `amount0`, `amount1`, and `locked_liquidity` but not, as shown below: ```solidity event LockedLiquidity(address beneficiary, address pair, address token0, address token1, uint256 amount0, uint256 amount1, uint256 locked_liquidity, uint256 deadline); if (lock_per_mille != 0) { ... } else { emit LockedLiquidity(beneficiary, pair, token0, token1, amount0, amount1, liquidity, deadline); return liquidity; } ```

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="kochi-ken"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

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