Prepared by:
HALBORN
Last Updated 04/26/2024
Date of Engagement by: September 2nd, 2022 - September 9th, 2022
100% of all REPORTED Findings have been addressed
All findings
7
Critical
0
High
1
Medium
1
Low
2
Informational
3
Seascape engaged Halborn to conduct a security audit on their Ninja Spin
smart contracts beginning on September 2nd, 2022 and ending on September 9th, 2022. The security assessment was scoped to some smart contracts provided in the GitHub repository blocklords/bigbang-smartcontracts.
The team at Halborn was provided a week for the engagement and assigned one full-time security engineer to audit the security of the smart contract. The security engineer is a blockchain and smart-contract security expert with advanced penetration testing, smart-contract hacking, and deep knowledge of multiple blockchain protocols.
The purpose of this audit is to:
Ensure that smart contract functions operate as intended
Identify potential security issues with the smart contracts
In summary, Halborn identified some security risks that were addressed and acknowledged by the Seascape
team.
Halborn performed a combination of manual and automated security testing to balance efficiency, timeliness, practicality, and accuracy in regard to the scope of this audit. While manual testing is recommended to uncover flaws in logic, process, and implementation; automated testing techniques help enhance coverage of the code and can quickly identify items that do not follow the security best practices. The following phases and associated tools were used during the audit:
Research into architecture and purpose
Smart contract manual code review and walkthrough
Graphing out functionality and contract logic/connectivity/functions (solgraph
)
Manual assessment of use and safety for the critical Solidity variables and functions in scope to identify any arithmetic related vulnerability classes
Manual testing by custom scripts
Scanning of solidity files for vulnerabilities, security hotspots or bugs. (MythX
)
Static Analysis of security for scoped contract, and imported functions. (Slither
)
Testnet deployment (Brownie
, Remix IDE
)
IN-SCOPE: The security assessment was scoped to the following smart contracts:
BigBangNFT.sol
BigBangFactory.sol
BigBangGame.sol
Located on the Commit ID: 4e6b040ec981df4f8ce9993bea75563ca5b9fa07
Critical
0
High
1
Medium
1
Low
2
Informational
3
Impact x Likelihood
HAL-01
HAL-02
HAL-05
HAL-03
HAL-04
HAL-07
HAL-06
Security analysis | Risk level | Remediation Date |
---|---|---|
CONTRACT ADMIN CAN REVOKE AND RENOUNCE HIMSELF | High | Solved - 09/13/2022 |
CONTRACT DOES NOT ALLOW MINTING NFT WITH THE ID 0 | Medium | Solved - 09/13/2022 |
NATIVE TOKEN FUNCTIONALITY COULD NOT BE USED | Low | Solved - 09/13/2022 |
MISSING ZERO ADDRESS CHECK | Low | Solved - 09/13/2022 |
UNUSED PARAMETERS | Informational | Acknowledged |
PRAGMA VERSION | Informational | Acknowledged |
UNSAFE MATH CALCULATIONS | Informational | Acknowledged |
// High
The Owner of the contract is usually the account that deploys the contract. In the BigBangNFTFactory.sol
smart contract, Only Admin
can perform some privileged actions such as setNft()
, addAdmin()
, addGenerator()
etc., the addAdmin()
function is used to add an Admin role, and the renounceAdmin
function is used to renounce being an Admin. It was observed that admin
could revoke his role via renounceAdmin()
. If an admin is mistakenly renounced, administrative access will result in the contract having no admin
, eliminating the ability to call privileged functions. In such a case, contracts would have to be redeployed.
function renounceAdmin() public virtual
{
renounceRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
BigBangNFTFactory
using the owner address.SOLVED: Now the owner cannot renounce his role. This issue was fixed in commit ID 7d4d7a60ef10d499be2c672a6b623211ef288246
// Medium
The BigBangNFT.sol
contract constructor contains an increment
of the counter variable, making the IDs begin on 1.
constructor() public ERC721("BigBang NFT", "BB") {
nftId.increment();
}
\color{black} \color{white}
It is known that some collections start at the NFT ID 0.
SOLVED: The Ninja Scape Game
can now start minting NFTs at ID 0. This issue was fixed in commit ID 63f46b35467cd3865416b1dae2aa99ea4363cf63
// Low
In the _safeTransfer()
function from BigBangGame.sol
smart contract, two different types of transfers could be performed. if _token
address sent as parameter is different from 0, the function will perform a token.transfer()
. If _token
is address(0)
, then the contract will send the native coin to the sender.
It is not possible to add address(0)
to the list of allowed tokens, as the addresses are validating this parameter to be different from 0. This makes it impossible to operate with native tokens.
constructor(address _token, address _nft, address _factory, address _verifier) public {
require(_token != address(0), "BBGame: Token can't be zero address");
require(_nft != address(0), "BBGame: Nft can't be zero address");
require(_verifier != address(0), "BBGame: Verifier can't be zero address");
BBNft = _nft;
BBFactory = _factory;
verifier = _verifier;
changeAllowed[_token] = true;
token[typeId] = _token;
}
function addToken(address _token) public onlyOwner {
require(_token != address(0), "BBGame: Token can't be zero address");
require(!changeAllowed[_token], "BBGame: This token is exist");
changeAllowed[_token] = true;
token[++typeId] = _token;
emit AddToken(_token, typeId, block.timestamp);
}
function _safeTransfer(address _token, address _to, uint256 _amount) internal {
if (_token != address(0)) {
IERC20 _rewardToken = IERC20(_token);
uint256 _balance = _rewardToken.balanceOf(address(this));
require(_amount <= _balance, "BBGame: Do not have enough token to reward");
uint256 _beforBalance = _rewardToken.balanceOf(_to);
_rewardToken.transfer(_to, _amount);
require(_rewardToken.balanceOf(_to) == _beforBalance + _amount, "BBGame: Invalid transfer");
} else {
uint256 _balance = address(this).balance;
require(_amount <= _balance, "BBGame: Do not have enough token to reward");
payable(_to).transfer(_amount);
}
}
// Accept native tokens.
receive() external payable {
//React to receiving ether
}
SOLVED: The SeaScape Team
now allows the BigBangGame.sol
contract to add the address(0) to specify that the native token could be used. This issue was fixed in commit ID 6fbb5845900735349c19c5e751991b9854d9a2a5
// Low
There is no validation of the addresses in the mint()
and access control functions. Addresses should be validated and checked that are different from zero when necessary. This issue is present in all the smart contracts, in the constructors and functions that use addresses as parameters. These examples show how the factory could be set up with a wrong address and how mint could burn NFTs if _owner
is address(0)
constructor(address _nft) public {
nft = BigBangNFT(_nft);
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function mint(address _owner, uint256 _quality, uint256 _image) public onlyGenerator returns(uint256) {
require (_quality > 0 && _quality < 6, "NFT Factory: invalid quality");
return nft.mint(_owner, _quality, _image);
}
SOLVED: The SeaScape Team
now checks the address inputs to ensure they are non-zero. This issue has been fixed in commit ID [7d4d7a60ef10d499be2c672a6b623211ef288246](https://github.com/Seastarinteractive/moonscape-smartcontracts/tree/7d4d7a60ef10d499be2c672a6b623211ef288246
// Informational
There are functions whose parameters are never used in some smart contracts. These parameters have no effect on the code.
operator
, from
, tokenId
, data
(BigBangGame.sol#190)BBFactory
(BigBangGame.sol#231)ACKNOWLEDGED: The SeaScape team
acknowledged this finding.
// Informational
The BigBangGame
smart contracts use the pragma version 0.6.7
which was released on May 4, 2020. latest pragma version 0.8.16
released on August 8, 2022, solves different issues. It is also noticeable that Solidity versions after 0.8.0
also implement default overflow protection on arithmetic operations.
Reference: Solidity Releases
note: All Ninja Spin
smart contracts implement same pragma version.
pragma solidity 0.6.7;
ACKNOWLEDGED: The SeaScape team
acknowledged this finding.
// Informational
Testing revealed that calculations within the smart contract did not make use of a safe math library. While Solidity pragma > 0.8.0 reverts to overflows by default, the code was making use of an older compiler version; thus it is vulnerable to integer overflows and underflows.
Halborn could not find a path to exploit the integer overflows; however, there might be some extreme test cases where this can be exploited by an attacker.
```{language=solidity caption="BigBangGame.sol" firstnumber=128 hlines=148} function goldChangeToken(uint256 _gold, uint256 _typeId, uint8 _v, bytes32 _r, bytes32 _s) external { require(_gold > 0, "BBGame: The exchange amount must greater than zero"); require(checkToken(_typeId), "BBGame: Do not have this token type");
uint256 chainId;
assembly {
chainId := chainid()
}
{
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
bytes32 message = keccak256(abi.encodePacked(_gold, msg.sender, nonce[msg.sender], address(this), chainId));
bytes32 hash = keccak256(abi.encodePacked(prefix, message));
address recover = ecrecover(hash, _v, _r, _s);
require(recover == verifier, "BBGame: Verification failed about goldChangeToken");
}
nonce[msg.sender]++;
uint256 _tokenAmount = _gold * MULTIPLIER / ratio;
_safeTransfer(token[_typeId], msg.sender, _tokenAmount);
emit GoldChangeToken(msg.sender, _typeId, _gold, _tokenAmount, block.timestamp);
} ```
ACKNOWLEDGED: The SeaScape team
acknowledged this finding.
Halborn used automated testing techniques to enhance the coverage of certain areas of the smart contracts in scope. Among the tools used was Slither, a Solidity static analysis framework. After Halborn verified the smart contracts in the repository and was able to compile them correctly into their ABIs and binary format, Slither was run against the contracts. This tool can statically verify mathematical relationships between Solidity variables to detect invalid or inconsistent usage of the contracts' APIs across the entire code-base.
No major issues found by Slither.
Halborn used automated security scanners to assist with detection of well-known security issues and to identify low-hanging fruits on the targets for this engagement. Among the tools used was MythX, a security analysis service for Ethereum smart contracts. MythX performed a scan on the smart contracts and sent the compiled results to the analyzers in order to locate any vulnerabilities.
No issues found by MythX.
Halborn strongly recommends conducting a follow-up assessment of the project either within six months or immediately following any material changes to the codebase, whichever comes first. This approach is crucial for maintaining the project’s integrity and addressing potential vulnerabilities introduced by code modifications.
// Download the full report
* Use Google Chrome for best results
** Check "Background Graphics" in the print settings if needed