CertiK reviewed WanPlan on 9 Nov 2022: 23 findings, 1 critical; 14 marked fixed, 1 acknowledged, 8 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 | 1 |
| High | 0 | 1 | 0 |
| Medium | 0 | 0 | 0 |
| Low | 8 | 0 | 13 |
Inputting negative numbers into the functions `stake()` and `unstake()` can cause unexpected behaviors. --- In the function `stake()`, the argument `_num` is of type `int256`. This allows a user to input a negative number, meaning they intend to stake a negative amount of tokens. ```solidity=112 function stake(int _num, address _to) public { ``` During the transfer of tokens from the user to the contract, argument `_num` is casted to type `uint256`. The result will be a large positive number. This may cause an unintended amount of `lpToken` to be transferred into the contract by the user. ```solidity=127 lpToken.transferFrom(msg.sender, address(this), uint(_num)); ``` The mapping `stakeNum` keeps track of a user's staked amount. Although `uint(_num)` amounts of tokens were transferred, the mapping will incorrectly decrease in value by the value `_num`. ```solidity=128 stakeNum[_to] += _num; stakeTotal += _num; ``` --- In the function `unStake()`, the argument `_num` is of type `int256`. This allows a user to input a negative number, meaning they intend to unstake a negative amount of tokens. ```solidity=134 function unStake(int _num) public { ``` If `_num` is a negative number, the `require` check that ensures the user has a greater or equal balance of staked tokens than the amount to unstake, can be bypassed. ```solidity=135 require(stakeNum[msg.sender] >= _num, "Error:stake lpToken balance not enough"); ``` The value `_num` is casted to type `uint256`, resulting in a large positive number. `uint(_num)` amount of tokens will then be incorrectly transferred out of the contract and to the user. The user is able to unstake `uint(_num)` amount of tokens without initially staking that same amount. ```solidity=148 lpToken.transfer(msg.sender, uint(_num)); ``` The mapping `stakeNum` will incorrectly increase in value by the value `_num`. ```solidity=149 stakeNum[msg.sender] -= _num; stakeTotal -= _num; ```
Accessing storage variables in a loop can be costly in terms of gas consumption. The storage variables `LinerReleaseRemain` and `LinerReleaseCount` are likely to be read and updated multiple times during the `for` loop. ```solidity=658 for (; LinerReleaseRemain > 0; LinerReleaseCount++) { if (ConstructTime + (LinerReleaseCount + 1) * 864000 >= block.timestamp) { return; } if (LinerReleaseRemain / (4000 * 1 ether) > 0) { balances[techCommunityAddress] += (4000 * 1 ether); LinerReleaseRemain -= (4000 * 1 ether); } else { balances[techCommunityAddress] += LinerReleaseRemain; LinerReleaseRemain = 0; } } ```
It is expected behavior that calls of the form `approve(spender, amount)` fail if the address in `spender` is the zero address.
It is expected behavior that calls of the form `transferFrom(from, dest, amount)` fail if the `from` address is zero.
Functions which are never called internally within the contract should have `external` visibility.
The contract has one or more payable functions, but does not have a function to withdraw the funds. ```solidity=384 function buy(uint256 _count) public payable { ```
Addresses should be checked before assignment or external calls to ensure they are not `address(0)`.
The variable names `LinerReleaseCount` and `LinerReleaseRemain` are misspelled throughout the contract.
The reserve amounts of `WantAddr` and `TradeCoinAddr` tokens are retrieved from the external call to the `pair` address: ```solidity=410 (uint reserveA, uint reserveB,) = pair.getReserves(); ``` The inequality of the addresses `WantAddr` and `TradeCoinAddr` is then checked in order to determine which address corresponds to which reserve value, either `reserveA` or `reserveB`. ```solidity=412 if (WantAddr < TradeCoinAddr) { ``` However, the inequality is not a guaranteed method of matching the addresses to the corresponding reserve values because the implementation of the external contract `pair` could have a different mechanism of ordering the two addresses. The call to `pair.getReserves()` could return a different ordering of reserve values.
A fee is taken on token transfers during the call to `transferFrom()`. However, the `burn` portion of the fee is missing as tokens are never transferred to the zero address. The event of transferring tokens to the zero address is still emitted. ```solidity=436 if (_tax != 0) { balances[stakeLPAddress] += (_tax * lpTax / 10000); balances[valueInstituteAddress] += (_tax * valueInstituteTax / 10000); emit Transfer(_from, stakeLPAddress, (_tax * lpTax / 10000)); emit Transfer(_from, valueInstituteAddress, (_tax * valueInstituteTax / 10000)); emit Transfer(_from, address(0), (_tax * burnTax / 10000)); // Burn event is emitted but never executed } ```
The `SafeMath` library is used unnecessarily. With Solidity compiler versions `0.8.0` or newer, arithmetic operations will automatically revert in case of integer overflow or underflow. --- ```solidity=105 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `WantImplementation` contract, in file `Want.sol` --- ```solidity=295 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `WantSale` contract.
The type casting from unsigned integer `uint` to the integer `int` and vice versa, may cause the values to become truncated or have the incorrect positive or negative sign. This can cause unexpected behaviors and errors if the bounds of type casting is not checked. ```solidity=101 heights.push(HeightProfit(0, int(block.number), _ratio, stakeTotal)); ``` - Type conversion `int256(block.number)` from type `uint256` to type `int256`. --- ```solidity=103 heights.push(HeightProfit(heights[heights.length - 1].height + 1, int(block.number), _ratio, stakeTotal)); ``` - Type conversion `int256(block.number)` from type `uint256` to type `int256`. --- ```solidity=113 require(int(lpToken.balanceOf(msg.sender)) >= _num, "Error: lp token balance not enough"); ``` - Type conversion `int256(lpToken.balanceOf(msg.sender))` from type `uint256` to type `int256`. --- ```solidity=121 lastClaimHeightMap[_to] = int(heights.length); ``` - Type conversion `int256(heights.length)` from type `uint256` to type `int256`. --- ```solidity=123 lastClaimHeightMap[_to] = int(heights.length) - 1; ``` - Type conversion `int256(heights.length)` from type `uint256` to type `int256`. --- ```solidity=127 lpToken.transferFrom(msg.sender, address(this), uint(_num)); ``` - Type conversion `uint256(_num)` from type `int256` to type `uint256`. --- ```solidity=141 lastClaimHeightMap[msg.sender] = int(heights.length); ``` - Type conversion `int256(heights.length)` from type `uint256` to type `int256`. --- ```solidity=143 lastClaimHeightMap[msg.sender] = int(heights.length) - 1; ``` - Type conversion `int256(heights.length)` from type `uint256` to type `int256`. --- ```solidity=148 lpToken.transfer(msg.sender, uint(_num)); ``` - Type conversion `uint256(_num)` from type `int256` to type `uint256`. --- ```solidity=159 lastClaimHeightMap[msg.sender] = int(heights.length); ``` - Type conversion `int256(heights.length)` from type `uint256` to type `int256`. --- ```solidity=161 lastClaimHeightMap[msg.sender] = int(heights.length) - 1; ``` - Type conversion `int256(heights.length)` from type `uint256` to type `int256`. --- ```solidity=191 for (int i = index + 1; i < int(heights.length); i++) { ``` - Type conversion `int256(heights.length)` from type `uint256` to type `int256`. --- ```solidity=192 sum += stakeNum[_owner] * heights[uint(i)].ratio; ``` - Type conversion `uint256(i)` from type `int256` to type `uint256`. --- ```solidity=199 for (int i = 0; i < int(heights.length); i++) { ``` - Type conversion `int256(heights.length)` from type `uint256` to type `int256`. --- ```solidity=200 sum += heights[uint(i)].total * heights[uint(i)].ratio; ``` - Type conversion `uint256(i)` from type `int256` to type `uint256`. --- ```solidity=421 stake.stake(int(_li), msg.sender); ``` - Type conversion `int256(_li)` from type `uint256` to type `int256`.
The following code components are never used in the contract `WantSale.sol`. ```solidity=297 address public GMAddr; ``` ```solidity=317 uint256 private PeriodStartSaleHeight; uint256 private PeriodEndSaleHeight; ``` ```solidity=320 bool public PublicBuy; ``` ```solidity=351 address public UniswapV2RouterAddr; ```
The local variables are returned instead of the return variable. ```solidity=109 return sum; ``` - The local variable `sum` is returned in place of the return variable `_reward`, which is never written. --- ```solidity=178 return sum; ``` - The local variable `sum` is returned in place of the return variable `_available`, which is never written. --- ```solidity=194 return sum; ``` - The local variable `sum` is returned in place of the return variable `_reward`, which is never written. --- ```solidity=202 return sum; ``` - The local variable `sum` is returned in place of the return variable `_reward`, which is never written.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (3)
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