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.
src/Swap/BaseV1-periphery.sol:282: assert(wcanto.transfer(pair, amountCANTO));
src/Swap/BaseV1-periphery.sol:300: require(IBaseV1Pair(pair).transferFrom(msg.sender, pair, liquidity)); // send liquidity to pair
src/Swap/BaseV1-periphery.sol:428: assert(wcanto.transfer(pairFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]));
src/Swap/BaseV1-periphery.sol:467: token.call(abi.encodeWithSelector(erc20.transfer.selector, to, value));
src/Swap/BaseV1-periphery.sol:475: tokenCon.transferFrom(from, to, value);
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 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.
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
Description:
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
BaseV1-periphery.sol:L282 BaseV1-periphery.sol:L300 BaseV1-periphery.sol:L428 BaseV1-periphery.sol:L467 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 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.
Instances
BaseV1-core.sol:L305 BaseV1-core.sol:L311
Actual codes used:
Recommendations:
Use _safeMint() instead of _mint().
3.
EVENT
IS MISSING INDEXED FIELDSEach event should use three indexed fields if there are three or more fields.
Instances:
BaseV1-core.sol:L65 BaseV1-core.sol:L66 BaseV1-core.sol:L546 BaseV1-core.sol:L76 BaseV1-core.sol:L78 BaseV1-core.sol:L79
Actual codes used:
4. require()/revert() statements should have descriptive reason strings
Instances:
BaseV1-periphery.sol:L465 BaseV1-periphery.sol:L468 BaseV1-core.sol:L556 BaseV1-core.sol:L561 BaseV1-core.sol:L562 BaseV1-core.sol:L576 BaseV1-core.sol:L581 BaseV1-core.sol:L586 BaseV1-core.sol:L100 BaseV1-core.sol:L108 BaseV1-periphery.sol:L219 BaseV1-periphery.sol:L90 BaseV1-periphery.sol:L220 BaseV1-periphery.sol:L300 BaseV1-core.sol:L342 BaseV1-core.sol:L523 BaseV1-core.sol:L526
5. Use of Block.timestamp
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
BaseV1-core.sol:L96 BaseV1-core.sol:L138 BaseV1-core.sol:L159 BaseV1-core.sol:L176 BaseV1-core.sol:L180 BaseV1-core.sol:L471 BaseV1-periphery.sol:L71
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
Description:
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 :
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