This document is a security audit report performed by RideSolo, where EZO Token V2 has been reviewed.
- CurrrencyPrices.sol github commit hash bcac99702f0af1832aaa97bc7a5562ed2d98f58c.
- EZOToken.sol github commit hash bcac99702f0af1832aaa97bc7a5562ed2d98f58c.
- SmartSwap.sol github commit hash ee918152d177f8dcee02a76431bdace3b5647878.
- secureETH.sol github commit hash c5acacdc8416e7da858b3460a0ec1f52539abd3a
** 13 issues** were reported including:
- 6 high severity issues.
- 2 medium severity issues.
- 2 low severity issues.
- 3 Owner privileges.
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 totokenBalancesForEZO[address(0)]
but when withdrawing it using_withdrawEther
requires the balance of the contract to be higher thantokenBalancesForEZO[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.
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.
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.
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.
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.
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)
);
}
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).
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.
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.
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.
- It is possible to double withdrawal attack. More details here
- 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
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.
The audited contracts are unsafe and should not be deployed due to multiple high severity. User funds are at risk.