UNUS SED LEO token audit report.
This is a security audit of UNUS SED LEO token report performed by Dexaran, Callisto Network.
- https://etherscan.io/address/0x2af5d2ad76741191d15dfe7bf6ac92d4bd912ca3#code (LEO token contract)
- https://etherscan.io/address/0xf17ebb3a24dc6d6b56d38adf0df499c1cd9e5672#code (LEO token contract controller at the moment of the security audit)
function proxyPayment(address _owner) public payable returns(bool allowed) {
allowed = false;
}
Use of different syntax for returning functions.
It is recommended to use the same syntax for all code fragments in order to facilitate readability. If the other fragments use the return false;
syntax , then it is recommended to use the same syntax in this function too.
function balanceOfAt(address _owner, uint _blockNumber) public view
returns (uint) {
if ((balances[_owner].length == 0)
|| (balances[_owner][0].fromBlock > _blockNumber)) {
if (address(parentToken) != address(0)) {
return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
} else {
return 0;
}
} else {
return getValueAt(balances[_owner], _blockNumber);
}
}
function totalSupplyAt(uint _blockNumber) public view returns(uint) {
if ((totalSupplyHistory.length == 0)
|| (totalSupplyHistory[0].fromBlock > _blockNumber)) {
if (address(parentToken) != address(0)) {
return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
} else {
return 0;
}
} else {
return getValueAt(totalSupplyHistory, _blockNumber);
}
}
function getValueAt(Checkpoint[] storage checkpoints, uint _block
) view internal returns (uint) {
if (checkpoints.length == 0) return 0;
if (_block >= checkpoints[checkpoints.length-1].fromBlock)
return checkpoints[checkpoints.length-1].value;
if (_block < checkpoints[0].fromBlock) return 0;
// Binary search of the value in the array
uint min = 0;
uint max = checkpoints.length-1;
uint mid = 0;
while (max > min) {
mid = (max + min + 1)/ 2;
if (checkpoints[mid].fromBlock<=_block) {
min = mid;
} else {
max = mid-1;
}
}
return checkpoints[min].value;
}
Balances may be requested for blocks that have not yet been mined. In chis case the contract will return the actual balance of the queried address while it is not a correct information because the contract does not know the balance of the queried address in the future.
This can not harm the LEO token contract, but this may confuse third party services that work with totalSupplyAt
or balanceOfAt
functions.
function approveAndCall(address _spender, uint256 _amount, bytes memory _extraData
) public returns (bool success) {
require(approve(_spender, _amount));
ApproveAndCallFallBack(_spender).receiveApproval(
msg.sender,
_amount,
address(this),
_extraData
);
return true;
}
contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 _amount, address _token, bytes memory _data) public;
}
It would be better if the receiveApproval function returns true
on successful execution. Otherwise, permissive fallback function may handle the receiveApproval invocation without causing the transaction to fail even if the receiver contract does not implement receiveApproval
function.
The default minime token is designed to by upgradeable, but the TokenFactory contract which is responsible for the upgrading process does not allow for implementation of new features/functions as it is only deploying the same version of the MinimeToken contract.
The address of TokenFactory can not be updated in the deployed contract.
/// @notice `onlyOwner` can upgrade the controller contract
/// @param _newControllerAddress The address that will have the token control logic
function upgradeController(address _newControllerAddress) public onlyOwner {
tokenContract.changeController(_newControllerAddress);
emit UpgradedController(_newControllerAddress);
}
function generateTokens(address _owner, uint _amount
) public onlyController returns (bool) {
uint curTotalSupply = totalSupply();
require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow
uint previousBalanceTo = balanceOf(_owner);
require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount);
updateValueAtNow(balances[_owner], previousBalanceTo + _amount);
emit Transfer(address(0), _owner, _amount);
return true;
}
function destroyTokens(address _owner, uint _amount
) onlyController public returns (bool) {
uint curTotalSupply = totalSupply();
require(curTotalSupply >= _amount);
uint previousBalanceFrom = balanceOf(_owner);
require(previousBalanceFrom >= _amount);
updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount);
updateValueAtNow(balances[_owner], previousBalanceFrom - _amount);
emit Transfer(_owner, address(0), _amount);
return true;
}
Owner can upgrade the controller
contract without any restrictions.
Theoretically, the controller
contract can be upgraded so that it can mint new tokens or burn any tokens at any address. If this happens, transactions will be available for viewing to everyone.
The reviewed smart-contract does not contain any medium or high severity security vulnerabilities or other issues. This contract can be used without any serious risk from technical side.
-
LEO token is compatible with ERC20 token standard.
-
LEO token is NOT prone to common ERC20 security vulnerabilities.
-
LEO token is NOT prone to re-approval attack.