Ccswap Security Assessment

Page created by Tina Klein
 
CONTINUE READING
Security Assessment

ccswap
May 7th, 2021
ccswap Security Assessment

Summary
This report has been prepared for ccswap smart contracts, to discover issues and vulnerabilities in the
source code of their Smart Contract as well as any contract dependencies that were not part of an officially
recognized library. A comprehensive examination has been performed, utilizing Manual Review and Static
Analysis techniques.

The auditing process pays special attention to the following considerations:

      Testing the smart contracts against both common and uncommon attack vectors.
      Assessing the codebase to ensure compliance with current best practices and industry standards.
      Ensuring contract logic meets the specifications and intentions of the client.
      Cross referencing contract structure and implementation against similar smart contracts produced
      by industry leaders.
      Thorough line-by-line manual review of the entire codebase by industry experts.

The security assessment resulted in findings that ranged from critical to informational. We recommend
addressing these findings to ensure a high level of security standards and industry practices. We suggest
recommendations that could better serve the project from the security perspective:

      Enhance general coding practices for better structures of source codes;
      Add enough unit tests to cover the possible use cases given they are currently missing in the
      repository;
      Provide more comments per each function for readability, especially contracts are verified in public;
      Provide more transparency on privileged activities once the protocol is live.
ccswap Security Assessment

Overview
Project Summary

Project Name            ccswap

Platform                Ethereum

Language                Solidity

Codebase                https://github.com/ccswap/contract_review

Commits                 3078f831e01cc2afe98923119beff1989c26047d

Audit Summary

Delivery Date           May 07, 2021

Audit Methodology       Manual Review, Static Analysis

Key Components

Vulnerability Summary

Total Issues            19

  Critical              0

  Major                 2

  Medium                0

  Minor                 3

  Informational         14

  Discussion            0
ccswap Security Assessment

Audit Scope

ID    file                    SHA256 Checksum

CCT   CCToken_flat.sol        abd3e90f0f55432488e1654e497120202157fb2126085b8cd349f02f2541baf0

MCV   MasterChefV2.sol       2e9a17053d4971b8e15f4f59ea12050ac4cdcac6c7fa1f98fae6ab41c692d95d

MCK   Migrator_flat.sol       6679ba4dc3d730782c2c9c0a052dfd83a7513ad585b481a0dd1d41c60fa159e5

TTL   TeamTimeLock_flat.sol   0a6760f35d48a44b6b787f45f59ee2faa7a6a30b828313fe40fe010a7cb2e910
ccswap Security Assessment

Findings

                                                              Critical              0 (0.00%)
                                                              Major                2 (10.53%)

                                19                            Medium
                                                              Minor
                                                                                    0 (0.00%)
                                                                                   3 (15.79%)
                            Total Issues
                                                              Informational       14 (73.68%)

                                                              Discussion            0 (0.00%)

ID       Title                                            Category            Severity            Status

CCT-01   Proper Usage of public and external type         Coding Style          Informational        Acknowledged

                                                          Language
CCT-02   Unlocked Compiler Version Declaration                                  Informational        Acknowledged
                                                          Specific

MCC-01   Proper Usage of public and external type         Coding Style          Informational        Acknowledged

                                                          Language
MCC-02   Unlocked Compiler Version Declaration                                  Informational        Acknowledged
                                                          Specific

MCK-01   Proper Usage of public and external type         Coding Style          Informational        Acknowledged

MCK-02   Lack of Input Validation                         Volatile Code         Minor                Resolved

MCK-03   Pair Creation With Zero Migration Balance        Gas Optimization      Informational        Acknowledged

                                                          Language
MCK-04   Unlocked Compiler Version Declaration                                  Informational        Acknowledged
                                                          Specific

MCK-05   Potential Front-Running For Migration Blocking   Control Flow          Major                Acknowledged

MCV-01   Proper Usage of public and external type         Coding Style          Informational        Acknowledged

MCV-02   Missing Some Important Checks                    Volatile Code         Minor                Acknowledged

MCV-03   add() Function Not Restricted                    Volatile Code         Minor                Acknowledged

MCV-04   Missing Emit Events                              Gas Optimization      Informational        Acknowledged

MCV-05   Array Index Out of Bound                         Volatile Code         Informational        Acknowledged
ccswap Security Assessment

ID       Title                                            Category           Severity            Status

         Take startBlock into Consideration in
MCV-06                                                    Logical Issue        Informational        Acknowledged
         getMultiplier()

MCV-07   Boolean Equality                                 Gas Optimization     Informational        Acknowledged

MCV-08   Potential Front-Running For Migration Blocking   Control Flow         Major                Acknowledged

TTL-01   Proper Usage of public and external type         Coding Style         Informational        Acknowledged

                                                          Language
TTL-02   Unlocked Compiler Version Declaration                                 Informational        Acknowledged
                                                          Specific
ccswap Security Assessment

CCT-01 | Proper Usage of                  public   and    external   type

 Category   Severity           Location                                                               Status

 Coding                        CCToken_flat.sol: 397, 414, 440, 448, 459, 477, 495, 514, 688, 697,
               Informational                                                                             Acknowledged
 Style                         1256, 1264, 1269, 1282

Description
“public” functions that are never called by the contract should be declared “external” . When the inputs are
arrays, “external” functions are more efficient than “public” functions.

Examples:

Functions like : renounceOwnership() , transferOwnership() , add() , set() , setMigrator() ,
MasterChef.migrate() , deposit() , withdraw() , emergencyWithdraw() , setPause() ,

Migrator.migrate() , symbol() , decimals() , transfer() , allowance() , approve() , transferFrom() ,

increaseAllowance() , decreaseAllowance() , renounceOwnership() , transferOwnership() ,

addMinter() , delMinter() , getMinter() , getBalance() , setBeneficiary()

Recommendation
Consider using the “external” attribute for functions never called from the contract.

Alleviation
The development team considered this is a good advice, but will still follow the openzeppeling standard lib
here.
ccswap Security Assessment

CCT-02 | Unlocked Compiler Version Declaration

 Category               Severity          Location                                           Status

 Language Specific         Informational   CCToken_flat.sol: 3, 31, 112, 330, 638, 709, 1009      Acknowledged

Description
The compiler version utilized throughout the project uses the “^” prefix specifier, '>=0.6.0=0.6.2
ccswap Security Assessment

MCC-01 | Proper Usage of                public   and   external   type

 Category           Severity                Location                                Status

 Coding Style          Informational        MasterChef_flat.sol: 953, 962                Acknowledged

Description
“public” functions that are never called by the contract should be declared “external” . When the inputs are
arrays, “external” functions are more efficient than “public” functions.

Examples:

Functions like : renounceOwnership() , transferOwnership() , add() , set() , setMigrator() ,
MasterChef.migrate() , deposit() , withdraw() , emergencyWithdraw() , setPause() ,

Migrator.migrate() , symbol() , decimals() , transfer() , allowance() , approve() , transferFrom() ,

increaseAllowance() , decreaseAllowance() , renounceOwnership() , transferOwnership() ,

addMinter() , delMinter() , getMinter() , getBalance() , setBeneficiary()

Recommendation
Consider using the “external” attribute for functions never called from the contract.

Alleviation
The development team considered this is a good advice, but will still follow the openzeppeling standard lib
here.
ccswap Security Assessment

MCC-02 | Unlocked Compiler Version Declaration

 Category               Severity          Location                                             Status

 Language Specific         Informational   MasterChef_flat.sol: 5, 86, 304, 497, 574, 875, 903       Acknowledged

Description
The compiler version utilized throughout the project uses the “^” prefix specifier, '>=0.6.0=0.6.2
ccswap Security Assessment

MCK-01 | Proper Usage of                 public   and    external   type

 Category             Severity                    Location                       Status

 Coding Style            Informational            Migrator_flat.sol: 237                 Acknowledged

Description
“public” functions that are never called by the contract should be declared “external” . When the inputs are
arrays, “external” functions are more efficient than “public” functions.

Examples:

Functions like : renounceOwnership() , transferOwnership() , add() , set() , setMigrator() ,
MasterChef.migrate() , deposit() , withdraw() , emergencyWithdraw() , setPause() ,

Migrator.migrate() , symbol() , decimals() , transfer() , allowance() , approve() , transferFrom() ,

increaseAllowance() , decreaseAllowance() , renounceOwnership() , transferOwnership() ,

addMinter() , delMinter() , getMinter() , getBalance() , setBeneficiary()

Recommendation
Consider using the “external” attribute for functions never called from the contract.

Alleviation
The development team considered this is a good advice, but will still follow the openzeppeling standard lib
here.
ccswap Security Assessment

MCK-02 | Lack of Input Validation

 Category                 Severity          Location                              Status

 Volatile Code              Minor           Migrator_flat.sol: 225                    Resolved

Description
Missing validation for the input variables _chef , _oldFactory in function Migrator.constructor() .

Recommendation
Consider adding below checks to ensure these input variables are not equal to address(0) :

    require(_chef != address(0), "Migrator     :   _chef is zero address");
    chef = _chef;
    require(_oldFactory != address(0), "Migrator       :   _oldFactory is zero address");
    oldFactory = _oldFactory;

Alleviation
The development team heeded our advice and resolved this issue in commit
2ea789f0b79a8f839a6fc211f938d27c04f62caa.
ccswap Security Assessment

MCK-03 | Pair Creation With Zero Migration Balance

 Category              Severity             Location                                   Status

 Gas Optimization         Informational     Migrator_flat.sol: 237~256(Migrator)           Acknowledged

Description
In the unlikely situation when the migrated pool does have any balance for migration, migrate() function is
expected to simply return. However, it is interesting to notice that the return does not happen until the new
ccswap pair is created, which may cost lots of gas.

Recommendation
Move the balance detection logic earlier so that we can simply return without migration and new pair
creation if the balance is zero. For example:

       function migrate(IUniswapV2Pair orig) public returns (ICCPair) {
          require(msg.sender == chef, "Migrator: not from master chef");
          require(block.number >= notBeforeBlock, "Migrator: too early to migrate");
          require(orig.factory() == oldFactory, "Migrator: not from old factory");
          uint256 lp = orig.balanceOf(msg.sender);
            if (lp == 0) return pair;

Alleviation
The development replied that: Not detec at first because we need to return pair object to masterChef.
ccswap Security Assessment

MCK-04 | Unlocked Compiler Version Declaration

 Category                 Severity              Location                               Status

 Language Specific           Informational       Migrator_flat.sol: 3, 27, 84, 135          Acknowledged

Description
The compiler version utilized throughout the project uses the “^” prefix specifier, '>=0.6.0=0.6.2
ccswap Security Assessment

MCK-05 | Potential Front-Running For Migration Blocking

 Category             Severity        Location                                           Status

 Control Flow            Major        Migrator_flat.sol: 237~256(Migrator)                    Acknowledged

Description
The migrate() function in MasterChef contract has a final check after the migration, i.e., require(bal ==
newLpToken.balanceOf(address(this)), "migrate: bad"). However, in the mint() function of CCPair, the
minted liquidity amount to be returned is only set to the old ccswap's pool token ammount when
_totalSupply == 0. This means that the whole migration process assumes the migration transaction is the
first to mint the new LP tokens (of this particular trading pair), otherwise it will fail. If the migration
transaction is not the first to mint new LP tokens, the first transaction that successfully mints the new LP
tokens will lead to _totalSupply != 0. In other words, the migration transaction will be forced to take the
execution path liquidity = SafeMath.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply)
/ _reserve1). This is a confirmed issue in Sushiswap, and they solved this issue by streamlining the entire
deployment script.

Recommendation
To ensure a smooth migration process, we need to guarantee the first minting of new LP tokens is
launched by the migration transaction. To achieve that, we need to prevent any unintended minting (of new
LP tokens) between deploy CCFactory and configure MasterChef. A natural approach is to complete the
initial three steps, deploy CCFactory, deploy migrator and configure MasterChef within the same
transaction, best facilitated by a contract-coordinated deployment.

Alleviation
The development team confirmed that this is a known issue. To solve this issue, they will first set the
migrator of factory and check there is not pairs in the factory. After that nobody can add liquidity until
migrator migrate this pool, which ensures no front running.
ccswap Security Assessment

MCV-01 | Proper Usage of                public   and    external    type

 Category       Severity          Location                                                   Status

 Coding Style     Informational   MasterChefV2.sol: 117, 133, 142, 147, 212, 228, 243, 267       Acknowledged

Description
“public” functions that are never called by the contract should be declared “external” . When the inputs are
arrays, “external” functions are more efficient than “public” functions.

Examples:

Functions like : renounceOwnership() , transferOwnership() , add() , set() , setMigrator() ,
MasterChef.migrate() , deposit() , withdraw() , emergencyWithdraw() , setPause() ,

Migrator.migrate() , symbol() , decimals() , transfer() , allowance() , approve() , transferFrom() ,

increaseAllowance() , decreaseAllowance() , renounceOwnership() , transferOwnership() ,

addMinter() , delMinter() , getMinter() , getBalance() , setBeneficiary()

Recommendation
Consider using the “external” attribute for functions never called from the contract.

Alleviation
The development team considered this is a good advice, but will still follow the openzeppeling standard lib
here.
ccswap Security Assessment

MCV-02 | Missing Some Important Checks

 Category       Severity   Location                                                               Status

 Volatile                  MasterChefV2.sol: 147~156, 172~183, 194~209, 212~225, 228~240, 243
                   Minor                                                                             Acknowledged
 Code                      ~254

Description
Functions migrate() , pendingCC() , updatePool() , deposit() , withdraw() , emergencyWithdraw() are
missing parameter validations.

Recommendation
Consider adding below checks in the functions mentioned before, to ensure the token of the given pool is
valid:

         require (address(pool.lpToken) != address(0), "MC: _pid is incorrect");

For example:

             function migrate(uint256 _pid) public notPause {
                require(address(migrator) != address(0), "migrate: no migrator");
                PoolInfo storage pool = poolInfo[_pid];
                require (address(pool.lpToken) != address(0), "MC: _pid is incorrect");
               IERC20 lpToken = pool.lpToken;
               ...
         }

Alleviation
The development team replied that they ensure every pool has nonzero lp token.
ccswap Security Assessment

MCV-03 | add() Function Not Restricted

 Category           Severity      Location                                            Status

 Volatile Code           Minor    MasterChefV2.sol: 115~130(MasterChef)                  Acknowledged

Description
The comment for function add() mentioned "DO NOT add the same LP token more than once. Rewards
will be messed up if you do."

The total amount of reward eggReward in function updatePool() will be incorrectly calculated if the same
LP token is added into the pool more than once in function add() .

However, the code does not reflect as the comment behaviors as there isn’t any valid restriction on
preventing this issue.

The current implementation is relying on the trust of the owner to avoid repeatedly adding same LP token
to the pool, as the function will only be called by the owner.

Recommendation
Detect whether the given pool for addition is a duplicate of an existing pool. The pool addition is only
successful when there is no duplicate.

One solution is add a check function in add(). For example:

       function massUpdatePools() public {
           uint256 length = poolInfo.length;
           for (uint256 pid = 0; pid < length; ++pid) {
               require(poolInfo[_pid].lpToken != _lpToken, "add: existing pool?");
           }
       }

Or using mapping of addresses -> booleans , which can restrict the same address being added twice.

Alleviation
The development team replied that they will choose another simpler way for gas saving. In addition, even if
a duplicated tokens added, they can set its allocation point to zero to undo it.
ccswap Security Assessment

MCV-04 | Missing Emit Events

 Category       Severity          Location                                                        Status

 Gas                              MasterChefV2.sol: 133~139(MasterChef), 142~144(MasterChef),
                  Informational                                                                      Acknowledged
 Optimization                     257~264(MasterChef)

Description
Function that affect the status of sensitive variables should be able to emit events as notifications to
customers.

       safeCCTransfer()

       set()

       setMigrator()

Recommendation
Consider adding events for sensitive actions, and emit it in the function. For function safeCCTransfer() ,
consider to emit events with parameters _to and _amount in case _amount > ccBal .
ccswap Security Assessment

MCV-05 | Array Index Out of Bound

 Category        Severity          Location                                                             Status

 Volatile Code     Informational   MasterChefV2.sol: (133), (147), (172), (194), (212), (228), (243)        Acknowledged

Description
There's no sanity check to validate if a pool is existing. The current implementation simply relies on the
implicit, compiler-generated bound-checks of arrays to ensure the pool index stays within the array range
[0, poolInfo.length-1]. However, considering the importance of validating given pools and their numerous
occasions, a better alternative is to make explicit the sanity checks by introducing a new modifier.

Recommendation
Apply necessary sanity checks to ensure the given _pid is legitimate by adding a new modifier
validatePool to functions set() , deposit() , withdraw() , emergencyWithdraw() , pendingMany() and
updatePool() .

 modifier validatePoolByPid(uint256 _pid) {
     require (_pid < poolInfo.length , "Pool does not exist") ;
     _;
 }
ccswap Security Assessment

MCV-06 | Take startBlock into Consideration in getMultiplier()

 Category          Severity             Location                                        Status

 Logical Issue       Informational      MasterChefV2.sol: 159~169(MasterChef)              Acknowledged

Description
We notice that this function does not take into account the initial block (startBlock) from which the rewards
start to apply. As a result, when a normal user gives arbitrary arguments, it could return wrong reward
multiplier

Recommendation
Apply additional sanity checks at the beginning of the getMultiplier() function so that the internal _from
parameter can be adjusted to take startBlock into account.

         _from = _from >= startBlock ? _from : startBlock;
ccswap Security Assessment

MCV-07 | Boolean Equality

 Category             Severity               Location                              Status

 Gas Optimization        Informational       MasterChefV2.sol: 273(MasterChef)        Acknowledged

Description
Boolean constants can be used directly and do not need to be compared to true or false.

Example:

   require(paused == false, "Mining has been suspended");

Recommendation
Consider changing it as following example:

   require(!paused, "Mining has been suspended");
ccswap Security Assessment

MCV-08 | Potential Front-Running For Migration Blocking

 Category            Severity       Location                                               Status

 Control Flow           Major       MasterChefV2.sol: 147~156(MasterChef)                     Acknowledged

Description
The migrate() function in MasterChef contract has a final check after the migration, i.e., require(bal ==
newLpToken.balanceOf(address(this)), "migrate: bad"). However, in the mint() function of CCPair, the
minted liquidity amount to be returned is only set to the old ccswap's pool token ammount when
_totalSupply == 0. This means that the whole migration process assumes the migration transaction is the
first to mint the new LP tokens (of this particular trading pair), otherwise it will fail. If the migration
transaction is not the first to mint new LP tokens, the first transaction that successfully mints the new LP
tokens will lead to _totalSupply != 0. In other words, the migration transaction will be forced to take the
execution path liquidity = SafeMath.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply)
/ _reserve1). This is a confirmed issue in Sushiswap, and they solved this issue by streamlining the entire
deployment script.

Recommendation
To ensure a smooth migration process, we need to guarantee the first minting of new LP tokens is
launched by the migration transaction. To achieve that, we need to prevent any unintended minting (of new
LP tokens) between deploy CCFactory and configure MasterChef. A natural approach is to complete the
initial three steps, deploy CCFactory, deploy migrator and configure MasterChef within the same
transaction, best facilitated by a contract-coordinated deployment.

Alleviation
The development team confirmed that this is a known issue. To solve this issue, they will first set the
migrator of factory and check there is not pairs in the factory. After that nobody can add liquidity until
migrator migrate this pool, which ensures no front running.
ccswap Security Assessment

TTL-01 | Proper Usage of              public   and   external   type

 Category           Severity              Location                                      Status

 Coding Style         Informational       TeamTimeLock_flat.sol: 612, 639                   Acknowledged

Description
“public” functions that are never called by the contract should be declared “external” . When the inputs are
arrays, “external” functions are more efficient than “public” functions.

Examples:

Functions like : renounceOwnership() , transferOwnership() , add() , set() , setMigrator() ,
MasterChef.migrate() , deposit() , withdraw() , emergencyWithdraw() , setPause() ,

Migrator.migrate() , symbol() , decimals() , transfer() , allowance() , approve() , transferFrom() ,

increaseAllowance() , decreaseAllowance() , renounceOwnership() , transferOwnership() ,

addMinter() , delMinter() , getMinter() , getBalance() , setBeneficiary()

Recommendation
Consider using the “external” attribute for functions never called from the contract.

Alleviation
The development team considered this is a good advice, but will still follow the openzeppeling standard lib
here.
ccswap Security Assessment

TTL-02 | Unlocked Compiler Version Declaration

 Category               Severity          Location                                        Status

 Language Specific         Informational   TeamTimeLock_flat.sol: 3, 221, 302, 495, 571         Acknowledged

Description
The compiler version utilized throughout the project uses the “^” prefix specifier, '>=0.6.0=0.6.2
ccswap Security Assessment

Appendix
Finding Categories

Centralization / Privilege
Centralization / Privilege findings refer to either feature logic or implementation of components that act
against the nature of decentralization, such as explicit ownership or specialized access roles in
combination with a mechanism to relocate funds.

Gas Optimization
Gas Optimization findings do not affect the functionality of the code but generate different, more optimal
EVM opcodes resulting in a reduction on the total gas cost of a transaction.

Mathematical Operations
Mathematical Operation findings relate to mishandling of math formulas, such as overflows, incorrect
operations etc.

Logical Issue
Logical Issue findings detail a fault in the logic of the linked code, such as an incorrect notion on how
block.timestamp works.

Control Flow
Control Flow findings concern the access control imposed on functions, such as owner-only functions
being invoke-able by anyone under certain circumstances.

Volatile Code
Volatile Code findings refer to segments of code that behave unexpectedly on certain edge cases that may
result in a vulnerability.

Data Flow
Data Flow findings describe faults in the way data is handled at rest and in memory, such as the result of a
struct assignment operation affecting an in-memory struct rather than an in-storage one.

Language Specific
ccswap Security Assessment

Language Specific findings are issues that would only arise within Solidity, i.e. incorrect usage of private or
delete.

Coding Style
Coding Style findings usually do not affect the generated byte-code but rather comment on how to make
the codebase more legible and, as a result, easily maintainable.

Inconsistency
Inconsistency findings refer to functions that should seemingly behave similarly yet contain different code,
such as a constructor assignment imposing different require statements on the input variables than a setter
function.

Magic Numbers
Magic Number findings refer to numeric literals that are expressed in the codebase in their raw format and
should otherwise be specified as constant contract variables aiding in their legibility and maintainability.

Compiler Error
Compiler Error findings refer to an error in the structure of the code that renders it impossible to compile
using the specified version of the project.
ccswap Security Assessment

Disclaimer
This report is subject to the terms and conditions (including without limitation, description of services,
confidentiality, disclaimer and limitation of liability) set forth in the Services Agreement, or the scope of
services, and terms and conditions provided to the Company in connection with the Agreement. This
report provided in connection with the Services set forth in the Agreement shall be used by the Company
only to the extent permitted under the terms and conditions set forth in the Agreement. This report may not
be transmitted, disclosed, referred to or relied upon by any person for any purposes without CertiK’s prior
written consent.

This report is not, nor should be considered, an “endorsement” or “disapproval” of any particular project or
team. This report is not, nor should be considered, an indication of the economics or value of any
“product” or “asset” created by any team or project that contracts CertiK to perform a security
assessment. This report does not provide any warranty or guarantee regarding the absolute bug-free
nature of the technology analyzed, nor do they provide any indication of the technologies proprietors,
business, business model or legal compliance.

This report should not be used in any way to make decisions around investment or involvement with any
particular project. This report in no way provides investment advice, nor should be leveraged as investment
advice of any sort. This report represents an extensive assessing process intending to help our customers
increase the quality of their code while reducing the high level of risk presented by cryptographic tokens
and blockchain technology.

Blockchain technology and cryptographic assets present a high level of ongoing risk. CertiK’s position is
that each company and individual are responsible for their own due diligence and continuous security.
CertiK’s goal is to help reduce the attack vectors and the high level of variance associated with utilizing
new and consistently changing technologies, and in no way claims any guarantee of security or
functionality of the technology we agree to analyze.
ccswap Security Assessment

About
Founded in 2017 by leading academics in the field of Computer Science from both Yale and Columbia
University, CertiK is a leading blockchain security company that serves to verify the security and
correctness of smart contracts and blockchain-based protocols. Through the utilization of our world-class
technical expertise, alongside our proprietary, innovative tech, we’re able to support the success of our
clients with best-in-class security, all whilst realizing our overarching vision; provable trust for all
throughout all facets of blockchain.
You can also read