As of 3 Nov 2026, AIDOGE has 2 audit reports by 1 security firm on Trustblock; the latest is by CertiK, dated 10 Aug 2023. Those reports list no open critical findings.
Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| ArbDoge AI Launchpad Audit | Security firm: CertiK | Date: | Scope: Files named in the report | No open critical findings | Open · skynet.certik.com |
| ArbDoge AI | Security firm: CertiK | Date: | Scope: Files named in the report | 1 critical finding, fixed | Open · skynet.certik.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 1 |
| High | 2 | 2 | 5 |
| Medium | 0 | 0 | 1 |
| Low | 11 | 6 | 15 |
```solidity=305 function emergencyRewardWithdraw(uint256 _amount) public onlyOwner { require(_amount <= rewardToken.balanceOf(address(this)), 'DogeBonusPool: not enough token'); rewardToken.safeTransfer(address(msg.sender), _amount); } ``` The `emergencyRewardWithdraw()` function allows the contract owner to withdraw reward tokens. In the [deployed `DogeBonusPool` contract](https://arbiscan.io/address/0x5845696f6031bfd57b32e6ce2ddea19a486fa5e5#readContract), AIDOGE tokens are used as both deposit tokens and reward tokens. If the owner's account is compromised by a hacker, the hacker could potentially withdraw all user deposits using this function.
Open the reportIn 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.
Open the reportIn 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.
Open the reportIn 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.
Open the reportIn the contract `AIDoge` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and update critical state variables to damage the tokenomics. 
Open the reportThe contract `DogeBonusPool` is used for users to stake pool tokens in order to earn `rewardToken`. As of April 23, 2023 8:30:15 PM (GMT + 0), the [deployed `DogeBonusPool`](https://arbiscan.io/address/0x5845696f6031bfd57b32e6ce2ddea19a486fa5e5#readContract) allows users to stake AIDOGE tokens and earn `rewardToken` which is also AIDOGE token. The expected rewards can be calculated as the product of the pool's `RewardsPerSecond` and the total reward period, which equals 6992930980883225239092 Wei or approximately 7000 Ether. However, the actual rewards, calculated by deducting the total deposit from `DogeBonusPool`'s balance of AIDOGE token, amount to 4384909523570706133135 Wei or approximately 4400 Ether. The discrepancy between these two values indicates that a portion of the rewards (about 2600 Ether of AIDOGE) is paid from other users' deposits.
Open the reportIn 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; ... ```
Open the reportIn 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.
Open the reportIn 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.
Open the reportThe linked function returns the length of `_pairs`, but its name is mistakenly set as `getMinterLength()`.
Open the reportThe 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 {} ```
Open the reportThere should always be events emitted in the sensitive functions that are controlled by centralization roles.
Open the reportPerforming 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].
Open the reportThe 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); ```
Open the reportInside `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.
Open the reportIn 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; } ```
Open the reportReading, 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=127 totalRewards = totalRewards.add(epochReward); ```
Open the reportIn the `add()` and `set()` functions, the flag '_withUpdate' determines if all the pools will be updated. This reliance might lead to significant loss of the reward.
Open the report```solidity=125 function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) public onlyOwner { if (_withUpdate) { massUpdatePools(); } totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint); poolInfo[_pid].allocPoint = _allocPoint; } ``` The `set()` function allows the owner to update a pool's `allocPoint`, which determines the proportion of total rewards the pool receives. However, the function does not check if the pool has been added. If `_pid` is equal to or greater than the number of valid pools, an invalid pool with `_pid` may be allocated rewards, causing other pools to lose rewards.
Open the report```solidity=191 require(_amount.add(user.amount) <= maxStakingPerUser, 'DogeBonusPool: exceed max stake'); ``` The `deposit()` function in the contract is used for users to deposit tokens. `_amount` represents the tokens that the user is transferring from their wallet, and `user.amount` represents the amount of tokens a user has already deposited. The check in the code requires the sum of `_amount` and `user.amount` to be smaller or equal to `maxStakingPerUser`, which represents the maximum amount of tokens that a user can deposit. However, if the token is deflationary, the contract may receive fewer tokens than the specified `_amount`. This can lead to deposit failures that should have been successful, as the total deposit does not exceed the `maxStakingPerUser` limit.
Open the reportThe return values of the `transfer()` 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=212 backToken.transfer(gov1Wallet, amountBackTokenGov1); ``` --- ```solidity=213 backToken.transfer(gov2Wallet, amountBackTokenGov2); ``` --- ```solidity=214 backToken.transfer(address(jackpotWallet), amountBackTokenJackpot); ``` --- ```solidity=215 backToken.transfer(devWallet, amountBackTokenDev); ``` --- ```solidity=304 backToken.transfer(_msgSender(), backToken.balanceOf(address(this))); ```
Open the reportThe contract has a `startTime` state variable, which is intended to represent the start time for users to burn tokens. However, users are able to call the `burn()` function to burn tokens before the startTime has been reached and share rewards.
Open the reportThe reports name a repository or files. Open a report to see its scope.
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.
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.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="arbdoge-ai"></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