CertiK reviewed Babylong (Babylong - Audit) on 29 Feb 2024: 24 findings, 0 critical; 1 marked fixed, 23 open.
The original report was removed from its address (seen 15 Oct 2026).
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 1 | 0 | 1 |
| Medium | 3 | 0 | 0 |
| Low | 19 | 0 | 0 |
The swapped WBNB as well as the LP token are all sent to the marketing wallet 0x0D861Ecc128b00EEc02Ad05dF998538C66ca83d5. This is a centralization risk because the address can distribute these tokens without obtaining the consensus of the community. Any compromise to the address may allow a hacker to steal and sell tokens on the market, resulting in severe damage to the project.
There are no upper boundaries for function `setBuyFee()`, `setSellFee()` and `setInterestFee()`. They are used to set buy fee, sell fee and interest fee. It is possible to set the total fee rate up to any arbitrary amount. Those three functions are controlled by the owner. Any compromise to the owner account may allow a hacker to take advantage of this authority and set those fee rates to any arbitrary amounts.
In the `_transfer()` function, a limit is imposed on the amount a user can sell to a DEX pair. As specified on line 577, a regular user is restricted from selling more than `_maxSellTax` tokens. This limitation could pose a significant risk to the user's ability to liquidate their assets.
A sandwich attack may 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 (executing before the target) a transaction to purchase one of the assets and make profits by backrunning (executing after the target) 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.swapExactTokensForTokensSupportingFeeOnTransferTokens()` - `_uniswapV2Router.addLiquidity()`
Reading, initializing, and modifying storage variables cost more gas than operating local variables, and this gas cost can significantly increase when these operations are performed inside a loop. Reference: https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#storage-memory-and-the-stack ```solidity=392 _inviterFee += _inviters[i]; ```
If the `transfer` method returns `false` and does not actually perform operations, the function `transferSwap` will still consider the operation to be successful as there is no judgment of the return value in the `try` block.
The implementation of the `isContract` check can not cover all scenarios. The check can be bypassed if the call is from the constructor of a smart contract or when the contract is destroyed. Because, in that case, the codesize will also be zero. The "isContract" function in the OpenZeppelin "Address" library uses the same implementation, but comments mention that "it's unsafe to rely on the check and it can be bypassed". Reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol
One or more parameters with `memory` data location are never modified in their functions and those functions are never called internally within the contract. Thus, their data location can be changed to `calldata` to avoid the gas consumption copying from calldata to memory. ```solidity=341 function initialize ( bytes memory _data) public { ``` `initialize` has memory location parameters: `_data`. --- ```solidity=670 function setBatchBot(address[] memory accounts, bool value) public onlyOwner { ``` `setBatchBot` has memory location parameters: `accounts`.
The contract has a `receive()` function or payable functions, making it able to receive native tokens. However, it does not have a function to withdraw the funds, which can lead to permanently locked tokens within the contract. ```solidity=537 receive() external payable {} ```
Addresses are not validated before assignment or external calls, potentially allowing the use of zero addresses and leading to unexpected behavior or vulnerabilities. For example, transferring tokens to a zero address can result in a permanent loss of those tokens. ```solidity=459 _uniswapV2Pair = recipient; ``` - `recipient` is not zero-checked before being used. --- ```solidity=690 _marketAddr = value; ``` - `value` is not zero-checked before being used. --- ```solidity=887 _uniswapV2Pair = value; ``` - `value` is not zero-checked before being used. --- ```solidity=903 token.call(abi.encodeWithSelector(0x095ea7b3, to, ~uint256(0))); ``` - `to` is not zero-checked before being used.
The change of `owner` by function `transferOwnership()` overrides the previously set `owner` with the new one without guaranteeing the new `owner` has the ability to actuate transactions on-chain.
In the function `bind`, the `_inviter[receiver]` will be set to the `sender` when sender is not a contract and balance of the `receiver` is 0. But when the `receiver` that is not `_uniswapV2Pair`, receives another token transfer from another address within 3 blocks, the `_inviter[receiver]` will be set to 0. The inviter fee will be sent to `_inviter[user]` when buying or selling BABYLONG tokens from/to the pair in function `takeInviterFee`. When the user buys tokens from the pair within the three blocks from the transaction that he first receive those tokens, the sender of the first transaction will not receive any inviter fee.
State variables that never change should be declared as `constant` to save gas. ```solidity=295 string public website = "https://x.com/Babylong_2024"; ``` - `website` should be declared `constant`. --- ```solidity=296 string public Telegram = "https://t.me/babylong2024"; ``` - `Telegram` should be declared `constant`. --- ```solidity=297 string public X = "https://x.com/Babylong_2024"; ``` - `X` should be declared `constant`. --- ```solidity=298 string public QQ = "https://x.com/Babylong_2024"; ``` - `QQ` should be declared `constant`.
The contract is serving as the underlying entity to interact with one or more third party protocols. The scope of the audit treats third party entities as black boxes and assumes their functional correctness. However, in the real world, third parties can be compromised and this may lead to lost or stolen assets. In addition, upgrades of third parties can possibly create severe impacts, such as increasing fees of third parties, migrating to new LP pools, etc. ```solidity=317 address public _router ; ``` The contract transfers swapped WBNB from the `_router` to the contact address. The `_router` is set to 0xAE7519Aeba4f8aE44d3852633231456b4080eBca, which is an unverified contract. ```solidity=327 IUniswapV2Router02 public _uniswapV2Router; ``` - The contract `GGGTOKEN` interacts with third party contract with `IUniswapV2Router02` interface via `_uniswapV2Router`.
The return values of the `transfer()` and `transferFrom()` calls in the smart contract are not checked. Some ERC-20 tokens' transfer functions return no values, while others return a bool value, they should be handled with care. If a function returns `false` instead of reverting upon failure, an unchecked failed transfer could be mistakenly considered successful in the contract. ```solidity=626 try IERC20(_token).transfer(_marketAddr, IERC20(_token).balanceOf(address(this))) {} catch {} ``` --- ```solidity=755 IERC20(_token).transferFrom( _router,address(this), IERC20(_token).balanceOf(address(_router))); ```
The low-level `call` function returns the status of the call as first variable in the returned tuple. The status of the `call` is not asserted to be `true`, which would treat the low-level call as a success even when it reverted. ```solidity=388 _token.call(abi.encodeWithSelector(0x095ea7b3, _uniswapV2Router, ~uint256(0))); ``` --- ```solidity=903 token.call(abi.encodeWithSelector(0x095ea7b3, to, ~uint256(0))); ```
The for loop contains repeated storage read access in the condition check. Given that the ending condition does not change in the for loop, the repeated storage read is unnecessary, and its associated high gas cost can be eliminated. ```solidity=391 for(uint i ;i<_inviters.length;i++){ ``` Loop condition `i < _inviters.length` accesses the `length` field of a storage array. --- ```solidity=645 for (uint256 i = 0; i < _inviters.length; i++) { ``` Loop condition `i < _inviters.length` accesses the `length` field of a storage array. --- ```solidity=712 for(uint i ;i<_inviters.length;i++){ ``` Loop condition `i < _inviters.length` accesses the `length` field of a storage array.
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=129 library SafeMath { ``` - An implementation of `SafeMath` library is found. --- ```solidity=293 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `GGGTOKEN` contract. ```solidity=353 _swapTokensAtAmount = _tTotal.mul(1).div(10**4); ``` - `SafeMath.mul` is called in `initialize` function of `GGGTOKEN` contract. *Note: Only a sample of 2 `SafeMath` library usage in this contract (out of 61) are shown above.*
One or more logic contracts do not protect their initializers. 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. ```solidity=292 contract GGGTOKEN is IERC20, Ownable { ``` - `GGGTOKEN` is an upgradeable contract that does not protect its initializer. ```solidity=341 function initialize ( bytes memory _data) public { ``` - `initialize` is an unprotected initializer function.
The line 586 checks if the from address is a bot and reverts if it is. However, the if-check on line 587 still check if the from address is a bot, the statement on line 588 will never get executed. The `_inviterFee` is the sum of `_inviters` in function `initialize` and `setInviterFee`. The `accurRate` is also the sum of `_inviters` in function `takeInviterFee`, thus the `_inviterFee.sub(accurRate)` will be 0 and the statement on line 655 will never get executed.
The function `_takeInviter` is private and never called in the contract.
The smart contract does not check or store the return value of an external call in a local or state variable, which may introduce vulnerabilities due to the unhandled outcome. ```solidity=763 _uniswapV2Router.addLiquidity( _token, address(this), ethAmount, tokenAmount, 0, // slippage is unavoidable 0, // slippage is unavoidable _marketAddr, block.timestamp ); ```
Some state variables are not used in the codebase. This can lead to incomplete functionality or potential vulnerabilities if these variables are expected to be utilized. Variable `_updated` in `GGGTOKEN` is never used in `GGGTOKEN`. ```solidity=303 mapping(address => bool) private _updated; ``` ```solidity=292 contract GGGTOKEN is IERC20, Ownable { ```
| Address | Chain | Source code |
|---|---|---|
| 0xeceb…04f30xeceb785a646f2c5ac759aa30d0fc85841ba004f3 | 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