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 |
The `approve` function could be used in a Front-Running attack that allows a spender to transfer more tokens than the owner of the tokens intended to allow the spender to transfer. --- Possible attack scenario: Alice allows Bob to transfer N of Alice's tokens (N > 0) by calling `approve()` method on the token smart contract and passing Bob's address and N as method arguments. After some time, Alice decides to change the number of Alice's tokens Bob is allowed to transfer from N to M (M > 0). She calls the `approve()` method again, this time passing Bob's address and M as method arguments. Bob notices Alice's second transaction before it was mined and quickly sends another transaction that calls `transferFrom()` method to transfer N of Alice's tokens somewhere. If Bob's transaction will be executed before Alice's transaction, then Bob will successfully transfer N of Alice's tokens and will gain the ability to transfer another M tokens. Before Alice noticed that something went wrong, Bob then calls `transferFrom()` method again, this time to transfer M of Alice's tokens. So, Alice's attempt to change Bob's allowance from N to M (N > 0 and M > 0) made it possible for Bob to transfer (N + M) of Alice's tokens, while Alice never intended to allow that many of her tokens to be transferred by Bob. --- ERC20 API: An Attack Vector on [Approve/TransferFrom Methods](https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#heading=h.m9fhqynw2xvt).
The order of external call/transfer and storage manipulation must follow the check-effect-interaction pattern. ### External call(s) in contract `Deposit.sol` ```solidity=127 lpToken.transferFrom(msg.sender, address(this), uint(_num)); ``` ### State variables written after the call(s) ```solidity=128 stakeNum[_to] += _num; stakeTotal += _num; ``` --- ### External call(s) in contract `Deposit.sol` ```solidity=148 lpToken.transfer(msg.sender, uint(_num)); ``` ### State variables written after the call(s) ```solidity=149 stakeNum[msg.sender] -= _num; stakeTotal -= _num; ``` --- ### External call(s) in contract `Deposit.sol` ```solidity=168 want.transfer(msg.sender, uint(sum)); ``` ### State variables written after the call(s) ```solidity=170 balanceMap[msg.sender] = 0; ```
There should always be events emitted in the sensitive functions that are controlled by centralization roles.
`Staker` implements the interface `IStake`, but does not inherit from it. ```solidity=37 contract Staker is Ownable { ``` The `IStake` interface is declared in contract `WantSale.sol` ```solidity=288 abstract contract IStake { ``` --- `WantImplementation` implements the interface `IWant`, but does not inherit from it. ```solidity=99 contract WantImplementation { ``` The `IWant` interface is declared in contract `WantSale.sol` ```solidity=269 abstract contract IWant { ``` --- `WantSale` implements the interface `IWanTSale`, but does not inherit from it. ```solidity=293 contract WantSale is Ownable { ``` The `IwantSale` interface is declared in contract `Want.sol` ```solidity=80 abstract contract IWanTSale { ```
The function `transferFrom()` deducts a fee from the amount of tokens to be transferred, resulting in less tokens arriving at the destination address than initially sent. However, the function `transfer()` does not implement this transfer fee.
The contracts cited are serving as the underlying entity to interact with one or more third party protocols. The scope of the audit treats third party entities as black boxes and assumes their functional correctness. However, in the real world, third parties can be compromised and this may lead to lost or stolen assets. In addition, upgrades of third parties can possibly create severe impacts, such as increasing fees of third parties, migrating to new LP pools, etc. ```solidity=305 IGM private gm; ``` - The contract `WantSale` interacts with third party contract with `IGM` interface via `gm`. --- ```solidity=306 TradeCoin private tc; ``` - The contract `WantSale` interacts with third party contract with `TradeCoin` interface via `tc`. --- ```solidity=307 IWant private want; ``` - The contract `WantSale` interacts with third party contract with `IWant` interface via `want`. --- ```solidity=308 IUniswapV2Router01 private uniswapV2Router; ``` - The contract `WantSale` interacts with third party contract with `IUniswapV2Router01` interface via `uniswapV2Router`. --- ```solidity=309 IPancakePair private pair; ``` - The contract `WantSale` interacts with third party contract with `IPancakePair` interface via `pair`. --- ```solidity=310 IStake private stake; ``` - The contract `WantSale` interacts with third party contract with `IStake` interface via `stake`. --- ```solidity=58 ILPToken private lpToken; ``` - The contract `Deposit` interacts with third party contract `ILPToken` interface via `lpToken`.
The return value of the `transfer()`/`transferFrom()` call is not checked. ```solidity=127 lpToken.transferFrom(msg.sender, address(this), uint(_num)); ``` --- ```solidity=148 lpToken.transfer(msg.sender, uint(_num)); ``` --- ```solidity=168 want.transfer(msg.sender, uint(sum)); ``` --- ```solidity=206 lpToken.transfer(_addr, lpToken.balanceOf(address(this))); ``` --- ```solidity=408 tc.transferFrom(msg.sender, ReceiverAddr, WantPriceTradeCoin.mul(_count) / (1 ether)); ``` --- ```solidity=413 tc.transferFrom(msg.sender, address(this), _count.mul(reserveB) / reserveA); ``` --- ```solidity=416 tc.transferFrom(msg.sender, address(this), _count.mul(reserveA) / reserveB); ```
The return value of an `external` call is not stored in a local or state variable. ```solidity=420 pair.approve(StakeAddr, _li); ``` --- ```solidity=434 want.approve(address(uniswapV2Router), _a1); ``` --- ```solidity=435 tc.approve(address(uniswapV2Router), _a2); ```
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