Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
2. _safeMint() should be used rather than _mint() wherever possible
Description:
_mint() is discouraged in favor of _safeMint() which ensures that the recipient is either an EOA or implements IERC721Receiver. Both open OpenZeppelin and solmate have versions of this function so that NFTs aren’t lost if they’re minted to contracts that cannot transfer them back out.
3. Use safeTransfer/safeTransferFrom consistently instead of transfer/transferFrom
Description
It is good to add a require() statement that checks the return value of token transfers or to use something like OpenZeppelin’s safeTransfer/safeTransferFrom unless one is sure the given token reverts in case of a failure. Failure to do so will cause silent failures of transfers and affect token accounting in contract.
src/auction/IAuction.sol:93: function initialize(
src/token/IToken.sol:51: function initialize(
src/token/metadata/interfaces/IBaseMetadata.sol:27: function initialize(
src/governance/governor/IGovernor.sol:119: function initialize(
src/governance/treasury/ITreasury.sol:64: function initialize(address governor, uint256 delay) external;
5. Use of Block.timestamp
Impact - Non-Critical
Description
Block timestamps have historically been used for a variety of applications, such as entropy for random numbers (see the Entropy Illusion for further details), locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts.
Block timestamps should not be used for entropy or generating random numbers—i.e., they should not be the deciding factor (either directly or through some derivation) for winning a game or changing an important state.
Time-sensitive logic is sometimes required; e.g., for unlocking contracts (time-locking), completing an ICO after a few weeks, or enforcing expiry dates. It is sometimes recommended to use block.number and an average block time to estimate times; with a 10 second block time, 1 week equates to approximately, 60480 blocks. Thus, specifying a block number at which to change a contract state can be more secure, as miners are unable to easily manipulate the block number.
6. Event is missing indexed fields
Impact - Non-Critical
Each event should use three indexed fields if there are three or more fields
The functions uses an named return, while the rest of the contract and functions uses unamed returns. Please keep it consistent within contracts and accross the project if possible to improve readibility.
1. Avoid using Floating Pragma:
Description:
Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
Links to github files
ERC1967Proxy.sol:L2 UUPS.sol:L2 ERC1967Upgrade.sol:L2 ERC721Votes.sol:L2 ERC721.sol:L2
Instances
2. _safeMint() should be used rather than _mint() wherever possible
Description:
_mint()
is discouraged in favor of_safeMint()
which ensures that the recipient is either an EOA or implementsIERC721Receiver
. Both open OpenZeppelin and solmate have versions of this function so that NFTs aren’t lost if they’re minted to contracts that cannot transfer them back out.Links to github files
Token.sol:L161 Token.sol:L167 Token.sol:L169 Token.sol:L188 ERC721.sol:L191
Instances
Recommendations:
Use _safeMint() instead of _mint().
3. Use safeTransfer/safeTransferFrom consistently instead of transfer/transferFrom
Description
It is good to add a require() statement that checks the return value of token transfers or to use something like OpenZeppelin’s safeTransfer/safeTransferFrom unless one is sure the given token reverts in case of a failure. Failure to do so will cause silent failures of transfers and affect token accounting in contract.
Links to github files
Auction.sol:L192 Auction.sol:L363
Instances
Recommended Mitigation Steps
Consider using safeTransfer/safeTransferFrom or require() consistently.
4.Multiple initialization due to initialize function not having initializer modifier.
Description
The attacker can initialize the contract, take malicious actions, and allow it to be re-initialized by the project without any error being noticed.
Links to github files
IAuction.sol:L93 IToken.sol:L51 IBaseMetadata.sol:L27 IGovernor.sol:L119 ITreasury.sol:L64
Instances
5. Use of Block.timestamp
Impact - Non-Critical
Description
Block timestamps have historically been used for a variety of applications, such as entropy for random numbers (see the Entropy Illusion for further details), locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts.
Links to github files
Auction.sol:L98 Auction.sol:L141 Auction.sol:L149 Auction.sol:L178 Auction.sol:L211 Token.sol:L186 MetadataRenderer.sol:L251 ERC721Votes.sol:L61 ERC721Votes.sol:L153 ERC721Votes.sol:L253 Governor.sol:L128 Governor.sol:L160 Governor.sol:L170 Governor.sol:L218 Governor.sol:L363 Governor.sol:L433 Governor.sol:L437 Treasury.sol:L76 Treasury.sol:L89 Treasury.sol:L123
Instances
Recommended Mitigation Steps
Block timestamps should not be used for entropy or generating random numbers—i.e., they should not be the deciding factor (either directly or through some derivation) for winning a game or changing an important state.
Time-sensitive logic is sometimes required; e.g., for unlocking contracts (time-locking), completing an ICO after a few weeks, or enforcing expiry dates. It is sometimes recommended to use block.number and an average block time to estimate times; with a 10 second block time, 1 week equates to approximately, 60480 blocks. Thus, specifying a block number at which to change a contract state can be more secure, as miners are unable to easily manipulate the block number.
6. Event is missing
indexed
fieldsImpact - Non-Critical Each
event
should use threeindexed
fields if there are three or more fieldsLinks to github files
IAuction.sol:L22 IAuction.sol:L28 IAuction.sol:L34 IToken.sol:L21 IManager.sol:L21 IGovernor.sol:L42 ITreasury.sol:L22
Instances
7. Variable names that consist of all capital letters should be reserved for const/immutable variables
Description
If the variable needs to be different based on which class it comes from, a
view
/pure
function should be used insteadLinks to github files
Auction.sol:L31 Token.sol:L23 MetadataRenderer.sol:L25 Manager.sol:L25 Manager.sol:L28 Manager.sol:L31 Manager.sol:L34 Manager.sol:L37 Manager.sol:L40 Manager.sol:L43 Manager.sol:L46 Manager.sol:L49 Governor.sol:L34 Treasury.sol:L25
Instances
8. Incosistent return type within contracts
Description
The functions uses an named return, while the rest of the contract and functions uses unamed returns. Please keep it consistent within contracts and accross the project if possible to improve readibility.
Links to github files
Token.sol:L143 MetadataRenderer.sol:L206 Manager.sol:L104 Manager.sol:L158 Governor.sol:L305 ITreasury.sol:L96
Instances
Recommended Mitigation Steps
use unamed return for every function