EVEOTC

Smart Contract Audit Report

Audit Summary

EVEOTC Audit Report EVEOTC allows users to sell tokens through a smart trade with the ability to use dynamic market pricing with discounts and premiums or an options trade with a time limit and strike price.

For this audit, we reviewed the project team's EVEOTC contract at 0xc5A179F59b25e12687cB349a8BF8f87Bb75dc952 on the Ethereum Testnet.

Audit Findings

All findings have been resolved, though some centralized aspects are present.
Date: January 19th, 2023.
Updated: January 20th, 2023 with resolutions to Findings.

Finding #1 - EVEOTCTokens - Low (Resolved)

Description: The addToken() and addUserToken() functions allows tokens to be added with no pricing mechanisms set.
Risk/Impact: The getUSDPrice() function would return 0 and the tokens would have no value in the platform.
Recommendation: The addToken() function should require at least 1 pricing mechanism is set. The addUserToken() should require that the manual_entry_price is not 0.
Resolution: System and User tokens cannot be added without a price or pricing mechanism set.

Finding #2 - EVEOTCTokens - Low (Resolved)

Description: The dangerouslyWithdrawFundsShouldBeUsedOnlyToPreserveAndProtectCustomersFunds() function allows the owner to withdraw all tokens from the contract, including user deposits.
Risk/Impact: If ownership is transferred to an untrustworthy address or the owner's wallet is compromised all funds may be lost.
Recommendation: The team should remove this function and instead pause the contract in case of emergency. This will require removing the isPaused modifier from the cancelTrade() function so users can cancel their trades to withdraw funds in case of an emergency.
Resolution: The dangerouslyWithdrawFundsShouldBeUsedOnlyToPreserveAndProtectCustomersFunds() function has been removed and the cancelTrade() function is no longer restricted to isNotPaused.

Finding #3 - EVEOTC - Informational (Resolved)

Description: The addToken() function uses the isOwner modifier when it calls the EVEOTCTokens addToken() function which also uses the isOwner modifier.
Recommendation: The isOwner modifier should be removed from the EVEOTC addToken() function or alternatively the EVEOTCTokens addToken() function should be made internal to save on gas costs on each function call.
Resolution: The team has implemented the solution described above.

Finding #4 - EVEOTCTokens - Informational (Acknowledged)

Description: The contract uses an "index + 1" based system to track tokens and whether they have already been added.
Recommendation: The team should consider using a mapping (address => bool) tokenExists mapping to track whether a token exists. This would result in less operations to find tokens and more straightforward code.
Resolution: The team has chosen to maintain the current implementation.

Finding #5 - EVEOTC - Informational (Resolved)

Description: The getPurchasedWithdrawableTokens() function uses the trades[smart_trades_purchases[_purchased_index]offer_index].time value multiple times within the function.
Recommendation: The team should store the trades[smart_trades_purchases[_purchased_index]offer_index].time value into a variable to save on gas costs on each function call.
Resolution: The team has implemented the solution described above.

Finding #6 - EVEOTC - Informational (Resolved)

Description: The validateOptionTrade() function uses the option_trades_purchases[_purchase_index] structure multiple times within the function.
Recommendation: The team should store the option_trades_purchases[_purchase_index] structure into a variable to save on gas costs on each function call.
Resolution: The team has implemented the solution described above.

Contracts Overview

  • The contracts utilize ReentrancyGuard to protect against reentrancy attacks in applicable functions.
  • As the contracts are implemented with Solidity v0.8.12, they are safe from any possible overflows/underflows.
EVEOTCTokens Contract:
  • This contract is used to manage tokens and token pricing.
  • Tokens can be either a System token or a User token.
  • System tokens are added by the team whereas User tokens can be added by any user.
  • System token pricing is determined by either a Chainlink Aggregator, a custom Chainlink Oracle, or a "manual entry price".
  • When fetching a System token's price the Chainlink Oracle is prioritized, if one has been set.
  • The Chainlink Oracle was out of scope so we cannot give an assessment in regard to security.
  • A Chainlink Aggregator is prioritized next if the Chainlink Oracle has not been set but a Chainlink Aggregator has been set.
  • The manual entry price is used if neither a Chainlink Oracle or Aggregator has been set.
  • User token pricing is only determined by the "manual entry price".
  • Any address may add a new User token at any time.
  • User tokens are not enabled by default and must be enabled by the owner.
  • The creator of a User token may set the "manual entry price" of the token at any time.
  • The owner may add a new System token at any time. System tokens are automatically enabled when added.
  • The owner may update the creator of a User token to any address at any time.
  • The owner may update the manual entry price of any System token and User token at any time.
  • The owner may enable and disable any System token and User token at any time.
  • The owner may set the Oracle API address at any time.
EVEOTC Contract:
  • This contract allows users to sell tokens through "smart trades" or "options trades".
  • Any address may add a smart trade offer or an options trade offer for any enabled token at a specified price when the contract is not paused.
  • A smart trade offer with a price of 0 will calculate the current market value as the price.
  • Users may also specify a discount or additional premium from the offer price.
  • The accepted payment tokens for the Trade must also be enabled.
  • Users must provide a "surplus" amount of the tokens being sold to cover commission costs.
  • The commission will vary between a smart trade and an options trade.
  • Users may receive a discount on the commission determined in the Staking contract.
  • The Staking contract was out of scope for this audit so we cannot provide an assessment in regard to security.
  • The tokens being sold in addition to the surplus tokens are stored within the contract.
  • Users may cancel a trade when the contract is not paused. They will receive any remaining tokens from the trade.
  • Any address may purchase tokens from a smart trade when the contract is not paused.
  • The purchase is made at the trade's price if one was specified.
  • If the user elected to not define a price the current market value will be fetched using the corresponding method in the EVEOTCTokens contract.
  • The price of the payment token is also determined using the corresponding method in the EVEOTCTokens contract.
  • The total payment is transferred to the smart trade creator.
  • An "admin commission" of the sale tokens is taken from the supplied surplus tokens based on the sale amount and transferred to the owner wallet address.
  • An additional "buy commission" is taken from the payment tokens and transferred to the owner wallet address.
  • The smart trade will become inactive once all tokens have been sold.
  • Users will be able to withdraw purchased tokens over time based on the smart trade's total vesting time when the contract is not paused.
  • Any address may pay the "premium" for an options trade when the contract is not paused.
  • Paying the premium reserves users a specified amount of the token being sold.
  • Users may then "pay the option" within the grace period from the options trade's expiration time when the contract is not paused.
  • The user will then be able to purchase the previously specified amount of tokens at the option trade's price.
  • The value of the tokens being used to purchase will be fetched using the corresponding method in the EVEOTCTokens contract.
  • A "trade commission" of the sale tokens is taken based on the sale amount and transferred to the owner wallet address.
  • Users may receive a discount calculated in the Staking contract.
  • The entire amount of tokens bought in an options trade is immediately transferred to the purchaser.
  • The owner may set the grace period to any value at any time.
  • The owner may add a System token at any time. Adding a token through this contract will automatically set the token's price.
  • The owner may update the Staking contract address at any time.
  • The owner may pause and unpause the contract at any time.
  • The owner may withdraw all tokens from the contract at any time.
  • The owner may set the smart trade buy and sell commission and the options trade buy and sell commission up to 100% at any time.
  • The owner may update the owner wallet address at any time.
  • The team must exercise caution when adding allowed tokens to the EVEOTC contract to avoid using fee-on-transfer tokens.

Audit Results

Vulnerability Category Notes Result
Arbitrary Jump/Storage Write N/A PASS
Centralization of Control
  • The owner may enable and disable valid tokens.
  • The owner may update the manual entry price of any token.
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 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

Inheritance Chart

Smart Contract Audit - Inheritance

Function Graph

Smart Contract Audit - Graph

Functions Overview


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public

 + [Int] AggregatorV3Interface 
    - [Ext] decimals
    - [Ext] description
    - [Ext] version
    - [Ext] getRoundData
    - [Ext] latestRoundData

 +  Owner 
    - [Pub] Constructor #
    - [Pub] changeOwner #
       - modifiers: isOwner
    - [Pub] getOwner

 +  ReentrancyGuard 
    - [Pub] Constructor #

 + [Int] IERC20 
    - [Ext] decimals
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Int] IEVEOTCStakes 
    - [Ext] getSmartDiscount
    - [Ext] getOptionDiscount

 +  EVEOTCTokens (Owner, ReentrancyGuard)
    - [Pub] Constructor #
       - modifiers: Owner
    - [Ext] token_indexes
    - [Ext] user_token_indexes
    - [Ext] rootSet #
       - modifiers: isOwner
    - [Pub] addToken #
       - modifiers: isOwner
    - [Ext] changeTokenStatus #
       - modifiers: isOwner
    - [Ext] addUserToken #
    - [Ext] setUserTokenPrice #
    - [Ext] changeUserTokenStatus #
       - modifiers: isOwner
    - [Ext] changeTokenPrice #
       - modifiers: isOwner
    - [Ext] changeUserTokenOwner #
       - modifiers: isOwner
    - [Pub] getColdUSDPrice
    - [Int] getUSDPrice #
    - [Ext] forceGetUSDPrice #
       - modifiers: isOwner
    - [Pub] getAggregatorUSDPrice
    - [Int] getAPIUSDPrice #

 +  EVEOTC (EVEOTCTokens)
    - [Pub] Constructor #
       - modifiers: EVEOTCTokens
    - [Pub] commissionSet #
       - modifiers: isOwner
    - [Ext] stakingContractSet #
       - modifiers: isOwner
    - [Ext] trades_to_query
    - [Ext] trades_length
    - [Pub] surplus
    - [Pub] addToken #
       - modifiers: isOwner
    - [Ext] addOffer #
       - modifiers: nonReentrant,isNotPaused
    - [Ext] cancelTrade #
       - modifiers: nonReentrant,isNotPaused
    - [Int] validateTrade
    - [Int] calculateTotalPayment
    - [Ext] estimateSmartTrade
    - [Ext] buySmartTrade #
       - modifiers: nonReentrant,isNotPaused
    - [Pub] getPurchasedWithdrawableTokens
    - [Ext] getPurchasedTokens #
       - modifiers: nonReentrant,isNotPaused
    - [Int] getCommissionBuySender
    - [Ext] setGracePeriod #
       - modifiers: isOwner
    - [Ext] estimatePremiumAmount
    - [Ext] estimateOptionTrade
    - [Ext] payPremium #
       - modifiers: nonReentrant,isNotPaused
    - [Int] validateOptionTrade
    - [Ext] payOptionTrade #
       - modifiers: nonReentrant,isNotPaused
    - [Pub] pause #
       - modifiers: isOwner
    - [Pub] unpause #
       - modifiers: isOwner
    - [Ext] dangerouslyWithdrawFundsShouldBeUsedOnlyToPreserveAndProtectCustomersFunds #
       - modifiers: isOwner

 +  OTCChainLinkOracle 
    - [Pub] refreshAPIUSDPrice #

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.