Skip to content

Instantly share code, notes, and snippets.

@RideSolo
Last active March 21, 2020 00:51
Show Gist options
  • Save RideSolo/93fa7a343dc8b7e3c05ed969de963a5a to your computer and use it in GitHub Desktop.
Save RideSolo/93fa7a343dc8b7e3c05ed969de963a5a to your computer and use it in GitHub Desktop.

EZO Token V2 Audit Report.

1. Summary

This document is a security audit report performed by RideSolo, where EZO Token V2 has been reviewed.

2. In scope

  • CurrrencyPrices.sol github commit hash bcac99702f0af1832aaa97bc7a5562ed2d98f58c.
  • EZOToken.sol github commit hash bcac99702f0af1832aaa97bc7a5562ed2d98f58c.
  • SmartSwap.sol github commit hash ee918152d177f8dcee02a76431bdace3b5647878.
  • secureETH.sol github commit hash c5acacdc8416e7da858b3460a0ec1f52539abd3a

3. Findings

** 13 issues** were reported including:

  • 6 high severity issues.
  • 2 medium severity issues.
  • 2 low severity issues.
  • 3 Owner privileges.

3.1 SmartSwap & SecureETH mint

Severity: high

Description

Following the description provided by the team about the usege of SecureETH contract:

  • "To allow users to freeze the value of their Ether instantly. So in volatile times, they hit freeze / secure contract and the value stays"

The impelmentation of SecureETH does not protect users from volatility in any way:

  • Users that will deposit ether through _sendEther will most probably lose their ether, since the deposited ether is added to tokenBalancesForEZO[address(0)] but when withdrawing it using _withdrawEther requires the balance of the contract to be higher than tokenBalancesForEZO[address(0)], except if the owner deposit ether through the fallback function.
  • Another issues is that the ether can be taken by someone swapping tokens against ether as described in "Smart Swap Deposit" issue.
  • In case of price drop, the owner is required to deposit even more ether to cover the price volatility.

Code snippet

https://github.com/ridesoloAudit/ezo-token/blob/d4c4f023597214f31b0e01052fd41e6a3db3d0e0/ezotoken/contracts/SmartSwap.sol#L327#L334

https://github.com/ridesoloAudit/ezo-token/blob/d4c4f023597214f31b0e01052fd41e6a3db3d0e0/ezotoken/contracts/SmartSwap.sol#L336#L353

https://github.com/ridesoloAudit/ezo-token/blob/d4c4f023597214f31b0e01052fd41e6a3db3d0e0/ezotoken/contracts/SmartSwap.sol#L362

3.2 Transfer Computation

Severity: high

Description

Both returnAmount and sentAmount calculation assumes that the EZO price is fixed to 100 USD, however CurrencyPrices(currencyPricesContract).currencyPrices(address(this)) was used when computing _valueCal, all calculation should reflect the same price.

3.3 Smart Swap Deposit

Severity: high

Description

When using smart swap contract deposit through sendEther or sendToken an order is automatically added (addOrder) and fullfilled (generalFundAssign, generalFundAssignEZO), if the wanted currency balance in the smartswap contract is higher than what the user is requesting and the deposited currency is ezo tokens.

A user that deposited tokens or ether previously might not be able to withdraw his deposit since it can be swapped with other users deposit that deposited ezo tokens even if his wanted currency and sent currency are different than ezo tokens, check here

Users that deposit tokens to swap them agains EZO will be automatically accredited newly minted tokens to their account, the deposited tokens will be kept inside the contract, check here

This logic need a balanced deposit between all tokens otherwise some users orders might not be fullfilled and and their deposit might be spent, blocking them from using cancelOrder.

3.4 EZO Deposit

Severity: high

Description

When cancelling an order generalFundAssign is used to refund the user tokens or ether, if the deposited tokens through sendToken are EZOs, instead of sending the tokens back to the user using assignTokens with the sender address equal to the EZO contract address, the developers used mint function which will create new tokens. The deposited EZO tokens will be frozen inside the contract making the token supply higher, an attacker can repeatedly deposit/cancel to make the total supply higher just to hurt the project. Please note that no max cap is setting when minting.

3.5 Rate Conversion

Severity: High

Description

The conversion operation in getCalValue is wrong:

  • It supposes that all the tokens have decimals equal to 18 (1 ether).
  • The value to be converted is multiplied by a truncated value, resulting in wrong return value. Check recoomendation for more details.

Recommendation

	function getCalValue(uint256 returnCurrencyAmount, uint256 remainingAmountNewOrder,address _currencySent,address _currencyWant) internal view returns(uint256)
	{
        return safeDiv(
            safeMul(
                safeDiv(
                    safeMul(
                        safeSub(returnCurrencyAmount,remainingAmountNewOrder), 
                        10**CurrencyPrices(currencyPricesContract).currencyDecimal(_currencySent), 
                    10**CurrencyPrices(currencyPricesContract).currencyDecimal(_currencyWant), 
                CurrencyPrices(currencyPricesContract).currencyPrices(_currencySent)
                , 
            CurrencyPrices(currencyPricesContract).currencyPrices(_currencyWant)
        );
	}

3.6 SecureETH Gas Limit

Severity: high

Description

burn function implemented in SecureETH requires the user address to be whitelisted in allowedForBurningTokens. allowedForBurningTokens is an array and to check if a user is whitelisted isAllowed modifier iterates over the array, when a simple mapping can be used to get the value directly.

This issue will cause high gas consumption, untill the contract will become unusable (following the array length).

Code snippet

https://github.com/ridesoloAudit/ezo-token/blob/d4c4f023597214f31b0e01052fd41e6a3db3d0e0/ezotoken/contracts/secureETH.sol#L163#L182

3.7 Transfer Return Value

Severity: medium

Description

When _uniqueId is equal to systemAddress the return value of the transfer function should be set to true, since it is a valid transaction, however the function will return false. Developers must simplty add a return statement here.

3.8 ERC 20 Compliance

Severity: medium

Description

Depending on the intention of the developers, the transfer function is not ERC20 compatible and users won't be able to transfer EZO tokens following the normal ERC20 rules.

3.9 SecureETH ERC20 Compliance

Severity: low

Description

SecureETH contract inherit from IERC20 interface but do not impelment the ERC-20 functions following the standard, the developers should define the usage of such contract to allow us to conclude the risk related with it.

Code snippet

https://github.com/ridesoloAudit/ezo-token/blob/d4c4f023597214f31b0e01052fd41e6a3db3d0e0/ezotoken/contracts/secureETH.sol

3.10. Known vulnerabilities of ERC-20 token

Severity: low

Description

  1. It is possible to double withdrawal attack. More details here
  2. Lack of transaction handling mechanism issue. WARNING! This is a very common issue and it already caused millions of dollars losses for lots of token users! More details here

3.11 Owner Privileges

Severity: high

Description

Please note that most function marked with "onlyOwner" can either remove trust that the blockchain technology enforce between users and developers or can be hacked in case if the private key is stolen.

  • setCurrencyPriceUSD allow the contract owner to set any currency value, instead decentralized oracle can be used such as "chainlink".
  • Owner can whitlist any address allowing it to burn and mint tokens from any address using addAllowedAddress
  • Owner can updateTxStatus and block the user fund for a specific transaction.

4. Conclusion

The audited contracts are unsafe and should not be deployed due to multiple high severity. User funds are at risk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment