Smart Contract Audit Report
Phenix Finance is releasing a new ERC20 token with an elastic supply and automatic LP adds.
For this audit, we reviewed the PhenixTokenVesting contract at commit 21a4f5c02dfa5293e6e459d44ed010c601dd902d and the PhenixFinance contract at commit 71e41633652b85a6298f21715e58656c693be4b6 on the team's GitHub repository.
Please ensure trust in the team prior to investing as they have some control in the ecosystem.
Date: March 14th, 2022.
Updated: September 21st, 2022 to reflect the updated PhenixFinance contract on the team's GitHub repository.
Finding #1 - PhenixFinance - High (Resolved)Description: The LP pair sync() function is not called when a rebase occurs.
Risk/Impact: Malicious users will be able to call the skim() function to steal excess tokens from the liquidity pool after rebases occur.
Recommendation: The team should include a call to the sync() function within the _rebase() function to ensure that the LP pool is synched during each rebase.
Resolution: The team has removed the auto-rebase functionality from the contract.
Finding #2 - PhenixTokenVesting - High (Resolved)Description: The increaseTimeLock() function allows the unlockTimestamp variable to overflow.
Risk/Impact: The team is able to bypass the unlock time by overflowing the unlockTimestamp.
Recommendation: The addition performed in the increaseTimelock() function should use SafeMath.
Resolution: The team has implemented the above recommendation.
Finding #3 - PhenixTokenVesting - Low (Resolved)Description: The swapAndBurnTokens() function is open to a potential front running attack.
Risk/Impact: A malicious user may use the swapAndBurnTokens() function to create an arbitrage opportunity within the liquidity pool.
Recommendation: The buybackAllocation variable should remain fairly small so that the swapAndBurnTokens() function does not have a significant impact on pricing of the liquidity pools. Additionally, the function should be restricted to only authorized addresses, so that malicious users may not call the function at will.
Resolution: The team has restricted the swapAndBurnTokens() function to only authorized addresses.
Finding #4 - PhenixFinance - Informational (Resolved)Description: Ownership is transferred to the deployer in the constructor.
Risk/Impact: This is unnecessary and incurs additional gas cost as the deployer is given ownership by default.
Recommendation: Remove the _transferOwnership() call within the constructor.
Finding #5 - PhenixFinance - Informational (Resolved)Description: The internal _updateAutoRebaseState() function has the onlyOwner modifier.
Risk/Impact: This is unnecessary and incurs additional gas cost as the function can only be called from the setRebase() function, which already has the onlyOwner modifier.
Recommendation: Remove the onlyOwner modifier from the _updateAutoRebase() function.
- The contracts utilize ReentrancyGuard to prevent against reentrancy attacks in applicable functions.
- The contracts utilize SafeMath to prevent possible overflows/underflows.
- The initial supply of the token is set to 1 billion $PHNX.
- The maximum allowed supply of $PHNX is 340,282,366,920,938,463,463,374,607,431,768,211,455 tokens.
- No mint or burn functions are present, though the circulating supply can be reduced by sending tokens to the 0x..dead address.
- There was no token allocation for our team to analyze as the contract has yet to be deployed to the mainnet.
- The initial distribution period of the contract must be manually disabled by the owner in order for all trading to take place on the platform. Only users that have been excluded by the owner can transfer tokens while the initial distribution period is enabled.
- There is a Liquidity fee and Phenix Vault fee on all transfers via an approved DEX where neither the sender nor the recipient is excluded from fees.
- There is an additional Sell fee added when transferring tokens to any Taxable address set by the team.
- The fees charged during transfers are stored in the contract address. The tokens are swapped for CRO for the purpose of funding the liquidity pool when the following conditions are met:
- The automatic liquidity add functionality is enabled by the team.
- The threshold number of tokens in the contract address has been reached.
- The contract is not currently performing an automatic liquidity add.
- The caller has not been added to the team's Taxable address list.
- A liquidity-add is funded by selling half of the tokens collected as liquidity fees, pairing the received CRO with the token, and adding it as liquidity to the CRO pair.
- The LP tokens received through this process are sent to the Liquidity address set by the team. We recommend the team lock the newly acquired LP tokens.
- Any remaining CRO in the contract is sent to the team's Phenix Fund Reserve address.
- Authorized rebase addresses can initiate a manual rebase at any time.
- During a rebase, tokens are automatically added to the total supply. The newly added tokens are distributed proportionally amongst holders in a frictionless manner.
- The number of tokens added to the total supply is dependent on the amount of time that has passed since the previous rebase, the current total supply, and the rebase percent set by the team.
- When the rebase RX3 functionality is enabled by the team, the contract's rebase multiplier is applied to the number of tokens that will be added to the total supply.
- The rebase multiplier is increased by a value set by the team on all token transfers and is reset after a rebase occurs.
- The rebase function properly calls sync() on each Pair address to prevent theft-of-liquidity attacks that have occurred with other rebase tokens.
- The contract complies with the ERC-20 token standard.
- The contract utilizes SafeMath libraries to protect against overflows/underflows.
- The owner can set the Liquidity fee and Phenix Vault fee to any values as long as the total combined fee percentage does not exceed 25%.
- The owner can set the additional Sell fee to any percentage at any time.
- The owner can include/exclude accounts from transfer fees at any time.
- The owner can enable/disable automatic liquidity adds at any time.
- The owner can update the threshold number of tokens that triggers an automatic liquidity add to any value at any time.
- The owner can disable the initial distribution period at any time.
- The owner can exclude accounts from the initial distribution trading restriction at any time.
- The owner can update the rebase percent to any value at any time.
- The owner can enable/disable the Rebase multiplier functionality at any time.
- The owner can set the Rebase max multiplier and Rebase multiplier step to any values at any time.
- The owner can withdraw any tokens or CRO from the contract at any time.
- The owner can add/remove addresses as an Authorized rebase address at any time.
- The owner can update the Liquidity wallet and Phenix Fund Reserve wallet at any time.
- The owner can add addresses as an Automated Market Maker Pair at any time.
- The owner can add/remove addresses as a Taxable address at any time.
- The owner can update the Router address at any time.
- This contract is used to manage withdrawals and burns of a designated token.
- When the contract receives ETH, the "buyback allocation" is automatically updated. The buyback allocation is increased by the ratio between the "buyback percentage allocation" and the "buyback percentage denominator".
- Any authorized receiver address may trigger a swap and burn. The contract will swap collected ETH, up to the buyback allocation, for the designated token and subsequently send the tokens to the 0x..dead address.
- Any authorized receiver address may trigger a token burn, up to the "burn percentage", given that the "burn timestamp difference" has passed since the last burn was triggered.
- Once the unlock timestamp has passed, any authorized receiver address may withdraw any token or LP token from the contract at any time; the owner is set as an authorized receiver upon deployment.
- Any authorized receiver address may withdraw all ETH from the contract at any time.
- The owner may add and remove any address as an authorized receiver at any time.
- The owner may increase the unlock timestamp by any amount at any time.
- The owner may set the designated token, LP pair, and Router addresses to any value at any time.
- The owner may set the burn limit percentage and burn limit denominator to any value at any time.
|Arbitrary Jump/Storage Write||N/A||PASS|
|Centralization of Control||
|Delegate Call to Untrusted Contract||N/A||PASS|
|Dependence on Predictable Variables||N/A||PASS|
|Improper Authorization Scheme||N/A||PASS|
|Outdated Compiler Version||N/A||PASS|
|Overall Contract Safety||PASS|
($) = payable function # = non-constant function Int = Internal Ext = External Pub = Public + [Int] IERC20 - [Ext] totalSupply - [Ext] balanceOf - [Ext] allowance - [Ext] transfer # - [Ext] approve # - [Ext] transferFrom # + ERC20Detailed (IERC20) - [Pub]
# - [Pub] name - [Pub] symbol - [Pub] decimals + [Int] IVVSFactory - [Ext] feeTo - [Ext] feeToSetter - [Ext] getPair - [Ext] allPairs - [Ext] allPairsLength - [Ext] createPair # - [Ext] setFeeTo # - [Ext] setFeeToSetter # + [Int] IVVSRouter01 - [Ext] factory - [Ext] WETH - [Ext] addLiquidity # - [Ext] addLiquidityETH ($) - [Ext] removeLiquidity # - [Ext] removeLiquidityETH # - [Ext] removeLiquidityWithPermit # - [Ext] removeLiquidityETHWithPermit # - [Ext] swapExactTokensForTokens # - [Ext] swapTokensForExactTokens # - [Ext] swapExactETHForTokens ($) - [Ext] swapTokensForExactETH # - [Ext] swapExactTokensForETH # - [Ext] swapETHForExactTokens ($) - [Ext] quote - [Ext] getAmountOut - [Ext] getAmountIn - [Ext] getAmountsOut - [Ext] getAmountsIn + [Int] IVVSRouter (IVVSRouter01) - [Ext] removeLiquidityETHSupportingFeeOnTransferTokens # - [Ext] removeLiquidityETHWithPermitSupportingFeeOnTransferTokens # - [Ext] swapExactTokensForTokensSupportingFeeOnTransferTokens # - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($) - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens # + Ownable - [Pub] # - [Pub] owner - [Pub] isOwner - [Pub] renounceOwnership # - modifiers: onlyOwner - [Pub] transferOwnership # - modifiers: onlyOwner - [Int] _transferOwnership # + [Lib] SafeMath - [Int] add - [Int] sub - [Int] sub - [Int] mul - [Int] div - [Int] div - [Int] mod + [Lib] SafeMathInt - [Int] mul - [Int] div - [Int] sub - [Int] add - [Int] abs + [Int] InterfaceLP - [Ext] sync # + PhenixFinance (ERC20Detailed, Ownable) - [Pub] # - modifiers: ERC20Detailed - [Pub] getNextRebase - [Int] _rebase # - [Ext] rebaseAndSync # - [Ext] totalSupply - [Ext] transfer # - modifiers: validRecipient,initialDistributionLock - [Ext] addLPAddress # - modifiers: onlyOwner - [Ext] getLPAddresses - [Ext] setTaxableAddress # - modifiers: onlyOwner - [Ext] setAuthorizedRebaseAddress # - modifiers: onlyOwner - [Ext] allowance - [Ext] balanceOf - [Int] _basicTransfer # - [Int] _transferFrom # - [Ext] transferFrom # - modifiers: validRecipient - [Int] _swapBack # - modifiers: noReentrancy - [Int] _takeFee # - [Ext] decreaseAllowance # - modifiers: initialDistributionLock - [Ext] updateRouter # - modifiers: onlyOwner - [Ext] increaseAllowance # - modifiers: initialDistributionLock - [Ext] approve # - modifiers: initialDistributionLock - [Ext] checkFeeExempt - [Ext] setInitialDistributionFinished # - modifiers: onlyOwner - [Ext] enableTransfer # - modifiers: onlyOwner - [Ext] setFeeExempt # - modifiers: onlyOwner - [Int] _shouldTakeFee - [Ext] setSwapBackSettings # - modifiers: onlyOwner - [Ext] setRX3Settings # - modifiers: onlyOwner - [Ext] setRebaseSettings # - modifiers: onlyOwner - [Int] _shouldSwapBack - [Pub] getCirculatingSupply - [Ext] isNotInSwap - [Ext] checkSwapThreshold - [Ext] setFeeReceivers # - modifiers: onlyOwner - [Ext] setFees # - modifiers: onlyOwner - [Ext] emergencyRecoverETH # - modifiers: onlyOwner - [Ext] emergencyRecoverToken # - modifiers: onlyOwner - [Ext] ($)
($) = payable function # = non-constant function Int = Internal Ext = External Pub = Public + PhenixTokenVesting (Ownable) - [Pub] Constructor # - [Pub] setAuthorizedReceiver # - modifiers: onlyOwner - [Ext] increaseTimeLock # - modifiers: onlyOwner - [Ext] withdrawTokens # - [Ext] withdrawPairTokens # - [Ext] swapAndBurnTokens # - [Ext] setTokenAddress # - modifiers: onlyOwner - [Ext] setPairTokenAddress # - modifiers: onlyOwner - [Ext] updateRouter # - modifiers: onlyOwner - [Ext] burnTokens # - [Ext] withdrawFunds # - [Pub] getTokenBurnLimit - [Pub] canBurnTokens - [Ext] setBurnTokenSettings # - modifiers: onlyOwner - [Ext] isTokensUnlocked - [Ext] getUnlockTimestamp - [Ext] getTokenAddress - [Ext] getPairAddress - [Int] _updateBuyBackAllocation # - [Ext] Receive Ether ($)
SourceHat (formerly Solidity Finance - founded in 2020) has quickly grown to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1700+ solidity smart contract audits covering all major project types and protocols, securing a total of over $50 billion U.S. dollars in on-chain value!
Our firm is well-reputed in the community and is trusted as a top smart contract auditing company for the review of solidity code, no matter how complex. Our team of experienced solidity smart contract auditors performs audits for tokens, NFTs, crowdsales, marketplaces, gambling games, financial protocols, and more!
Contact us today to get a free quote for a smart contract audit of your project!
What is a SourceHat Audit?
Typically, a smart contract audit is a comprehensive review process designed to discover logical errors, security vulnerabilities, and optimization opportunities within code. A SourceHat Audit takes this a step further by verifying economic logic to ensure the stability of smart contracts and highlighting privileged functionality to create a report that is easy to understand for developers and community members alike.
How Do I Interpret the Findings?
Each of our Findings will be labeled with a Severity level. We always recommend the team resolve High, Medium, and Low severity findings prior to deploying the code to the mainnet. Here is a breakdown on what each Severity level means for the project:
- High severity indicates that the issue puts a large number of users' funds at risk and has a high probability of exploitation, or the smart contract contains serious logical issues which can prevent the code from operating as intended.
- Medium severity issues are those which place at least some users' funds at risk and has a medium to high probability of exploitation.
- Low severity issues have a relatively minor risk association; these issues have a low probability of occurring or may have a minimal impact.
- Informational issues pose no immediate risk, but inform the project team of opportunities for gas optimizations and following smart contract security best practices.