ArbDoge AI Launchpad Audit

CertiKFiles named in the report

CertiK reviewed AIDOGE (ArbDoge AI Launchpad Audit) on 10 Aug 2023: 21 findings, 0 critical; 13 marked fixed, 8 acknowledged.

No open critical findings
Open the reportOpen AIDOGE’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings21

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

SeverityOpenAcknowledgedFixed
Critical000
High023
Medium001
Low069
HighApproval to incorrect address and Missing ApprovaFixed

In the `_doAddLp()` function, before adding liquidity into the pool, the contract set approvals of token and `WETH` for the spender. However, the contract adds liquidity via the `INonfungiblePositionManager` contract and incorrectly sets the `swapRouter` as the `spender`, which will cause the transaction reverted since the approval should be for the `nonfungiblePositionManager` to run function `mint()`. Also, the contract not set allowance with `AIERC20` for `nonfungiblePositionManager` as well.

HighIncorrect swap and add liquidity functionalityFixed

In the `_doAddLp()`, the contract uses half token to swap for `WETH`, then adds liquidity into the pair. However, this functionality will not work due to two errors: - Incorrect parameter: passing of `address(this)` as `to` causes an error "UniswapV2: INVALID_TO" - Missing approval: adding liquidity requires approving corresponding amount first. ```solidity=211 _approve(address(this), address(swapRouter), tokenAmount); uint256 ethAmountBefore = WETH.balanceOf(address(this)); try swapRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(half, 0, pathEth,address(this),block.timestamp){ uint256 ethAmount = WETH.balanceOf(address(this)) - ethAmountBefore; try swapRouter.addLiquidity(address(this), address(WETH), half, ethAmount, 0, 0, address(0), block.timestamp) { emit AddLiquidity(tokenAmount, ethAmount, block.timestamp); } catch {} } catch {} ``` ### Incorrect parameter The use of `address(this)` will fail and lead to the error `UniswapV2: INVALID_TO` because according to the `UniswapV2Pair` contract, the `to` address is not allowed to be one of the addresses in the `path` parameter included in function `swapExactTokensForTokensSupportingFeeOnTransferTokens()`. ```solidity require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO'); ``` ### Missing approval According to the `UniswapV2Router02` contract, the running of the function `addLiquidity()` will execute the `safeTransferFrom()` to send funds from the function caller to the `pair` address, therefore sufficient approvals for both tokens will be required to successfully perform this operation. ```solidity TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); ``` **Note:** This finding pertains to the updated code provided by the team on 07/28/2023.

HighMint to the zero addressFixed

In the `_doAddLp()` function, the contract swaps half of current tokens for `WETH` first, then adds liquidity into the pool via the `INonfungiblePositionManager` contract. However, it is noticed that when adding liquidity into the pool, the `recipient` is set to the **zero-address**, which means the newly minted NFT position token is transferred to the zero address. In the `NonfungiblePositionManager` contract, there is a check for token ID when calling `decreaseLiquidity()`, `collect()` and `burn()` functions. Minting to the zero address will cause the check to fail when invoking these functions.

MediumIncorrect calculation of ETH amountFixed

In the `_doAddLp()` function, the `ethAmountBefore` is the `WETH` token balance of current contract. However, when adding liquidity into the trade pair, the `ethAmount` is calculated by subtracting the `ethAmountBefore` from the `address(this).balance`. The `WETH` is an ERC20 token, and `address(this).balance` is the native token balance. ```solidity=222 uint256 ethAmountBefore = WETH.balanceOf(address(this)); try swapRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(half, 0, pathEth, address(this),block.timestamp) uint256 ethAmount = address(this).balance - ethAmountBefore; ... ```

Low`mint` function requires initialized poolFixed

In the `_doAddLp()` function, the contract swaps half of the current tokens for `WETH` first and then adds liquidity to the pool via the `INonfungiblePositionManager` contract. However, the `NonfungiblePositionManager` contract requires the pool to be created and initialized before creating any position. The current implementation does not comply with these requirements.

LowDiscussion on unrestricted function `doSwapBack()Fixed

In the previous version, the `doSwapBack()` function could only be called by the `owner` role. However, in the current version, it has been declared as a public and unrestricted function. It is important to note that this function not only performs the swap, but also carries out actions such as burning tokens and distributing tokens to the `bonusWallet`, `tradingPool.vault()`, and `teamWallet`. since this function allows any party to trigger the swap back operation, this will make the contract a potential target for exploits such as sandwich attacks. We would like to confirm if current implementation aligns with the intended design.

LowFunction Name TypoFixed

The linked function returns the length of `_pairs`, but its name is mistakenly set as `getMinterLength()`.

LowLocked Blockchain Native TokensFixed

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=309 receive() external payable {} ```

LowMissing Emit EventsFixed

There should always be events emitted in the sensitive functions that are controlled by centralization roles.

LowPotential Divide by ZeroFixed

Performing division by zero would raise an error and revert the transaction. ```solidity=165 uint256 amountBurn = taxAmount * burnFee / totalFee; ``` The expression `taxAmount * burnFee / totalFee` may divide by zero. Its divisor has has estimated interval [0, 1500]. --- ```solidity=166 uint256 amountLp = taxAmount * liquidityFee / totalFee; ``` The expression `taxAmount * liquidityFee / totalFee` may divide by zero. Its divisor has has estimated interval [0, 1500]. --- ```solidity=167 uint256 amountBouns = taxAmount * bounsFee / totalFee; ``` The expression `taxAmount * bounsFee / totalFee` may divide by zero. Its divisor has has estimated interval [0, 1500]. --- ```solidity=168 uint256 amountTrade = taxAmount * tradingPoolFee / totalFee; ``` The expression `taxAmount * tradingPoolFee / totalFee` may divide by zero. Its divisor has has estimated interval [0, 1500]. --- ```solidity=169 uint256 amountTeam = taxAmount * teamFee / totalFee; ``` The expression `taxAmount * teamFee / totalFee` may divide by zero. Its divisor has has estimated interval [0, 1500].

Show 3 more
LowUnused Return ValueFixed

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=214 WETH.approve(address(swapRouter), outAmount); ``` --- ```solidity=230 nonfungiblePositionManager.mint(lpParams); ```

LowUseless allowance during `swapBack`Fixed

Inside `swapBack()` function, the contract will approve full tax amount for the `swapRouter` contract. ```solidity=170 _approve(address(this), address(swapRouter), taxAmount); ``` However, during the swap, there is another call to `_approve()` function. The previous approval will be overwritten.

LowUseless ComparisonFixed

In the `_doTransfer()` function, it is checked that `taxType` is not equal to `TaxType.Transfer` if `taxType == TaxType.Trade` is known to be true. Therefore, the linked condition is always true and the comparison is unless. ```solidity=128 if (taxType == TaxType.Trade) { ... } else if (taxType != TaxType.Transfer) { shouldTakeFee = false; } ```

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (12)

  • interfaces/IUniswapV2Router02.sol
  • interfaces/IAIERC20BounsPool.sol
  • interfaces/ISwapRouterV3.sol
  • interfaces/IUniswapV3Pool.sol
  • interfaces/IWETH.sol
  • interfaces/INonfungiblePositionManager.sol
  • interfaces/IUniswapV3Factory.sol
  • interfaces/IUniSwapV2Pair.sol
  • interfaces/IAIERC20TradingPool.sol
  • interfaces/IUniswapV2Factory.sol
  • interfaces/IUniswapV2Router01.sol
  • launchpad/AIERC20.sol

Part of AIDOGE’s security record

AIDOGE
Audits2 audits by 1 firmLast audit Aug 2023, by CertiK.
Critical findingsNo open critical findingsAcross the 2 reports, 1 critical finding was reported. It is marked fixed by the firm that reported it.
Open AIDOGE’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