Yieldification

Smart Contract Audit Report

Audit Summary

Yieldification Audit Report Yieldification is a new ERC-20 token with staking contracts that allow users to earn rewards in ETH.

For this audit, we reviewed the following contracts on the Ethereum Mainnet:

Audit Findings

Medium findings were identified and the team should resolve these issues. In addition, centralized aspects are present.
Date: August 11th, 2022.
Updated: August 12th, 2022 with acknowledged findings.
Updated: November 25th, 2022 with additional contracts.

Finding #1 - PerpetualFutures - Medium

Description: The team has no ability to withdraw the ETH fees collected.
Risk/Impact: Any ETH fees collected will be stuck in the contract.
Recommendation: The team should add an owner restricted function to withdraw ETH from the contract.
Resolution: The team has not yet addressed this issue.

Finding #2 - PerpetualFutures - Low

Description: The contract does not track the total amount of fees collected.
Risk/Impact: The team must rely on events emitted or iterating over all positions to accurately determine the total fees collected in the contract.
Recommendation: The team should track the total fees collected to allow them to withdraw fees more easily. The total fees should be reset to 0 when withdrawn.
Resolution: The team has not yet addressed this issue.

Finding #3 - slYDF & StakeRewards - Low (Acknowledged)

Description: The swapping done in these contracts rely on the current reserves in the ETH-YDF liquidity pool to calculate slippage.
Risk/Impact: A frontrunner can manipulate the reserves before a transaction in order to create an arbitrage opportunity. A liquidity pool's reserves are not sufficient to prevent price manipulation in a swap.
Recommendation: The team should consider adding a TWAP Oracle or relying on Chainlink for a pricing mechanism. Alternatively, users could be enabled to provide the minimum amount out they expect from a swap.
Resolution: The team has implemented a fee structure that will mitigate potential frontrunning due to the high initial tax after buys.

Finding #4 - YDF - Low (Acknowledged)

Description: The _swapForETH() function is only called if the YDF fees collected reach 0.5% of the ETH-YDF liquidity pool's liquidity and performs a swap with unlimited slippage.
Risk/Impact: The liquidity pool can be manipulated to not allow the _swapForEth() function to be called until there is a large amount of YDF within the contract. This allows for a frontrunner to control when the next swap occurs and take advantage of the arbitrage opportunity it would create.
Recommendation: The team should consider adding a TWAP Oracle or relying on Chainlink for a pricing mechanism and adding a maximum allowed slippage.
Resolution: The team has implemented a fee structure that will mitigate potential frontrunning due to the high initial tax after buys.

Finding #5 - StakeRewards - Informational

Description: The totalStakedUsers is not decremented when a user no longer has any shares leading to inaccurate values.
Recommendation: The team should decrement the totalStakedUsers in the _removeShares() function if the user no longer has shares.

Finding #6 - YDFVester - Informational

Description: The team is able to add new Staking contracts but is unable to remove them.
Recommendation: The team should consider using a mapping to track valid Staking contracts and adding the ability to remove Staking contracts if needed.

Finding #7 - PerpetualFutures - Informational

Description: The contract maintains a large structure in memory for each position that is opened. These structures are never deleted.
Recommendation: The team should consider deleting positions after they are closed to prevent excess memory usage.

Contracts Overview

  • As the contracts are implemented with Solidity v0.8.9, they are safe from any possible overflows/underflows.
YDF Contract:
  • The owner is minted the initial total supply of 696.9 million (696,900,000) $YDF upon deployment.
  • The owner, slYDF contract, and this contract are fee exempt upon deployment.
  • The sYDF or slYDF addresses may mint any amount of tokens to the YDFVester contract.
  • Any user may burn their own tokens to reduce the total supply.
  • At the time of writing this report, there are 669 total token holders. The token allocation is as follows:
  • The token may not be bought until the owner has enabled trading.
  • Any address that performs a buy transaction within the first two blocks after trading is enabled will be marked as a bot.
  • Addresses marked as bots may buy tokens but may not be involved in any other transaction.
  • Addresses may not own more than 1% of the total supply until the "launch max transaction period" has passed from when trading was enabled.
  • Taxes are collected during sells if neither the sender or recipient is excluded from taxes.
  • A flat marketing and rewards tax are taken. An additional sell early tax is taken depending on the last time an address has bought tokens.
  • The sell early tax decays over time until reaching 0 when the "early sell expiration" period has passed since the address's last buy.
  • The sell early tax will only decay while the user has bought at least as many tokens as they have sold.
  • The decay will reset each time the users buys or when they sell more tokens than they have bought.
  • Users may reset their buy and sell data to reset the sell early tax decay. Resetting will set their bought tokens to their current balance, set their last buy time to the current timestamp, and set their sold tokens to 0.
  • The marketing and rewards tax percentages are initially set to 3% and 2% respectively.
  • The sell early tax begins at 10% before any decay occurs.
  • The marketing and rewards taxes are set to 1% and the sell early tax set to 13% once the "set and lock taxes" period has passed from when trading was enabled.
  • The marketing and rewards taxes are collected within the contract. The sell early tax is burned.
  • During transfers where the sender is not an approved market maker the tokens collected within the contract are swapped for ETH if the following conditions are met:
    • Swapping is enabled.
    • There is liquidity in the YDF-ETH liquidity pool.
    • The contract's YDF balance is at least 0.5% of the YDF-ETH liquidity pool's balance.
  • The proportion of ETH received relative to the marketing tax is transferred to the Treasury address.
  • The remaining ETH is transferred to the Rewards contract if it currently has shares deposited.
  • The ETH is instead transferred to the Treasury address if there are not any shares deposited.
  • The Vester address may add to the amount of tokens a user has bought. This will be considered a user's first buy, and their buy timestamp set accordingly, if they have not bought YDF tokens before.
  • The owner may include or exclude any address from taxes at any time.
  • The owner may add or remove any address as a market maker, used to determine buys and sells, at any time.
  • The owner may toggle swapping taxes for ETH at any time.
  • The owner may update the Treasury address at any time.
  • The owner may enable trading only once after deployment.
  • The owner may withdraw all ETH from the contract at any time.
sYDF:
  • Any address may stake a specified staking token to earn rewards.
  • The team must exercise caution when assigning the staking token to avoid using fee-on-transfer tokens.
  • Users receive a share in the StakeRewards contract for each token staked in the contract.
  • Users must specify a valid APR when staking. Each APR has a corresponding stake time.
  • Users earn rewards per block based on the selected APR and amount of tokens staked.
  • The staking tokens are locked in the contract for the stake time. Rewards are still earned once the stake time has elapsed.
  • Users are minted an NFT representing their position in the contract.
  • The contract implements ERC-2981 functionality that supports the use of Royalties that can be used with NFT marketplaces.
  • Users may unstake their tokens at any time but will pay a penalty if unstaking early. Unstaking will claim all earned rewards.
  • Users will pay a penalty in staked tokens proportional to the lock time remaining relative to the total lock duration.
  • The penalty will be burned if the staking tokens are YDF tokens. The penalty will be transferred to the owner if the staking tokens are any other token.
  • Users may also manually claim their rewards once per week if the specified NFT has not been blacklisted. Blacklisted NFTs may still use the unstake functionality to claim rewards.
  • Earned YDF tokens will be minted and transferred to the YDFVester contract where they will be vested over time.
  • The owner may update the Payment and Royalty addresses at any time.
  • The owner may update the royalty basis points at any time.
  • The owner may update the base URI at any time.
  • The owner may add, remove, and update APR lock options and their corresponding lock durations at any time.
  • The owner may toggle any NFT ID as blacklisted at any time. Blacklisted NFTs may not be transferred or claim rewards.
slYDF:
  • Any address may stake a specified LP token to earn rewards.
  • The contract provides "zap" functionality to support automatically adding LP for users.
  • The zap functionality allows users to stake LP tokens by providing only ETH, only YDF, or both ETH and YDF.
  • Users will receive 2 shares in the StakeRewards contract for each underlying YDF token the staked LP tokens are worth.
  • Users must specify a valid APR when staking. Each APR has a corresponding stake time.
  • Users will earn a reward per block based on the selected APR and amount of tokens staked.
  • The LP will be locked in the contract for the lock duration. Rewards are still earned once the lock duration has elapsed.
  • Users will be minted an NFT representing their position in the contract.
  • The contract implements ERC-2981 functionality that supports the use of Royalties that can be used with NFT marketplaces.
  • Users may unstake their tokens at any time but will pay a penalty if unstaking early. Unstaking will claim all earned rewards.
  • Users will pay a penalty in LP tokens proportional to the lock time remaining relative to the total lock duration. The penalty will be transferred to the owner.
  • Users may also manually claim their rewards once per week if the specified NFT has not been blacklisted.
  • Earned YDF tokens will be minted and transferred to the YDFVester contract where they will be vested over time.
  • The owner may update the Payment and Royalty addresses at any time.
  • The owner may update the royalty basis points at any time.
  • The owner may update the base URI at any time.
  • The owner may add and remove APR lock options and their corresponding lock durations at any time.
  • The owner may toggle any NFT ID as blacklisted at any time. Blacklisted NFTs may not be transferred or manually claim rewards.
  • The owner may set the maximum allowed slippage when zapping to any value at any time.
  • Users should take care not to send ETH directly to the contract and to only interact through the intended functions as any ETH sent directly to the contract will not be recovered.
StakeRewards Contract:
  • This contract is used to distribute rewards for sYDf and slYDF stakers.
  • The sYDF and slYDF addresses may increase a user's shares.
  • Users are distributed their rewards if they already have shares.
  • The sYDF and slYDF addresses may decrease a user's shares.
  • Users are always distributed their pending rewards when shares are removed.
  • Users will receive a reward amount of ETH on each block based on the amount of shares deposited.
  • Users may manually claim their rewards at any time.
  • Users may choose to compound their rewards when manually claiming; compounding will swap the user's ETH for YDF.
  • Any address may deposit ETH into the contract to be distributed as rewards given that there are currently shares deposited in the contract.
  • The owner may update the maximum allowed slippage when compounding to any value at any time.
  • The owner may update the sYDF and slYDF addresses at any time.
YDFVester Contract:
  • Any approved Staking contract may create a vesting lock for an address.
  • Vested tokens must be supplied to the contract or users will be unable to withdraw.
  • Tokens are vested over a period of 90 days divided into 10 withdrawal periods.
  • Users may only withdraw once per period.
  • Any withdrawal periods that have elapsed will be included in the current withdrawal.
  • Withdrawn tokens are transferred to the user and added to their tokens bought count in the YDF contract.
  • The owner may add an address as a valid Staking address at any time.
pfYDF Contract:
  • This contract defines the pfYDF ERC-721 NFTs.
  • The contract allows conforms to the ERC-2981 Royalty standard for distributing royalties in NFT marketplaces.
  • The PerpetualFutures contract may mint any address an NFT at any time.
  • The PerpetualFutures contract may burn any NFT at any time.
  • The owner may set the Royalty address and royalty basis points at any time.
  • The owner may set the base URI at any time.
  • The owner may set the PerpetualFutures address at any time.
PerpetualFutures Contract:
  • This contract allows users to take long and short positions against various Indexes using ETH or any supported collateral token.
  • When trading is enabled, any address may open a position against a specified Index by providing collateral.
  • The contract properly accounts for fee-on-transfer tokens where applicable.
  • Indexes may have restrictions preventing users from opening a position on certain days of the week or during specific hours of a given day.
  • Users may specify an amount of leverage.
  • The total size of the position will be multiplied by the leverage chosen.
  • A "position opening" fee will be taken from the provided collateral.
  • Leveraged positions will be charged a larger fee proportional to the amount of leverage.
  • A discount may be applied to the opening fee if the FeeReducer address has been set by the team.
  • The current Index price at the time of opening is determined using PriceFeeds. The PriceFeeds are intended to be Chainlink Data Feeds.
  • Each PriceFeed associated with the Index will fetch the current price of the asset it is tracking.
  • If there is more than 1 PriceFeed, the cumulative price will be determined based on the "weight" of each PriceFeed where a higher weight will have more impact on the price.
  • The position will not be opened if the Index's current price is outside of the allowed slippage specified by the user.
  • The position will also not be opened if the difference between the total amount of open short and long positions for the collateral token would exceed the maximum "open difference" value.
  • Users will be minted a pfYDF NFT representing ownership of their position on the platform.
  • The user may additionally create a "trigger order" when opening a position.
  • A trigger order will close the position if the index hits a specified target price during "upkeep".
  • Users may close one of their open positions at any time.
  • The closing user will be returned any remaining collateral after fees and losses.
  • The position will be put into an "unsettled position" if it resulted in an overall profit and the collateral token is not YDF.
  • Positions that are in the profit and using YDF as collateral will receive the collateral and profit when closing.
  • Any profit will be forfeited if the starting price is not the "minimum price difference for profit" from the opening price or the "minimum open time for profit" has not passed from when the position was opened.
  • A "position closing" fee will be taken based on the total size of the position and a "position duration" fee will be taken based on the amount of time the position was open.
  • A discount may be applied to the closing fees if the FeeReducer address has been set by the team.
  • The pfYDF NFT representing the position will be burned.
  • The Settler address may settle an unsettled position at any time.
  • The position owner will be transferred the profit from the position in the form of YDF tokens.
  • Sufficient tokens must be supplied to the contract to pay out profits.
  • Users may add and remove a trigger order from a position at any time. Each user may only have up to the "max trigger orders" number of trigger orders at once.
  • Users may update the target price for a trigger order at any time. The target price must stay greater than the current price if the original target price was greater than the current price. The target price must stay lower than the current price if the original target price was lower than the current price.
  • Any address may check if "upkeep" is needed. The contract will iterate over all open positions and check if they are liquidable if or one of their trigger prices have been reached.
  • A position is liquidable if the current price has passed the liquidation threshold.
  • The liquidation threshold is determined from the price of the Index when the position was opened and the position's leverage.
  • Any address may perform upkeep at any time. The contract will iterate over all open positions and liquidate or close all applicable positions. Only the "maxLiquidationsPerUpkeep" positions will be closed at once.
  • The upkeep functionality is intended to be run periodically by Chainlink Keepers.
  • The owner may add and remove a token as a valid collateral token at any time.
  • The owner may update the main collateral token address at any time. This is intended to be the YDF token.
  • The owner may set the max leverage, up to 250, at any time.
  • The owner may set the max number of trigger orders for each user to any value at any time.
  • The owner may set the minimum duration for a position to collect profit, up to 1 day, at any time.
  • The owner may set the minimum price change for a position to collect profit, up to a 10% change, at any time.
  • The owner may set the close and open position fees, up to 10%, at any time.
  • The owner may update the Settler and FeeReducer addresses at any time.
  • The owner may set the maximum allowed difference between long and short positions to any value at any time.
  • The owner may set the max liquidations per upkeep to any non-zero value at any time.
  • The owner may add and remove an Index at any time.
  • The owner may update the weight for each PriceFeed in an Index at any time.
  • The owner may set the hours and days an Index may have a position opened at any time.
  • The owner may enable and disable trading at any time.
  • The owner may withdraw any token from the contract at any time.
slYDFZapper Contract:
  • This contract serves as a wrapper for staking YDF tokens and ETH in the slYDF contract.
  • Users may stake using just ETH, just YDF, or both.
  • When staking with only ETH, half of the supplied ETH will be swapped for YDF tokens.
  • The remaining ETH will be paired with the received YDF tokens and staked in the slYDF contract.
  • The user will be transferred all received slYDF tokens.
  • When staking with only YDF, half of the supplied YDF will be swapped for ETH.
  • The remaining YDF will be paired with the received ETH and staked in the slYDF contract.
  • The user will be transferred all received slYDF tokens.
  • When staking with both YDF and ETH, the supplied tokens will be paired and staked in the slYDF contract.
  • The user will be transferred all received slYDF tokens.
  • All staking functions will return any excess ETH and YDF tokens remaining after staking.
  • The contract properly accounts for fee-on-transfer tokens where applicable.
Bridge Contract:
  • This contract uses Relay addresses to transfer tokens between users across chains.
  • The contract requires the use of off-chain logic. This is outside the scope of this audit so we cannot give an assessment in regard to security.
  • Any user may initiate a transaction when the contract is active.
  • Users must pay the "bridge cost" when initiating a transaction.
  • The specified amount of tokens will be transferred from the user and stored in the contract.
  • Any Relay address may "initiate a delivery" when the contract is active. This will allocate a specified amount of tokens for an address.
  • A Relay address may "deliver" an initiated delivery when the contract is active. The delivering Relay address must be different from the Relay address that initiated the delivery.
  • A delivery will transfer the tokens allocated in the initiation to the specified address.
  • Any Relay address may mark a "source" as complete. This will remove the data associated with a transaction that has been initiated but is incomplete and mark the transaction as completed.
  • The contract does not properly accounts for fee-on-transfer tokens, though it is intended to be used with YDF tokens which would not take fees on a peer-to-peer transfer. If the team intends to use a fee-on-transfer token, the contract must be restructured or properly excluded from fees.
  • The owner may toggle whether the contract is active at any time.
  • The owner may set the bridge cost to any value at any time.
  • The owner may add and remove a Relay address at any time.
  • The owner may set the source confirmations to any value at any time.
  • The owner may withdraw all tokens and ETH from the contract at any time.

Audit Results

Vulnerability Category Notes Result
Arbitrary Jump/Storage Write N/A PASS
Centralization of Control
  • The sYDF and slYDF owner may blacklist any NFT in the contracts.
  • The slYDF and StakeRewards owner may allow slippage up to 100% in the contracts.
  • The PerpetualFutures owner may disable trading at any time.
  • The PerpetualFutures owner may withdraw all tokens from the contract.
  • The Bridge owner may withdraw all tokens from contract.
  • The Bridge owner may set the bridge cost to any amount.
WARNING
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 YDF, slYDF, and StakingRewards functions are open to potential frontrunning. WARNING
Improper Events N/A PASS
Improper Authorization Scheme N/A PASS
Integer Over/Underflow N/A PASS
Logical Issues The team has no ability to withdraw ETH fees collected in the PerpetualFutures contract. WARNING
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
Unbounded Loops N/A PASS
Unused Code N/A PASS
Overall Contract Safety   WARNING

Contract Source Summary and Visualizations

Name

Address/Source Code

Visualized
(Hover-Zoom Recommended)

YDF Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

sYDF Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

slYDF Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

StakeRewards Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

YDFVester Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

pfYDF Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

PerpetualFutures Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

slYDFZapper Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

Bridge Contract

ETH Mainnet

Inheritance Chart.  Function Graph.

About Solidity Finance

Solidity Finance was founded in 2020 and quickly grew to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1300+ 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 across 1500 projects!.
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 Solidity Audit?

Typically, a smart contract audit is a comprehensive review process designed to discover logical errors, security vulnerabilities, and optimization opportunities within code. A Solidity 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.