# Final Security Audit of `DEXI` token ![](https://i.imgur.com/DreWe7g.png) ## Conclusion This audit was made by [Web3Go](https://web3go.tech) Auditor: Vladimir Smelov <vsmelov.job@gmail.com>. Date: 2022-08-09 In the final contract were **NOT FOUND**: - Backdoors for investor funds withdrawal by anyone. - Bugs allow stealing money from the contract. - Any severe security problems. - Any serious problems with gas consumption. The client was acknowledged about all notes below. ## Scope #### Pre-audit - DEXI.sol (md5 hash - `4669ec9cc43e556f5901a998a60825a3`) #### Final audit - DEXI.sol https://gist.github.com/vsmelov/7d66ce139b6996c82dae8eb80efeaf09 ## Methodology 1. Blind audit. Understand the structure of the code without reading any docs. 2. Ask questions to developers. 3. Draw the scheme of cross-contracts interactions. 4. Write user stories and usage cases. 5. Run static analyzers. 6. Find problems with: - backdoors; - bugs; - math; - potential leaking of funds; - potential locking of the contract; - validate arguments and events; - others. ## Result ### Critical There are no critical in the final version of the DEXI token. ___ ### Major #### MAJOR-1. DEXI does not allow zero-amount transfers. At - contracts/DEXI.sol:721 ```solidity=721 function _transfer( address from, address to, uint256 amount ) private { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); require(amount > 0, "Transfer amount must be greater than zero"); ``` there is an incompatibility with https://eips.ethereum.org/EIPS/eip-20 amount=0 is the correct value, and some DeFi projects may not work with DEXI. It's **explicitly** stated in EIP-20, whose author is **Vitalik Buterin**, that erc-20 tokens **MUST** support `amount=0` transfers. For example, if some developer of some marketplace will rely on eip-20 Standart and will think that `IERC20(dexi).transfer(amount * fee)` will always work, even in case if `fee=0`, it will break integration with your token in case if `fee=0`. Let's check any popular erc-20 token, e.g., usdt https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7#code they all support amount=0 transfers. This is not a SECURITY ISSUE because no one may steal money. But it's a major defi-ecosystem-integration issue. ##### **Recommendation.** Accept `amount=0`. ##### **Status.** ACKNOWLEDGED Since it's the client's strong opinion not to allow zero transfers, they can leave it as it is. **This is not a security issue.** Be aware, then use the DEXI token with other DeFi applications. ##### **Client's commentary.** > We decided to move forward with certain functionality. ___ ### Warning There are no warnings in the final version of the DEXI token. ___ ### Comment. #### COMMENT-1. Variables should be constants At - contracts/DEXI.sol:405-406 ```solidity=405 uint256 private _tTotal = 50000000 * 10**uint256(_decimals); address public _burnpoolWalletAddress = address(0x000000000000000000000000000000000000dEaD); ``` The variables are never changed. ##### Recommendation. Consider the usage of constants to save gas. ##### Status. FIXED - Variables were declared as constants. ___ #### COMMENT-2. Use scientific notation for clarity At - contracts/DEXI.sol:405 ```solidity=405 uint256 private _tTotal = 50000000 * 10**uint256(_decimals); ``` "50000000" has too many zeros. ##### Recommendation. Replace it with "50 * 1e6" for better readability. ##### Status. FIXED - Scientific notations were used. ___ #### COMMENT-3. No need to initialize "previous" values At - contracts/DEXI.sol:410,413,416 ```solidity=409 uint256 public _taxFee = 3; uint256 private _previousTaxFee = _taxFee; uint256 public _burnFee = 3; uint256 private _previousBurnFee = _burnFee; uint256 public _liquidityFee = 3; uint256 private _previousLiquidityFee = _liquidityFee; ``` There is no reason to initialize previous values. ##### Recommendation. Consider removing the initialization to save gas at deployment time. ##### Status. FIXED - These variables were removed. ___ #### COMMENT-4. Unclear reason to use _maxTxAmount At - contracts/DEXI.sol:418 - contracts/DEXI.sol:724 ```solidity=724 if(from != owner() && to != owner()) require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount."); ``` It's unclear what the motivation is to limit the max transfer amount—just wasting gas. It does not change anything because someone may do a significant transfer in a row of smaller transfers. But it may induce a problem if some huge holder wants to withdraw his big share, e.g., from the DEX pool. ##### Recommendation. Remove `_maxTxAmount` restriction. ##### Status. ACKNOWLEDGED ##### Client's commentary. > We would like to keep it to restrict manipulations in a single transaction. ___ #### COMMENT-5. Use the same style of variable and getter function. - contracts/DEXI.sol:429 In the final version, it looks like this: ```solidity=437 mapping (address => mapping (address => uint256)) private _allowances; mapping (uint16 => uint256) public _yearMintedAmount; mapping (uint16 => uint256) public _yearCanMintAmount; mapping (address => bool) public _isBlacklisted; mapping (address => bool) private _isExcludedFromFee; ``` Some variables are public (but prefixed with an underscore), and others are private. ##### Recommendation. Use the same style. E.g., name public variables with no underscore prefix and private variables with underscore prefix, or make all variables public to use the default getter. ##### Status. ACKNOWLEDGED - The style remained the same. --- #### COMMENT-6. Index important event parameters - contracts/DEXI.sol:450-454 In the final contract, it looks like ```solidity=446 event IsBlackListed(address indexed user, bool indexed flag); event ExcludeFromFee(address account, bool isExcludedFromFee); event SetEnabledFlag(bool _enableFlag, TAX_TYPE _flagType); event TaxesSet(uint8 _buyTax, uint8 _sellTax, uint8 _transferTax, uint8 _burnFee); event AddNewSwapPair(address pair); ``` ##### Recommendation. Index important event parameters ##### Status. ACKNOWLEDGED - Some important event parameters are still not indexed. ___ #### COMMENT-7. The event is never used - contracts/DEXI.sol:451 - contracts/DEXI.sol:453 - contracts/DEXI.sol:454 ```solidity=451 event IncludeInReward(address account, bool isExclude); event ExcludeFromFee(address account, bool isExcludedFromFee); event IncludeInFee(address account, bool isExcludedFromFee); event TokenTranfer(address from, address to, uint256 amount, bool takeFee); ``` ##### Recommendation. Consider removing unused events. ##### Status. FIXED - Unused events were removed. ___ #### COMMENT-8. Use "external pure" declarations - contracts/DEXI.sol:486 - contracts/DEXI.sol:490 - contracts/DEXI.sol:494 ```solidity=486 function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view returns (uint8) { return _decimals; } ``` ##### Recommendation. Use `external pure` declaration for pure functions. ##### Status. FIXED - `external pure` declaration was used. ___ #### COMMENT-9. Local variable shadows external declaration There is an Ownable.owner() function, but it's being shadown by the "owner" argument: - contracts/DEXI.sol:512 - contracts/DEXI.sol:706 ##### Recommendation. Rename to _owner ##### Status. ACKNOWLEDGED ___ #### COMMENT-10. No need to use `_msgSender()` - contracts/DEXI.sol:523 - contracts/DEXI.sol:528 ... In fact "Context" base class is needed in case you change the context of the transaction execution inside the contract (e.g., in meta transactions as described in https://eips.ethereum.org/EIPS/eip-2771) You never change the code execution context, so you don't need to use `_msgSender`. It's just wasting gas. ##### Recommendation. Use msg.sender instead. ##### Status. FIXED - "Context" library usage was removed. ___ #### COMMENT-11. The owner may set `_maxTxAmount` too low At - contracts/DEXI.sol:892 ```solidity=892 function _setMaxTxAmount(uint256 maxTxAmount) external onlyOwner() { require(maxTxAmount > 0, "maxTxAmount should be greater than zero"); _maxTxAmount = maxTxAmount; emit SetMaxTxAmount(maxTxAmount); } ``` The owner can make the token impossible to use just by setting `_maxTxAmount` to some minimal value (e.g. =1). ##### Recommendation. Remove. The owner must be multisig! ##### Status. ACKNOWLEDGED