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 contracts deployed on up to 6 networks: Ethereum, Arbitrum, AVAX, Fantom, Binance Smart Chain, and Polygon all at the same addresses. Please see the table at the bottom of the report for all addresses.

Audit Findings

Informational findings were identified and the team may want to review them. In addition, centralized aspects are present.
Date: August 11th, 2022.
Updated: August 12th, 2022 with acknowledged findings.
Updated: November 25th, 2022 with pfYDF, PerpetualFutures, slYDFZapper, and Bridge contracts.
Updated: December 5th, 2022 with NFTMarketplace contract.
Updated: January 13th, 2023 with OverTheCounter contracts.
Updated: January 18th, 2023 with resolution to findings.
Updated: March 6th, 2023 with new OverTheCounter contract.
Updated: May 2nd, 2023 with changes from the PerpetualFutures contract at 0x32EF81D6b048dF4B080999B0a5c4F70A2881434f on multiple networks to 0x0144Fa34AC7F36B2e0Cea60DCCb0ED3C947AB672 on the Goerli testnet.

Finding #1 - OverTheCounter - High (Resolved)

Description: Users can create a pool without supplying any ETH if the input asset is not ETH and the contract has a sufficient ETH balance.
Risk/Impact: This allows users to not pay the createServiceFeeETH. Repeated use of this exploit would drain all of the contract's balance to the Treasury address.
Recommendation: The team must check msg.value >= createServiceFeeETH in the createPool() function.
Resolution: The createPool() function now checks that msg.value >= createServiceFeeETH.

Finding #2 - OverTheCounter - High (Resolved)

Description: Users can reenter into the poolRemove() function.
Risk/Impact: A malicious user could create a Pool with a worthless token paired with ETH. They could then swap for 1 ETH and call the poolRemove() function. By reentering the poolRemove() function all of the contract's ETH can be drained. This could be done for any token.
Recommendation: The team must make the poolRemove() function NonReentrant. They should consider making all functions NonReentrant as well.
Resolution: The team has added NonReentrant to all external functions that change state.

Finding #3 - OverTheCounter - Medium (Resolved)

Description: Users can leverage the onERC721Received() function that is called during the safeTransferFrom() function within the tradeOTC() function to execute arbitrary logic.
Risk/Impact: A malicious user could create a contract that calls the packageWithdraw() function during the trade in the tradeOTC() function. The scenario is as follows:
  1. User A creates a contract that calls packageWithdraw() on a specified otcYDF NFT in the onERC721Received() function.
  2. User A transfers an otcYDF NFT to the contract and the contract adds the target otcYDF NFT to its userOTCTradeWhitelist.
  3. User B agrees to trade the target NFT with the contract by adding the contract to their userOTCTradeWhitelist.
  4. User B's NFT is transferred to the contract which subsequently calls packageWithdraw() upon receiving the token.
  5. The contract's otcYDF NFT is transferred to User B who receives less assets than expected.
Recommendation: The team should call transferFrom() rather than safeTransferFrom() in the tradeOTC() function. Alternatively, the team can add ReentrancyGuard to both the tradeOTC() and packageWithdraw() functions.
Resolution: The team has changed the safeTransferFrom() functions to transferFrom() to prevent any reentrancy. They have additionally added NonReentrant to all external functions that change state.

Finding #4 - OverTheCounter - Medium (Resolved)

Description: Users can update a Package's unlockStart and unlockEnd variables after purchasing a Package.
Risk/Impact: This allows users to bypass the vesting withdraw logic in the _withdrawAssetFromPackage() function.
Recommendation: The team should consider only allowing the Package creator to update a Package's attributes.
Resolution: Only the Package creator can adjust the unlockStart and unlockEnd times.

Finding #5 - PerpetualFutures - Medium (Resolved)

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 implemented a withdrawETH() function.

Finding #6 - NFTMarketplace - Medium (Resolved)

Description: Listing owners have no ability to edit or remove a buy it now listing.
Risk/Impact: Listing owners may have their NFT bought at a value lower than they intended. The NFT will additionally always be for sale.
Recommendation: The team should consider adding the ability to edit and remove buy it now offers.
Resolution: The team has added the ability for NFT owners to remove a buy it now listing from the Marketplace.

Finding #7 - PerpetualFutures - Low (Acknowledged)

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 plans to manually track and collect fees.

Finding #8 - PerpetualFutures - Low (Acknowledged)

Description: The contract does not track the staked main collateral token balance separately from the main collateral token balance used to payout profit.
Risk/Impact: If sufficient tokens are not supplied profit can be paid out in users' staked funds.
Recommendation: The team should track the staked main collateral token balance to prevent these tokens from being used to pay profits.
Resolution: The team plans to manually supply main collateral tokens to the contract to prevent the above situation.

Finding #9 - 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 #10 - 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 #11 - 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 #12 - 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 #13 - 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.

Finding #14 - OverTheCounter - Informational (Resolved)

Description: The createPool() function allows users to create a pool that would be considered invalid in the swapPool() function.
Recommendation: The team should consider requiring both tokens are not ETH in the createPool() function.
Resolution: The team has implemented the solution recommended above.

Finding #15 - OverTheCounter - Informational (Resolved)

Description: The contract has no method to allow users to update their Pools.
Recommendation: The team should consider adding an updatePool() function to let users change the price of their Pool.
Resolution: The team has implemented the solution recommended above.

Finding #16 - OverTheCounter - Informational (Resolved)

Description: The packageCreate() function allows users to create Packages with an unlockEnd time and no unlockStart time and vice versa.
Recommendation: The team should consider requiring that both the unlockEnd and unlockStart times are 0 or that both the unlockEnd and unlockStart times are not 0:
require((unlockEnd == 0 && unlockStart ==0) || (unlockEnd != 0 && unlockStart != 0))
Resolution: The team has implemented the solution recommended above.

Finding #17 - OverTheCounter - Informational (Resolved)

Description: The contract does not give itself approval after transferring otcYDF NFTs in the acceptPackageOffer() and buyItNow() functions. This will require users to give approval to the contract if they sell a Package that has previously been bought.
Recommendation: The team should call the approveOverTheCounter() function after transferring the otcYDF NFTs in the acceptPackageOffer() and buyItNow() functions.
Resolution: The team has implemented the solution recommended above.

Contracts Overview

  • As the contracts are implemented with Solidity v0.8, 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 is 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. The collateral tokens include a "main collateral" token.
  • The team is currently relying on their own pricing mechanism which is out of scope for this audit so we are unable to provide an assessment in regard to security. The team plans to migrate to Chainlink pricing in the future.
  • When trading is enabled, any address may initiate opening a position against a specified active Index by providing collateral and creating an "open Position request". Users will be charged an "open fee" in ETH if the fee has been set.
  • Each collateral token may have a minimum collateral amount that may vary between tokens.
  • Each Index may have restrictions preventing users from opening a position on certain days of the week and/or during specific hours of a given day.
  • Users may specify an amount of leverage up to the max leverage value. The total size of the position will be multiplied by the leverage chosen.
  • Each index may have its own individual max leverage value.
  • After an open Position request has been submitted a Relay address may open the Position on the behalf of the requester.
  • A "Position opening" fee will be taken from the provided collateral and stored within the contract.
  • 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 FeeReducer contract was out of scope for this audit so we are unable to give an assessment in regard to security.
  • The Position will not be opened if the Index's current price is outside of the allowed slippage specified by the user in the open position request.
  • The Position will not be opened if the difference between the total amount of open short and long Positions would exceed the maximum "open difference" value for the collateral token.
  • Users will be minted a pfYDF NFT representing ownership of their Position on the platform.
  • Users may additionally create a "trigger order" for an open Position.
  • A trigger order will close the Position if the index hits a specified target price during "upkeep".
  • 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.
  • Users may close one of their open Positions at any time.
  • Users may initiate closing one of their open Positions at any time by submitting a "close Position request".
  • After a close Position request has been submitted a Relay address may close the Position on the behalf of the requester.
  • The closing user will be returned any remaining collateral after closing fees and losses.
  • Users will be charged two types of closing fees, 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 Position will be put into an "unsettled state" if it resulted in an overall profit and the collateral token is not the main collateral token.
  • Positions that are in the profit and using the main collateral token will receive the collateral and profit when closing.
  • The overall profit for a Position may not exceed the "max profit" factor of the Position's collateral amount. This value defaults to 10 times the collateral amount.
  • The pfYDF NFT representing the Position will be burned.
  • Users may cancel one of their pending open Position requests or close Position requests at any time. Any users may cancel a request if the "pending position request" time has passed.
  • A Relay address may settle an unsettled Position at any time.
  • The Position owner will be transferred the profit from the position in the form of main collateral tokens.
  • Sufficient tokens must be supplied to the contract to pay out profits.
  • Any address may check if "upkeep" is needed for a specified Position. Upkeep is needed if the Position is liquidable, has reached maximum profit, or the current amount of fees would exceed the current return.
  • A Position is considered liquidable if it has reached the "delinquency price" based on its starting price.
  • The Position will also be closed if one of the trigger order prices for the Position has been reached.
  • A Relay 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 the team's own Keepers.
  • The owner may add and remove a token as a valid collateral token at any time.
  • The owner may set the max leverage, up to 250, at any time.
  • The owner may set the max leverage for an individual index, up to 250, at any time.
  • The owner may set the max profit percentage, up to 100%, 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 close and open position fees, up to 10%, at any time.
  • The owner may set the ETH open fee to any value at any time.
  • The owner may set the expiration for pending Position requests, up to 1 hour, at any time.
  • The owner may add and remove an address as a Relay 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 minimum collateral amount for a collateral token at any time.
  • The owner may add and remove 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 update the FeeReducer address at any time.
  • The owner may withdraw all tokens and ETH from the contract at any time.
  • The contract properly accounts for fee-on-transfer tokens where applicable.
PromoYDF Contract:
  • This contract defines the promoYDF token.
  • The max supply of the token is set to 10 million $promoYDF [10,000,000].
  • The owner may mint tokens up to the max supply at any time.
  • Any user may burn their own tokens to reduce the total supply.
  • There are no fees associated with transferring tokens.
  • The owner may set the max supply to any value at any time
  • The contract complies with the ERC-20 token standard.
  • =
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.
NFTMarketplace Contract:
  • This contract is used to list NFTs for sale.
  • Any user may create a "buy it now" listing for an NFT they own.
  • A buy it now listing offers an NFT for sale at a specified amount of ETH or approved ERC-20 tokens.
  • When enabled, any address may purchase an NFT with a buy it now listing.
  • A service fee is taken from the purchase amount and transferred to a Treasury address controlled by the team.
  • An additional royalty will be taken if the NFT conforms to the ERC-2981 royalty standard.
  • Any address may create an "offer" for an NFT at a specified amount of tokens or ETH.
  • An offer for an NFT is valid until the provided expiration time passes. Alternatively, an offer with an expiration time of 0 will never expire.
  • Users are charged an "add offer fee" amount of ETH when creating an offer.
  • Users may edit and remove their offers at any time.
  • When enabled, the owner of an NFT may accept an unexpired offer for the NFT at any time.
  • A service fee is taken from the purchase amount and transferred to a Treasury address controlled by the team.
  • An additional royalty will be taken if the NFT conforms to the ERC-2981 royalty standard.
  • Accepting an offer will remove any existing buy it now listings for the NFT.
  • The owner may toggle the ability to accept offers and buy it now listings at any time.
  • The owner may toggle any token address as valid at any time.
  • The owner may set the Treasury and WETH addresses at any time.
  • The owner may set the service fee, up to 10%, at any time.
  • The owner may set the add offer fee to any value at any time.
  • The owner may withdraw all tokens and ETH from the contract at any time.
otcYDF Contract:
  • This contract defines the otcYDF NFT.
  • otcYDF NFTs are used to represent the ownership of a Package or a Pool in the OverTheCounter contract.
  • When an otcYDF NFT is traded any "buy it now amount" associated with the NFT's package will be disabled.
  • The OverTheCounter address may mint any address an NFT at any time.
  • The OverTheCounter address may burn any user's NFT at any time.
  • The OverTheCounter address may give itself approval for a specified NFT at any time.
  • The owner may update the Royalty address 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 update the OverTheCounter address at any time.
  • The contract implements ERC-2981 functionality that supports the use of Royalties that can be used with NFT marketplaces.
  • The royalty for each contract is taken as a percentage of the sale price based on the "royalty basis points".
OverTheCounter Contract:
  • This contract allows users to create Pools to trade tokens and to sell Packages of various Assets.
  • Any address may create a Pool between two tokens when enabled.
  • Pools allow users to purchase the output tokens the creator supplies to the pool using the input token the creator specifies.
  • Purchases will remain at a static price set by the creator when creating the Pool.
  • Users must ensure that the price is in terms of 18 decimals to ensure correct conversion between the two tokens.
  • A flat "create service fee" amount of ETH is taken when creating a pool and sent to a Treasury address controlled by the team.
  • The Pool creator is minted an otcYDF NFT to represent ownership of the Pool.
  • The Pool creator may optionally specify a "referrer" address.
  • The contract is given approval for the NFT when minted.
  • Any address may use a Pool to swap tokens when enabled. A referrer address may optionally be provided.
  • Users provide a specified amount of the input token and will receive an amount of the output token based on the price set in the Pool.
  • A "pool swap fee" is taken from the input tokens. The fee is split between the "protocol amount" and "referrer amount".
  • The referrer amount is split between the Pool referrer and swap referrer, if they both exist.
  • If only one referrer is defined, the whole referrer amount is sent to whichever referrer is defined.
  • The referrer fee will be sent to the Treasury address if neither referrer is defined.
  • Users may receive a discount on this fee as determined in the FeeReducer contract.
  • The FeeReducer contract was out of scope for this audit so we are unable to give an assessment in regard to security.
  • The owner of a Pool may update the Pool at any time. This allows the owner to update the price, deposit more input tokens, and withdraw the output tokens.
  • The owner of a Pool may remove the Pool at any time.
  • They will receive all collected input tokens and any remaining output tokens.
  • The otcYDF NFT representing ownership of the Pool will be burned.
  • Any address may create a Package consisting of various assets up to the "max assets per package" when enabled.
  • Assets may consist of ERC-20, ERC-721, or ERC-1155 tokens.
  • The creator may optionally provide a referrer address.
  • The owner supplies a specified amount of tokens or the NFT ID. The tokens are then stored in the contract.
  • The creator may optionally specify a "buy it now" asset and amount and an "unlock start time" and an "unlock end time".
  • If a buy it now price has been set the creator may also add an address to the "buy it now whitelist".
  • A flat "create service fee" amount of ETH is taken when creating a Package and sent to a Treasury address controlled by the team.
  • The Package creator is minted an otcYDF NFT to represent ownership of the Package.
  • The contract is given approval for the NFT when minted.
  • The owner of a Package may withdraw Assets from the Package.
  • If the current owner is also the creator of the Package, they may withdraw all of the Assets at any time.
  • If the current owner is not the creator the amount they may withdraw is based on the amount of time elapsed from the last withdraw.
  • If the Package has an unlock start time specified the withdrawal amount begins accumulating at that time.
  • If the Package has no unlock start time the withdrawal amount begins accumulating from the Package's creation time.
  • NFTs may not be withdrawn until the unlock end time has passed if one was set.
  • Any address may create an Offer for a Package when enabled. They may optionally provide a referrer address.
  • Users must pay an "add offer fee" when creating a new Offer.
  • The user may optionally specify an expiration time for the Offer.
  • An Offer with an expiration time of 0 will never expire and must be manually removed.
  • Users may create an Offer in either ETH or an approved ERC-20 token.
  • ETH offers will be converted into WETH.
  • The owner of a Package may accept a non-expired Offer for the Package when enabled. The last withdrawal from the package must be before the offer was created.
  • The owner will receive the amount of tokens offered and the user who created the Offer will become the new owner of the Package.
  • A "buy fee" percentage of the amount of tokens offered will be taken and split the same way as swap fees.
  • Users may receive a discount on this fee as determined in the FeeReducer contract.
  • Any address may purchase a Package with a buy it now price enabled.
  • If the Package has a buy it now whitelist the purchaser must be the whitelisted address.
  • The owner will receive the buy it now amount of the buy it now asset and the purchaser will become the new owner of the Package.
  • A "buy fee" percentage of the buy it now amount will be taken and split the same way as swap fees.
  • Users may receive a discount on this fee as determined in the FeeReducer contract.
  • The purchaser may optionally withdraw all assets currently eligible for withdrawal at the time of the purchase.
  • Users may use this contract's "tradeOTC" functionality to trade ownership of Packages and Pools between each other.
  • Each user must add the other user to the "userOTCTradeWhitelist". When the second user does this the contract will automatically swap the otcYDF NFTs between the users ensuring a fair trade.
  • A "trade OTC" fee is taken when the actual NFT transfer occurs and sent to the Treasury address controlled by the team.
  • The owner of a Package or the user who created the Offer may remove an Offer from a Package at any time.
  • The owner of a Package may update the Package buy it now asset, buy it now amount, and buy it now whitelisted address at any time.
  • The creator of a Package may update the Package unlock start time and unlock end time.
  • The otcYDF address may disable the buy it now option for a Package at any time.
  • The owner may enable and disable the contract at any time.
  • The owner may update the Treasury address at any time.
  • The owner may set the max Assets per package to any value at any time.
  • The owner may set the create service fee and add offer fee to any values at any time.
  • The owner may set the pool swap fee up to 25% at any time.
  • The owner may set the buy fee up to 20% at any time.
  • The owner may set the referrer split up to 100% at any time.
  • The owner may set the trade OTC fee to any value at any time.
  • The owner may add and remove any address from the valid tokens list at any time.
  • The owner may update the FeeReducer address at any time.
  • Fee-on-transfer tokens must exclude this contract from fees in order for Pools and Packages containing the token to function.

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 and ETH from the contract.
  • The Bridge owner may withdraw all tokens from contract.
  • The Bridge owner may set the bridge cost to any amount.
  • The otcYDF owner may set the royalty percentage up to 100%.
  • The OverTheCounter service fee and add offer fee are uncapped.
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 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
Unbounded Loops N/A PASS
Unused Code N/A PASS
Overall Contract Safety   PASS

Contract Source Summary and Visualizations

Name

Address/Source Code

Visualized
(Hover-Zoom Recommended)

YDF Contract

Multichain

Inheritance Chart.  Function Graph.

sYDF Contract

Multichain

Inheritance Chart.  Function Graph.

slYDF Contract

Multichain

Inheritance Chart.  Function Graph.

StakeRewards Contract

Multichain

Inheritance Chart.  Function Graph.

YDFVester Contract

Multichain

Inheritance Chart.  Function Graph.

pfYDF Contract

Multichain

Inheritance Chart.  Function Graph.

PerpetualFutures Contract

Multichain

Inheritance Chart.  Function Graph.

PromoYDF Contract

Multichain

Inheritance Chart.  Function Graph.

slYDFZapper Contract

Multichain

Inheritance Chart.  Function Graph.

Bridge Contract

Multichain

Inheritance Chart.  Function Graph.

NFTMarketplace Contract

Multichain

Inheritance Chart.  Function Graph.

otcYDF Contract

Multichain

Inheritance Chart.  Function Graph.

OverTheCounter Contract

Multichain

Inheritance Chart.  Function Graph.

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 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 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.