1. 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.
Consider using safeTransfer/safeTransferFrom or require() consistently.
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.
src/Swap/BaseV1-core.sol:305: _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
src/Swap/BaseV1-core.sol:311: _mint(to, liquidity);
Recommendations:
Use _safeMint() instead of _mint().
3. require()/revert() statements should have descriptive reason strings
require / revert statement should have descriptive string reasons along with the statement so it is a better practice to include descriptive reason strings
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. Variable names that consist of all capital letters should be reserved for const/immutable variables
If the variable needs to be different based on which class it comes from, a view/pure function should be used instead (e.g. like this).
1. 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.
Instances
//Links to github Files: BaseV1-periphery.sol:L282 BaseV1-periphery.sol:L300 BaseV1-periphery.sol:L428 BaseV1-periphery.sol:L475
Actual codes used:
Recommended Mitigation Steps
Consider using safeTransfer/safeTransferFrom or require() consistently.
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.Instances :
//Links to github files: BaseV1-core.sol:L305 BaseV1-core.sol:L311
Actual Codes used:
Recommendations:
Use _safeMint() instead of _mint().
3. require()/revert() statements should have descriptive reason strings
require / revert statement should have descriptive string reasons along with the statement so it is a better practice to include descriptive reason strings
Instances:
// Links to github files BaseV1-periphery.sol:L90 BaseV1-periphery.sol:L219 BaseV1-periphery.sol:L220 BaseV1-periphery.sol:L300 BaseV1-periphery.sol:L465 BaseV1-periphery.sol:L468 BaseV1-core.sol:L100 BaseV1-core.sol:L108 BaseV1-core.sol:L342 BaseV1-core.sol:L523 BaseV1-core.sol:L526 BaseV1-core.sol:L556 BaseV1-core.sol:L561 BaseV1-core.sol:L562 BaseV1-core.sol:L576 BaseV1-core.sol:L581 BaseV1-core.sol:L586
Actual codes used
4.
EVENT
IS MISSING INDEXED FIELDSDescription
Each event should use three indexed fields if there are three or more fields
Instances
//Links to Githubfile BaseV1-core.sol:L65 BaseV1-core.sol:L66 BaseV1-core.sol:L76 BaseV1-core.sol:L78 BaseV1-core.sol:L79 BaseV1-core.sol:L546
Actual codes used:
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.
Instances
// Link to Github files: BaseV1-periphery.sol:L71 BaseV1-core.sol:L96 BaseV1-core.sol:L138 BaseV1-core.sol:L159 BaseV1-core.sol:L176 BaseV1-core.sol:L180 BaseV1-core.sol:L471
Actual codes used:
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. Variable names that consist of all capital letters should be reserved for const/immutable variables
If the variable needs to be different based on which class it comes from, a view/pure function should be used instead (e.g. like this).
Instances :
// Links to github files: BaseV1-core.sol:L18 BaseV1-core.sol:L32 BaseV1-core.sol:L33 BaseV1-core.sol:L34 BaseV1-core.sol:L49 BaseV1-core.sol:L50 BaseV1-periphery.sol:L49 BaseV1-periphery.sol:L51 BaseV1-periphery.sol:L61 BaseV1-periphery.sol:L62 BaseV1-periphery.sol:L64 BaseV1-core.sol:L15
Actual codes used