This is the report from a security audit performed on ERC20andCrowdsale by gorbunovperm.
ERC20andCrowdsale alow to create ERC20 token and sale it at five stages with a different rate of exchange at each stage.
In total, 6 issues were reported including:
-
1 high severity issue.
-
0 medium severity issues.
-
4 low severity issues.
-
1 minor observations.
Issues for ERC20Token.sol
function transfer(address to, uint tokens) public returns (bool success) {
balances[msg.sender] = balances[msg.sender].sub(tokens);
balances[to] = balances[to].add(tokens);
// ...
}
function transferFrom(address from, address to, uint tokens) public returns (bool success) {
balances[from] = balances[from].sub(tokens);
allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
balances[to] = balances[to].add(tokens);
// ...
}
In some cases it is possible to send funds to an empty address.
Add require(to != address(0));
condition in the begining of the function.
function approve(address spender, uint tokens) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
Approval(msg.sender, spender, tokens);
return true;
}
In case the user wants to change the approved amount an double-spend attack is possible.
Look at here.
function inflate(uint percent) public onlyOwner {
// ...
_totalSupply += addedTokens;
// ...
}
Theoretically, the variable _totalSupply
can be overflowed. This is not a danger in this case but it is better to fix it.
Use _totalSupply = _totalSupply.add(addedTokens);
instead _totalSupply += addedTokens;
.
Issues for Crowdsale.sol
function buyTokens(address _beneficiary) public payable {
// ...
tokensSold += tokens;
// ...
}
tokensSold
variable overflow is possible. This will change the level of stage in the opposite direction. Accordingly, the price will change.
Use tokensSold = tokensSold.add(tokens);
instead tokensSold += tokens;
.
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal {
require(_beneficiary != address(0));
require(_weiAmount >= minAmount);
require(_weiAmount <= maxAmount);
}
In endCrowdsale
function stage level changes to StageLevel.END
but this is not checked when buying a tokens. And the level will be changed again after the first purchase because _updateCrowdsaleStage
function will be call.
Add require(stageLevel != StageLevel.END);
condition in _preValidatePurchase
function.
function endCrowdsale( address _returnAddress, uint256 _tokenAmount) public onlyOwner {
stageLevel = StageLevel.END;
_deliverTokens(_returnAddress, _tokenAmount);
}
In some cases it is possible to send funds to an empty address.
Add require(_returnAddress != address(0));
condition in the begining of the function.
These contracts are not secure, it is necessary to fix the described vulnerabilities.