Web3 Security Review: Superseed Token Audit
Cantina Security Report
Organization
- @superseed-xyz
Engagement Type
Cantina Reviews
Period
-
Repositories
N/A
Findings
Low Risk
2 findings
2 fixed
0 acknowledged
Informational
3 findings
3 fixed
0 acknowledged
Gas Optimizations
1 findings
1 fixed
0 acknowledged
Low Risk2 findings
Missing input validation in constructors
State
Severity
- Severity: Low
Submitted by
0xWeiss
Description
Both contracts in scope (TokenClaim and SuperseedToken) lack input validation on their constructors.
Recommendation
Validate the following parameters:
- TokenClaim:
constructor(address _initialOwner, address _token, address _treasury) Ownable(_initialOwner) {+ require(_token != address(0), "invalid address");+ require(_treasury != address(0), "invalid address");token = IERC20(_token);treasury = _treasury;}- SuperseedToken:
constructor(address superAdmin,address minter,address treasury)ERC20("Superseed", "SUPR")ERC20Permit("Superseed"){+ require(treasury != address(0), "invalid address");+ require(superAdmin != address(0), "invalid address");+ require(minter != address(0), "invalid address");_mint(treasury, 10_000_000_000e18);_grantRole(DEFAULT_ADMIN_ROLE, superAdmin);_grantRole(MINTER_ROLE, minter);}Missing event when updating the merkle root
State
Severity
- Severity: Low
Submitted by
0xWeiss
Description
The merkle root function makes a key state change but lacks to emit an event:
function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {if (_merkleRoot == bytes32(0)) revert InvalidInput("_merkleRoot");merkleRoot = _merkleRoot;}Recommendation
Emit an event with the old and the new merkle roots as arguments:
function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {if (_merkleRoot == bytes32(0)) revert InvalidInput("_merkleRoot");+ emit merkleRootUpdated(merkleRoot,_merkleRoot);merkleRoot = _merkleRoot;}
Informational3 findings
ERC20 import is redundant
State
Severity
- Severity: Informational
Submitted by
0xWeiss
Description
The SuperseedToken contract imports multiple ERC20 extensions:
ERC20, ERC20Burnable, AccessControl, ERC20Permit, ERC20Votes
which under the hood already use the originalERC20
contract, making it redundant.Recommendation
Remove the
ERC20
import:- contract SuperseedToken is ERC20, ERC20Burnable, AccessControl, ERC20Permit, ERC20Votes {+ contract SuperseedToken is ERC20Burnable, AccessControl, ERC20Permit, ERC20Votes {Avoid Unnecessary Use of SafeERC20 for SuperseedToken
State
Severity
- Severity: Informational
Submitted by
Kankodu
Description
Since
SuperseedToken
strictly follows the ERC20 standard and reverts on failed transfers, the safety checks provided by the SafeERC20 library are unnecessary.Recommendation
Use direct ERC20
transferFrom
call to avoid unnecessary overhead.Use Named Constants for Improved Readability
State
Severity
- Severity: Informational
Submitted by
Kankodu
Description
Named constants enhance code clarity and maintainability by replacing hardcoded values with meaningful identifiers.
Recommendation
Define
TEN_BILLION_TOKENS
as a constant:uint256 internal constant TEN_BILLION_TOKENS = 10_000_000_000e18;Use this constant instead of directly writing the value to improve readability and prevent errors.
Gas Optimizations1 finding
Improve Custom Error Definitions for Clarity and Efficiency
State
Severity
- Severity: Gas optimization
Submitted by
Kankodu
Description
The
InvalidInput
error currently includes a string parameter, which increases bytecode size and provides no significant advantage over using a standardrevert
with a string message.Recommendation
Instead of using a string parameter, define multiple custom errors with structured and informative parameters. This improves clarity while reducing bytecode size. For example:
error MerkleRootCannotBeEmpty();error ZeroBalanceForProvidedToken(address token);error InputAmountCannotBeZero();By using structured parameters, errors become more meaningful and cost-efficient while maintaining clarity.