CertiK reviewed EML (EML Token) on 13 Jun 2023: 15 findings, 0 critical; 3 marked fixed, 3 acknowledged, 9 open.
Report hosted on skynet.certik.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 2 | 0 |
| Medium | 0 | 1 | 0 |
| Low | 9 | 0 | 3 |
### Token_Factory.sol #### _owner In the contract `TokenFactory` the role `_owner` has authority over the functions shown in the diagram and list below. * createProxy() - Create new token proxy contract Any compromise to the `_owner` account may allow the hacker to take advantage of this authority to create new proxy token contracts.  ### Token_Implementation.sol #### _burners In the contract `TokenImplementation` the role `_burners` has authority over the functions shown in the diagram and list below. * burn() - Burn tokens Any compromise to the `_burners` account may allow the hacker to take advantage of this authority to burn tokens.  #### _lockers In the contract `TokenImplementation` the role `_lockers` has authority over the functions shown in the diagram and list below. * updateVestingLock() - Update an existing vesting lock for an account * vestedTransfer() - Create a transfer and then create a vesting lock over those tokens * batchVestedTransfer() - Create a multiple transfers and then create a vesting lock over each of those transfer amounts * batchTimeLockedTransfer() - Create a multiple transfers and then create a time lock over each of those transfer amounts * lockedTransfer() - Create a transfer and then create a time lock over those tokens * addTimeLock() - Create a new time lock on account tokens * addVestingLock() - Create a new vesting lock on account tokens Any compromise to the `_lockers` account may allow the hacker to take advantage of this authority to control the locking of tokens.  #### _owner In the contract `TokenImplementation` the role `_owner` has authority over the functions shown in the diagram and list below. * unpause() - Unpause contract to reactivate certain functions * addLocker() - Add locker role * removeLocker() - Remove locker role * recoverToken() - Send tokens from contract to owner * pause() - Pause contract to disable certain functions * removeBurner() - Remove burner role * freeze() - Freeze account to disable account functionality * addBurner() - Add burner role The following are functions that the `_owner` role can run since `TokenImplementation` extends `OwnableUpgradeable`. * transferOwnership() - Transfer contract ownership to another address * renounceOwnership() - Give up contract ownership Any compromise to the `_owner` account may allow the hacker to take advantage of this authority to control/restrict contract and account functionality and add privileged authorizations.   #### _supervisor In the contract `TokenImplementation` the role `_supervisor` has authority over the functions shown in the diagram and list below. * unfreeze() - Unfreeze account to reenable account functionality * transferSupervisorOwnership() - Transfer supervisor role * renounceSupervisorOwnership() - Give up supervisor role * removeVestingLock() - Remove a vesting lock for an account * removeTimeLock() - Remove time lock for certain amount of account’s tokens Any compromise to the `_supervisor` account may allow the hacker to take advantage of this authority to restore account functionality and remove token locks. 
All EML tokens are sent to the contract owner when deploying the contract. This is a potential centralization risk as the owner can distribute EML tokens without the consensus of the community. The token is already deployed on the Ethereum mainnet and the following link shows the top token holder balances: [https://etherscan.io/token/0x03dde9e5bb31ee40a471476e2fccf75c67921062#balances](https://etherscan.io/token/0x03dde9e5bb31ee40a471476e2fccf75c67921062#balances). The addresses are as follows: 1. 0x0cBeB1c3cAc0BD1EFaCAe164342cb535bdAe931c 2. 0x2DbE49882Fa742A5DEc0fd5b7842643636BE4118 3. 0x219C8A930879575F739206e899468beDe4b56baD 4. 0xba038dB66D4F5AcB9328518CE16519c19910c696 5. 0xdc30E4862AfE00eB835d5d06dc1955bc799e34d5 6. 0xCB82131FeadE6dddD7BA4744Ff8Fe8c8c8012252 7. 0x321C3cCede20F02a7f9d9e34CAd6834b07D4217d The following transactions show that the top token holders were all transferred tokens from the token owner contract: 1. [https://etherscan.io/token/0x03dde9e5bb31ee40a471476e2fccf75c67921062?a=0x9bda9e70fdbf0d9cbab1db1d3ecafcfe084b412f](https://etherscan.io/token/0x03dde9e5bb31ee40a471476e2fccf75c67921062?a=0x9bda9e70fdbf0d9cbab1db1d3ecafcfe084b412f) 2. [https://etherscan.io/token/0x03dde9e5bb31ee40a471476e2fccf75c67921062?a=0x321c3ccede20f02a7f9d9e34cad6834b07d4217d](https://etherscan.io/token/0x03dde9e5bb31ee40a471476e2fccf75c67921062?a=0x321c3ccede20f02a7f9d9e34cad6834b07d4217d)
Checks should be made to ensure that the vesting and time lock amounts are not greater than the leftover unlocked balance. Lack of these checks can lead to locked balances greater than the overall balance of the user and cause all transactions for that user to revert. In function `Lockable._updateVestingLock()` there is only a check to ensure that the input amount is greater than 0, however this is not enough to prevent issues from occurring since there is no upper limit to the amount that can be input in the `amount` parameter. ```solidity=326 require(amount > 0, "VestingLock: amount is 0"); ``` In function `Lockable._addTimeLock()` there is only a check to ensure that the input amount is greater than 0, however this is not enough to prevent issues from occurring since there is no upper limit to the amount that can be input in the `amount` parameter. ```solidity=222 require(amount > 0, "TimeLock: lock amount is 0"); ``` In function `TokenImplementation.addVestingLock()` there is a check to ensure that the value of `amount` is both greater than 0 and is under the total token balance of the account. ```solidity=551 require(amount > 0 && balanceOf(account) >= amount, "VestingLock: amount is 0 or over balance"); ``` For all transfers, the `_beforeTokenTransfer()` will be run to run a series of checks before the transfers occur. If the total locked amount (`getAllLockedAmount(from)`) is greater than the `balanceOf(from)`, all transfers for the user will fail even if the user has unlocked tokens. ```solidity=440 if (from != address(0)) require(balanceOf(from) - getAllLockedAmount(from) >= amount, "Lockable: insufficient transfer amount"); ```
| Address | Chain | Source code |
|---|---|---|
| 0x03dd…10620x03dde9e5bb31ee40a471476e2fccf75c67921062 | Chain: Ethereum | Source code: Verified source |
1,044 projects reviewed · 1,375 reports · latest May 2025
See CertiK’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us