Audit · firm’s term: audit report
QuillAudits reviewed Baby Doge (BabyDoge - Deflationary Swap and Multitoken Burn P) on 20 Jun 2023: 12 findings, 0 critical; 10 marked fixed, 2 open.
Report hosted on quillaudits.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 2 |
| Medium | 0 | 0 | 1 |
| Low | 2 | 0 | 7 |
buyTokensWithERC20() uses transferFrom to transfer tokens from msg.sender to contract and then sends it to adminFeeReceiver,feeReceiver as fee and uses remaining for swapping. In the case where the token that is getting transferFrom doesn't revert on failure( e.g when the user isn't having enough balance to transfer) the code will run without reverting the transaction, Now because the user hasn’t transferred any tokens to the MultiTokenBurnPortal while sending token fees to adminFeeReceiver,feeReceiver the contract send tokens from collected fees ( in the case if contract is getting used for collecting fees) and use collected fee for swapping tokens.
ERC20 token which doesn’t revert on transfer, transferFrom (or in other important operation) can make this code vulnerable. E.g. burnTokens() uses token's transferFrom function to transfer tokens to DEAD_WALLET to burn them. it can happen that a token that is getting transferred is a token that doesn't revert on failure (e.g while not having enough balance when transferring) instead, it returns a bool value. the returned value is not getting checked in the function and it proceeds on the next line to add the amount in burnedAmount[msg.sender][token] and in portals[token].totalBurned.So in this way a user would be able to increase the amount of burned tokens that contract stores without burning the tokens. and after that, while swapping tokens the user can get a discount for the amounts that weren’t actually burned.
_checkDiscounts() fails to validate from the 2nd index. It sets prevDiscount = _discounts[0] on L589 but never reassigns it to the next one while iterating through the loop. so while checking it every time, it checks the current index's discount data (i.e discount and burnAmount) with the prevDiscount's data which was set as the 0th index of _discounts. So for the 1st index, it compares index 0's discount data but for the next i.e for the 2nd index also, it compares the 0th index's data and not the 1st one which would be previous in this case.This happens because prevDiscount is not getting updated in the loop. Example: this is the discount array: [{ discount: 1000, burnAmount: 50e18 }, { discount: 2000, burnAmount: 150e18 }, { discount: 2000, burnAmount: 300e18 }]While validating this array the _checkDiscounts() function checks 1st index with 0th and the 2nd also with 0th index and not with 1st. so it fails to identify that 1st index's discount and 2nd index's discount amount are the same.
BurnPortal struct is using uint128 for totalBought and for totalBurned, it is hard to directly predict that the amount of burn token and bought tokens won't reach the max limit of what uint128 can store (2**128-1), our recommendation would be to use uint256 for storing these values to avoid any problems in future while incrementing these values.
Readme file states that "Swap path must be [ WBNB -> BabyDoge ] for buyTokensWithBNB". The code only checks that swap path should contain two elements and the first element would be weth but doesn't contain any check for checking if the second element ( token address) is BabyDoge or not.
In buyTokensWithBNB() and buyTokensWithERC20() there are external calls for sending fees to addresses, for transferring tokens to and from the msg.sender. It can happen that tokens having hooks can give control to the external address e.g msg.sender while transferring tokens, on the other hand side while sending native tokens to addresses e.g. as a fee. Once they receive a callback, they can then try to reenter for calling buyTokensWithBNB(), buyTokensWithERC20() functions.In some cases, msg.sender can make a reentrant call and can use the issue discussed in A.2 and can use collected fees. This issue gets fixed after using SafeERC20 wrapper, but we recommend using reentrancy guard for both buyTokensWithBNB(), buyTokensWithERC20() functions to avoid any other issues related to reentrancy because of having external calls.
Contracts are using floating pragma (pragma solidity ^0.8.0), Contracts should be deployed with the same compiler version and flags that they have been tested thoroughly. Using floating pragma does not ensure that the contracts will be deployed with the same version. It is possible that the most recent compiler version gets selected while deploying a contract which has higher chance of having bugs in it.
Contracts are using floating pragma (pragma solidity ^0.8.0), Contracts should be deployed with the same compiler version and flags that they have been tested thoroughly. Using floating pragma does not ensure that the contracts will be deployed with the same version. It is possible that the most recent compiler version gets selected while deploying a contract which has higher chances of having bugs in it.
Some imported interfaces (IBabyDogeFactory and IBabyDogePair) are not getting used and can be removed.
Some imported imports (SafeOwnable and IFactory) are not getting used and can be removed.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (2)
350 projects reviewed · 459 reports · latest Apr 2025
See QuillAudits’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