Ultron Foundation DAO
Smart Contract Audit Report
Audit Summary
Ultron Foundation is building a new decentralized automated liquidity protocol trading platform that is used to exchange cryptocurrencies, with additional DAO capabilities.
For this audit, we reviewed the contracts provided to us on the team's private GitHub repository.
We previously reviewed the project team's multisig contracts here.
Audit Findings
Medium findings were identified and the team should resolve these issues. In addition, centralized aspects are present.
Date: December 20th, 2022.Finding #1 - UniswapV2Pair - Medium
Description: The fee calculation in the swap() function allows for underflow:Risk/Impact: Arbitrary logic can be executed during the swap function. This can be exploited to cause the fees to underflow. The following require statement can then be manipulated to cause swaps to occur that should not be allowed:uint fee0 = (balance0 - (_reserve0 - amount0Out)).mul(10) / 10000; uint fee1 = (balance1 - (_reserve1 - amount1Out)).mul(10) / 10000;Recommendation: The fee0 and fee1 amounts should instead be calculated using the amount0In and amount1In values.require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0 - fee0).mul(_reserve1 - fee1).mul(1000**2), 'UniswapV2: K');
Resolution: The team has not yet addressed this issue.
Finding #2 - UniswapDAO & DAOTreasury - Medium
Description: Any voter may cancel any initiative at any time.
Risk/Impact: One voter acting in bad faith may cancel any initiative they do not agree with.
Recommendation: The team should consider allowing only the user that proposed an initiative to cancel it.
Resolution: The team has not yet addressed this issue.
Finding #3 - UniswapV2Pair - Medium
Description: The _swapWETHFee() function relies on getAmountsOut() to determine pricing of a non-WETH token to non-WETH token pair.
Risk/Impact: A frontrunner can manipulate the reserve values before the _swapWETHFee() function is called to create an artificial arbitrage opportunity.
Recommendation: The team should consider collecting fees in the tokens being swapped in all cases. Alternatively, the team can rely on Chainlink off-chain Oracle or a TWAP Oracle for pricing.
Resolution: The team has not yet addressed this issue.
Finding #4 - UltronNFT - Informational
Description: An NFT's claimable_amount and locked_amount cannot be set to 0 due to the following code in the decreaseClaimable() function:Recommendation: The team should allow equality in these requirements as follows:require(nft_packages[_id].claimable_amount - _amount > 0, 'ltz'); require(nft_packages[_id].locked_amount - nft_packages[_id].claimable_amount > 0, 'ltz2')Resolution: The team has not yet addressed this issue.require(nft_packages[_id].claimable_amount - _amount >= 0, 'ltz'); require(nft_packages[_id].locked_amount - nft_packages[_id].claimable_amount >= 0, 'ltz2')
Contracts Overview
UltronNFT Contract:DAOTreasury Contract:
- This contract defines Ultron NFTs.
- Only the first minted Ultron NFT may be burned and only the owner may transfer their NFTs.
- The owner may mint an NFT to any address at any time.
- Users and approved addresses may enable and disable the "autocompound" value for their NFTs.
- Each NFT has a "claimable amount", "locked amount", and "total rewards amount".
- The owner may add to an NFT's claimable amount, as long as the new claimable amount would not exceed the locked amount.
- The owner may decrease an NFT's claimable amount as long as it remains above 0.
- The owner may increase an NFT's total rewards amount to any value at any time.
- The owner may disable an NFT's autocompound status if its "disable at next week" value is true. Doing so will set the disable at next week value to false.
Treasury Contract:
- This contract allows users to vote on different types of initiatives.
- Only valid "voter" addresses may vote on and propose an initiative.
- Any voter address may cancel a non-executed initiative at any time.
- The contract deployer is the first voter by default.
- Voter addresses may propose 4 different kinds of initiatives:
- A DAO change request.
- A transfer tokens request.
- A transfer ETH request.
- A change voter address request.
- Once an initiative has been proposed, any voter address may vote for or against the initiative.
- If more than 50% of the total number of voters have voted for the initiative it is considered passed.
- With the exception of a new voter address request, the initiatives have no function on their own and must be executed by the Treasury contract.
- A passed change voter address request may be executed by any address at any time.
- The address specified in the initiative will be added or removed as a voter accordingly.
- The contract deployer may set the Treasury address once after deployment.
UniswapV2ERC20 Contract:
- This contract is intended to be used with the DAOTreasury contract to execute initiatives.
- The contract deployer may set the initial DAO contract once after deployment.
- Any address may trigger the setting of a new DAO address, if a DAO change request has passed in the DAO contract.
- Any address may trigger a withdrawal of tokens, if a transfer tokens request has passed in the DAO contract.
- Any address may trigger a withdrawal of ETH, if a transfer ETH request has passed in the DAO contract.
- This contract correctly calls the corresponding "confirm" function to mark an initiative as completed once the transaction has been executed.
UniswapV2Factory Contract:
- The UniswapV2ERC20 contract implements the ERC-20 standard for use as an LP token.
- This contract utilizes a "permit" mechanism which allows the owner of the $uxLP tokens to sign a transaction that enables another user to withdraw tokens and send them to the recipient. The recipient then submits the permit on behalf of the owner.
UniswapV2Pair Contract:
- The UniswapV2Factory contract is responsible for the creation of liquidity pairs for two tokens, thereby enabling trading on the platform.
- When creating a new trading pair, the UniswapV2Pair initialize() function is called which allows the factory to specify the two ERC20 tokens that this pair will exchange.
- Once the pool is created, its address is stored with a double mapping that takes both token addresses as input.
- The contract also contains additional functionality to execute passed initiatives from the UniswapDAO contract.
- The initialDaoSetter address specified upon deployment may set the initial UniswapDAO contract once after deployment.
- Any address may trigger the setting of a new DAO address, if a DAO change request has passed in the DAO contract.
- Any address may trigger the setting of a new FeeTo address, if a fee change request has passed in the DAO contract.
- Any address may trigger the setting of a new Treasury address, if a Treasury change request has passed in the DAO contract.
- Any address may trigger the setting of a new Router address, if a Router change request has passed in the DAO contract.
- This contract correctly calls the corresponding "confirm" function to mark an initiative as completed once the transaction has been executed.
UniswapV2Router02 Contract:
- The UniswapV2Pair contract is the core Uniswap trading functionality.
- Each UniswapV2Pair manages a liquidity pool made up of reserves of two ERC-20 tokens.
- This contract is responsible for tracking the balance of both tokens in the pair, as well as mints and burns of the LP token.
- Users can add liquidity by providing an equivalent value of each token and are minted LP tokens in return.
- The LP tokens may be burned to receive the underlying assets at any time.
- Users may also exchange one token for an equivalent amount of the other token based on the current market value.
- A 0.3% fee is taken on an exchange between tokens and given as rewards to LP providers.
- Of the 0.3% fee collected, 0.075% is taken on liquidity adds and burns if the FeeTo adddress has been set.
- An additional 0.1% of the swapped tokens are taken as a fee and transferred to a Treasury address controlled by the team.
UniswapDAO Contract:
- The UniswapV2Router02 contract is used to interact with liquidity pools that are created via the UniswapV2Factory contract.
- UniswapV2Router02 routes orders to the user-determined pair contract to swap assets.
- This contract performs requirement checks needed for swapping tokens, adding liquidity, and removing liquidity.
- The contract uses an alternative implementation for WETH that handles deposits and withdraws through regular transfers. This contract was outside the scope of this audit so we are unable to give an assessment with regard to security.
- This contract allows users to vote on different types of initiatives.
- Only valid "voter" addresses may vote on and propose an initiative.
- Any voter address may cancel a non-executed initiative at any time.
- The contract deployer is the first voter by default.
- Voter addresses may propose 5 different kinds of initiatives:
- A DAO change request.
- A fee change request.
- A Treasury change request.
- A Router change request.
- A change voter address request
- Once an initiative has been proposed, any voter address may vote for or against the initiative.
- If more than 50% of the total number of voters have voted for the initiative it is considered passed.
- With the exception of a new voter address request, the initiatives have no function on their own and must be executed by the UniswapV2Factory contract.
- A passed change voter address request may be executed by any address at any time.
- The address specified in the initiative will be added or removed as a voter accordingly.
Audit Results
| Vulnerability Category | Notes | Result |
|---|---|---|
| Arbitrary Jump/Storage Write | N/A | PASS |
| Centralization of Control |
|
PASS |
| Compiler Issues | N/A | PASS |
| Delegate Call to Untrusted Contract | N/A | PASS |
| Dependence on Predictable Variables | N/A | PASS |
| Ether/Token Theft | N/A | PASS |
| Flash Loans | N/A | PASS |
| Front Running | The _swapWETHFee() function is vulnerable to potential front running. | WARNING |
| Improper Events | N/A | PASS |
| Improper Authorization Scheme | N/A | PASS |
| Integer Over/Underflow | The UniswapV2Pair address allows for potential underflow. | WARNING |
| Logical Issues | N/A | PASS |
| Oracle Issues | N/A | PASS |
| Outdated Compiler Version | N/A | PASS |
| Race Conditions | N/A | PASS |
| Reentrancy | N/A | PASS |
| Signature Issues | N/A | PASS |
| Sybil Attack | N/A | PASS |
| Unbounded Loops | N/A | PASS |
| Unused Code | N/A | PASS |
| Overall Contract Safety | WARNING |
Contract Source Summary and Visualizations
Name |
Address/Source Code |
Visualized |
UltronNFT |
||
DAOTreasury |
||
Treasury |
||
UniswapV2ERC20 |
||
UniswapV2Factory |
||
UniswapV2Pair |
||
UniswapV2Router02 |
||
UniswapDAO |
About SourceHat
SourceHat has quickly grown to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1800+ 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.