ElectroSwap Yield Farm
Smart Contract Audit Report
Executive Summary
This report presents the outcomes of our collaborative engagement with the ElectroSwap team, focusing on the comprehensive evaluation of the YieldFarm contract.
Our team conducted an initial security assessment from October 5th to October 14th, 2024. This report was updated on October 18th, focusing on the changes from commit e39390a
to commit 9011678
.
This report was updated on October 21st, focusing on the changes from commit 9011678
to commit a3ade3f
. This report was updated on November 11th, to reflect the contract's Mainnet address.
ElectroSwap is developing a decentralized yield farming platform that allows users to provide liquidity to Uniswap V2 and V3 pools in exchange for rewards. The platform supports both V2 and V3 farms, offering liquidity providers additional incentives such as third-party rewards and bonus multipliers for staking BOLT tokens.
Audit Scope
Name |
Source Code (ETN Mainnet) |
Visualized |
YieldFarm |
Name/Source Code |
Visualized |
YieldFarm |
Audit Findings
All findings have been resolved. In addition, minimal centralized aspects are present.
Finding #1 |
YieldFarm |
High Resolved |
Finding #1 - YieldFarm
|
||
Description: When a pool is deactivated, Risk/Impact: Users will be unable to withdraw liquidity from deactivated pools, which conflicts with the contract's intended functionality.
Recommendation: Modify the deactivation process so that Resolution: The team has implemented the above recommendation. |
||
Finding #2 |
YieldFarm |
High Resolved |
Finding #2 - YieldFarm
|
||
Description: During withdrawals, the _collectRewardsAndFees() function incorrectly updates Risk/Impact: This will result in incorrect reward calculations, leading to under-rewarding of farmers.
Recommendation: Update the Resolution: The team has implemented the above recommendation. |
||
Finding #3 |
YieldFarm |
High Resolved |
Finding #3 - YieldFarm
|
||
Description: The Risk/Impact: This issue leads to the contract distributing more rewards than the amount deposited. This overpayment could deplete the reward pool, resulting in fewer rewards available for subsequent deposits or other users.
Recommendation: Remove the Resolution: The team has implemented the above recommendation. |
||
Finding #4 |
YieldFarm |
Medium Resolved |
Finding #4 - YieldFarm
|
||
Description: Users can deposit BOLT tokens multiple times, but the deposit() function does not update or record the logic for subsequent BOLT deposits, despite accepting the token transfer. Risk/Impact: If users deposit BOLT more than once, those additional tokens will not be accounted for, effectively locking them in the contract without providing any benefits to the user.
Recommendation: Modify the deposit() function to either prevent additional BOLT deposits if the caller currently has a non-zero Resolution: The team has modified the logic to properly allow multiple BOLT deposits if the sum of all deposited BOLT tokens by the user qualifies them for a valid reward tier. |
||
Finding #5 |
YieldFarm |
Low Resolved |
Finding #5 - YieldFarm
|
||
Description: The deposit() function does not prevent users from submitting 0 for both _amount0 and _amount1 parameters, allowing deposits without adding any liquidity. While the add-liquidity transaction would result in failure for UniswapV2 pairs, it can still occur for UniswapV3 deposits, leading to the addition of farmers without any actual liquidity being provided. Risk/Impact: Users can be added to the farmers array without depositing any tokens into the contract. Malicious users can initiate deposits of 0 tokens causing unnecessary growth of the farmers array which increases gas costs for future operations. Recommendation: Add a check in the deposit() function to ensure that at least one of _amount0 or _amount1, is greater than zero to prevent zero-liquidity deposits. Resolution: The team has added a require statement to enforce that both _amount0 and _amount1 are greater than zero. |
||
Finding #6 |
YieldFarm |
Informational Resolved |
Finding #6 - YieldFarm
|
||
Description: The contract does not include logic to support fee-on-transfer tokens in the deposit() function for Recommendation: The project team should avoid using Pairs that involve fee-on-transfer tokens or assigning such tokens as third-party rewards, unless proper fee exemptions are in place. Alternatively, the team could introduce logic in the deposit() and depositThirdPartyReward() functions that records the contract's token balance before and after the transfer occurs, ensuring the actual transfer amount is used. Resolution: The team has acknowledged this finding and does not intend to add Pairs containing fee-on-transfer tokens. |
||
Finding #7 |
YieldFarm |
Informational Acknowledged |
Finding #7 - YieldFarm
|
||
Description: The add-liquidity and increase-liquidity processes may be vulnerable to front-running due to the absence of minimum "amount out" values. However, while this could expose the contract to front-running, there is no clear financial incentive for a malicious user to exploit it. Recommendation: The deposit() function could be modified to accept minimum "amount out" values for each token, ensuring that liquidity is only added when these thresholds are met, thereby mitigating potential front-running risks. Resolution: The team has acknowledged this Finding. |
System Overview
DeploymentA new Reward token contract is created upon deployment of the YieldFarm contract. The initial total supply is 10,000 tokens and is minted to the deployer. The YieldFarm contract is added as a Minter address and can mint any number of tokens to any address at any time.
Create V2 FarmThe owner can create a new yield farm for a V2 liquidity pool by specifying its name identifier, the address of an existing V2 Pair, and a number of allocation points to assign to the farm. The token addresses for the Pair are recorded, and the total reward allocation for all farms is updated.
Create V3 FarmThe owner can create a new yield farm for a V3 liquidity pool by specifying its name identifier, an existing V3 position token ID, and a number of allocation points to assign to the farm. The V3 position’s token addresses, fee, and liquidity range are recorded. The associated V3 NFT, which represents the liquidity position, is transferred from the owner to the contract, and the total reward allocation for all farms is updated.
Yield Farm UpdatesThe owner can update the allocation points assigned to an existing farm at any time. The owner can update the name identifier assigned to an existing farm at any time. The owner can deactivate an existing farm at any time preventing future deposits and reward calculations from occurring. The owner can update the contract's rewards per block value to any value at any time. The owner can update the valid BOLT deposit amounts and their corresponding reward multipliers at any time.
Add/Deposit Third-Party RewardsThe owner can add third-party rewards to a farm by specifying the token address and token manager address. The owner or designated token manager can supply third-party rewards to a specific farm by depositing tokens and specifying the number of blocks over which these tokens will be distributed. This process updates the tokens-per-block rate for the farm and adjusts the end block to reflect the new distribution period.
DepositsAny user can initiate a deposit by specifying a farm ID to deposit into, the amount of the first token in the liquidity pair the user is depositing, and the amount of the second token in the liquidity pair the user is depositing. The caller may also specify an amount of BOLT tokens to deposit to boost rewards. The sum of the specified BOLT deposit amount and the user's existing BOLT deposit amount must be a valid amount previously defined by the team.
If ETN is sent with the deposit, one of the pool's tokens must be the WETN address set by the team. The contract will wrap the provided ETN as WETN and handle the other token as an ERC20 transfer from the caller to the contract. Users depositing into a V2 farm provide both tokens, which are added as liquidity to the farm's assigned Pair address. For V3 farms, liquidity is concentrated within a specific price range, and liquidity is increased for the farm's existing V3 position.
Once the deposit is made, if the caller does not currently have a liquidity amount associated with their address, they are added as a farmer. The farmer's total liquidity, rewards, fees, and debts are updated accordingly. Additionally, any excess tokens not added as liquidity are refunded to the user.
WithdrawsAny user can initiate a withdrawal by specifying a farm ID and an amount of liquidity to withdraw. If the user withdraws from a pool that includes WETN, the user can elect for the contract to unwrap the WETN and send it as ETN.
The user's current pending rewards are calculated based on a combination of the user's liquidity, the farm's allocation points, the block duration, and any applicable multipliers, including BOLT bonuses and duration-based bonuses. The calculated number of rewards are minted to the caller via the Reward token contract.
The user's third-party rewards (if applicable) are calculated based on the user's liquidity, the third-party tokens per block value, and the block duration. The calculated amount of third-party rewards are transferred from the contract to the caller.
The user's share of collected fees (if applicable) is determined by their liquidity and the farm's accumulated fee per share values for both tokens in the pool. The contract calculates the user's entitlement to the fees collected from swaps in the liquidity pool and transfers the corresponding amounts of token0 and token1 from the contract to the caller. If the pool contains WETN and the user has opted for native ETN, the contract will unwrap the WETN and transfer the equivalent ETN to the user.
Liquidity is removed/decreased from the Pair address of the specified Farm ID. When withdrawing from a V3 Pair, the user's collected fees are transferred along with the removed liquidity.
If the user withdraws from a pool that includes WETN, the user can elect for the contract to unwrap the WETN and send it as ETN, while the other token is transferred as an ERC20.
The full number of BOLT tokens previously deposited are automatically returned from the contract to the user if the full liquidity amount is withdrawn.
Vulnerability Analysis
Vulnerability Category | Notes | Result |
---|---|---|
Arbitrary Jump/Storage Write | N/A | PASS |
Centralization of Control | N/A | 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 | N/A | PASS |
Improper Events | N/A | PASS |
Improper Authorization Scheme | N/A | PASS |
Integer Over/Underflow | N/A | PASS |
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 | PASS |
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.