Closed yuriy77k closed 4 years ago
Auditing time is 5 days
@MrCrambo assigned
Estimated auditing time is 5 days.
@gorbunovperm assigned
Auditing time is 5 days
@danbogd assigned
Estimated audit time: 6 days
@RideSolo assigned. Please complete audit in 4 days.
My report is finished.
My report is finished.
The contract contains high severity security issues. The developer is informed about it.
EZO Token smart contract security audit report performed by Callisto Security Audit Department
Commit hash e1284e5f8dd773ae9973b0fad3244efac9180513.
In total, 25 issues were reported including:
3 high severity issues.
6 medium severity issues.
5 low severity issues.
4 notes.
7 owner privileges (the ability of an owner to manipulate contract, may be risky for investors).
When a user call transfer
function to take an order deposited through sendToken
:
_valueCal
of EZO tokens to be sent to the order maker is wrong since the value should be equal to the amount of the currency sent multiplied by the currency price then divided by the price of EZO in usd. Multiple errors can be seen,
safeDivv
is used instead of safeDiv
which will divide the result of the multiplication by 1 ether
instead of the ezo price in USD.100
but the price of EZO tokens can be changed by the owner using setEZOTokenPriceUSD
, meaning that 100
should be replaced by ezoTokenPriceUSD
.condition
used to check if the value requested by the function caller is incorrect, the condition should be as follow if(_valueCal > _value) { /* do processing */}
to avoid extra computation if both values are equal.returnAmount
computation is incorrect it should be the difference in USD multiplied by the 10 power the currency decimals then divided by the currency price in USD. sentAmount
should be the _valueCal
in EZO multiplied by EZO token price in USD divided by the currency price in usd, while taking the decimals into account, node of the described steps where taken into account.When using smart swap contract deposit through sendEther
or sendToken
an order is automatically added (addOrder
) and fulfilled (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, check [here]](https://github.com/ridesoloAudit/ezo-token/blob/e1284e5f8dd773ae9973b0fad3244efac9180513/ezotoken/contracts/SmartSwap.sol#L220#L225).
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 against 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 fulfilled and and their deposit might be spent, blocking them from using cancelOrder
.
In the function checkStability
there is chance that the returnCurrencyAmount
will be equal the remainingAmountNewOrder
but this condition is unhandled, so in this case the function will be revert. The function generalFundAssign
that transfer funds will not work for this user.
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 following conversion operation might be wrong, since the token decimals are not taken into account directly inside the code, the token decimals value can be integrated with the price in usd however we cannot confirm (this issue should be confirmed with the developers)
The owner is responsible of setting the tokens prices using setCurrencyPriceUSD
however it is not possible to set all the tokens that exist on the blockchain, meaning that the tokens addresses not set by the owner should not be allowed for deposit using sendToken
. This will just constrain the users to cancel their order or give a bad user experience to other users if they want to take that order using transfer
since the transaction will just throw because of [dividing by zero]().
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.
To create the uniqueId needed in the contract logic, the developers can use a hashing function with a pack of some unique variables that cannot be recreated twice and save the value
and sender
variables in a mapping.
In the ERC-20 standard should be approve, transferFrom functions and event Approval, but here they are missing.
The transfer function in EZO is not ERC20 compliant as it stands. From the ERC20 standard: “Note Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event”. This function has a require statement that causes execution to revert if value is greater than zero.
According to ERC20 standard, when initializing a token contract if any token value is set to any given address a transfer event should be emitted.
The burn function in EZOToken.sol will not let users burn all of their tokens because of the fourth require statement, which prevents users from decreasing their balance to zero by using the burn function.
setCurrencyPriceUSD
function role is to set the tokes reference value, _currency
and _price
arrays should be of equal length, a require must be added to check that condition.
In function addAllowedAddress
there is no zero address checking.
Add into a function transfer(address _to, ... )
following code:
require( _to != address(this) );
Naming on SafeMath
library is leading to confusion when using safeMull
, safeMul
, safeDiv
and safeDivv
making the code readability more complex and prone to errors.
When depositing ether or tokens a new PurchaseData
contract is deployed making the transaction cost more expensive and not optimized.
Under burn function we see wrong comment "Function will create new tokens and assign to investor's address".
Mappings allowed and allowedToBurn are created but never used.
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".burn
tokens from any address.mint
tokens from any address using addAllowedAddress
updateTxStatus
and block the user fund for a specific transaction.halt()
function.The audited smart contract must not be deployed. Reported issues must be fixed prior to the usage of this contract.
https://gist.github.com/RideSolo/6ecbd3224e5d808e40338746a252f2c9
https://gist.github.com/gorbunovperm/5305cb96a2d85e42b77db4c79b120de6
https://gist.github.com/MrCrambo/f9499804a579df9fb10611079e5f4776
https://gist.github.com/danbogd/bc4d72f3d20c7b87d83f56c42af91e35
Audit request
Element Zero - Smart Swap Contract. Documentation attached.
Element Zero - Smart Swap Blockchain Document (4).docx
Source code
https://github.com/ezo-network/ezo-token/tree/master/ezotoken/contracts
Disclosure policy
Standard disclosure policy.
Contact information (optional)
kyle@jointer.io
Platform
ETH
Budget
5.695 Ether