Skip to content

Instantly share code, notes, and snippets.

@danbogd
Last active December 5, 2019 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danbogd/114297162d13b70df00d33eddc76f849 to your computer and use it in GitHub Desktop.
Save danbogd/114297162d13b70df00d33eddc76f849 to your computer and use it in GitHub Desktop.

LCX2 audit report.

1. Summary

This document is a security audit report performed by danbogd, where LCX2 has been reviewed.

2. In scope

Сommit hash 1021bf8e087d1c3bd56ddc9f7f117e5d94a727ca.

3. Findings

In total, 5 issues were reported including:

  • 0 medium severity issues
  • 3 low severity issues
  • 2 owner privileges (ability of owner to manipulate contract, may be risky for investors).
  • 0 notes.

No critical security issues were found.

3.1. No checking for zero address

Severity: low

Description

Incoming addresses should be checked for an empty value(0x0 address).

Code snippet

https://github.com/tech-lcx/LCX-Smart-Contract/blob/1021bf8e087d1c3bd56ddc9f7f117e5d94a727ca/vestingToken.sol#L229

3.2. Owner Privileges

Severity: owner previliges

Description

Contract owner allow himself to:

Upgrade the token contract and implement any logic in the new contract:
        function setTokenAddress(IERC20 token) public onlyOwner returns(bool){
        LCXToken = token;
        return true;
    }      

    Revoke the vesting, and take users tokens for himself even if the tokens were bought by the users using ETH or a different asset.

        function revoke(address account) public onlyOwner {
        VestedToken storage vested = vestedUser[account];
        require(!vested.revoked);
        uint256 balance = vested.totalToken;
        uint256 vestedAmount = _vestedAmount(account);
        uint256 refund = balance.sub(vestedAmount);
        require(refund > 0);
        vested.revoked = true;
        vested.totalToken = vestedAmount;
        LCXToken.safeTransfer(owner(), refund);
        emit VestingRevoked(account);
    }

3.3. Bypassing Smart Contract Timelocks

Severity: low

Description

There are no checks that the beneficiary address can be a contract address.

Example:

The user was able to divest himself of his interest even though the tokens never moved. He didn’t sell the timelocked tokens itself. He sold the future ownership of the tokens. The user is asked by the deployer of the LCX vesting contract for the address where he’d like to receive his tokens after the releaseTime expires in 3 years. User deploys the “Bypasser” contract and gives its address to the deployer of the LCX vesting contract. The Bypasser contract didn’t magically make the timelocked tokens transferable — it made the future ownership of the timelocked tokens transferable.

More details here.

Code snippet

https://github.com/tech-lcx/LCX-Smart-Contract/blob/1021bf8e087d1c3bd56ddc9f7f117e5d94a727ca/vestingToken.sol#L287-L298

         function _setVesting(address account, uint256 amount, uint256 cliff, uint256 duration, uint256 startAt) internal {
         require(account!=address(0));
         require(cliff<=duration);
         VestedToken storage vested = vestedUser[account];
         vested.cliff = cliff;
         vested.start = startAt;
         vested.duration = duration;
         vested.totalToken = amount;
         vested.releasedToken = 0;
         vested.revoked = false;
         }

3.4. Known vulnerabilities of ERC-20 token

Severity: low

Description

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.

Recommendation

Add the following code to the transfer(_to address, ...) function:

require( _to != address(this) );

4. Conclusion

The review did not show any critical issues, some of low severity issues were found.

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