NC031 - Using >/>= without specifying an upper bound is unsafe:
There will be breaking changes in future versions of solidity, and at that point your code will no longer be compatable. While you may have the specific version to use in a configuration file, others that include your source files may not.
Click to show 19 findings
File: v2-core/src/SablierV2LockupDynamic.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/SablierV2LockupDynamic.sol#L0:0
File: v2-core/src/SablierV2LockupLinear.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/SablierV2LockupLinear.sol#L0:0
File: v2-core/src/SablierV2LockupTranched.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/SablierV2LockupTranched.sol#L0:0
File: v2-core/src/SablierV2NFTDescriptor.sol
3 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/SablierV2NFTDescriptor.sol#L0:0
File: v2-core/src/abstracts/Adminable.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/abstracts/Adminable.sol#L0:0
File: v2-core/src/abstracts/NoDelegateCall.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/abstracts/NoDelegateCall.sol#L0:0
File: v2-core/src/abstracts/SablierV2Lockup.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/abstracts/SablierV2Lockup.sol#L0:0
File: v2-core/src/libraries/Errors.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/libraries/Errors.sol#L0:0
File: v2-core/src/libraries/Helpers.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/libraries/Helpers.sol#L0:0
File: v2-core/src/libraries/NFTSVG.sol
3 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/libraries/NFTSVG.sol#L0:0
File: v2-core/src/libraries/SVGElements.sol
3 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/libraries/SVGElements.sol#L0:0
File: v2-core/src/types/DataTypes.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/types/DataTypes.sol#L0:0
File: v2-periphery/src/SablierV2BatchLockup.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/SablierV2BatchLockup.sol#L0:0
File: v2-periphery/src/SablierV2MerkleLL.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/SablierV2MerkleLL.sol#L0:0
File: v2-periphery/src/SablierV2MerkleLT.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/SablierV2MerkleLT.sol#L0:0
File: v2-periphery/src/SablierV2MerkleLockupFactory.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/SablierV2MerkleLockupFactory.sol#L0:0
File: v2-periphery/src/abstracts/SablierV2MerkleLockup.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/abstracts/SablierV2MerkleLockup.sol#L0:0
File: v2-periphery/src/libraries/Errors.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/libraries/Errors.sol#L0:0
File: v2-periphery/src/types/DataTypes.sol
2 pragma solidity >=0.8.22;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/types/DataTypes.sol#L0:0
NC032 - Top level declarations should be separated by two blank lines:
File: v2-periphery/src/types/DataTypes.sol
112
90
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/types/DataTypes.sol#L0:0
NC033 - Duplicate import statements:
This issue arises when the same file is imported multiple times.
File: v2-core/src/SablierV2LockupLinear.sol
10 import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol";
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/SablierV2LockupLinear.sol#L0:0
NC034 - Custom error has no error details:
Consider adding parameters to the error to indicate which user or values caused the failure.
File: v2-core/src/libraries/Errors.sol
18 error DelegateCall();
28 error SablierV2Lockup_DepositAmountZero();
43 error SablierV2Lockup_StartTimeZero();
90 error SablierV2LockupDynamic_SegmentCountZero();
144 error SablierV2LockupTranched_TrancheCountZero();
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/libraries/Errors.sol#L0:0
File: v2-periphery/src/libraries/Errors.sol
11 error SablierV2BatchLockup_BatchSizeZero();
28 error SablierV2MerkleLockup_InvalidProof();
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/v2-core/src/libraries/Errors.sol#L0:0
NC035 - Unused struct
definition:
Note that there may be cases where a struct superficially appears to be used, but this is only because there are multiple definitions of the struct in different files. In such cases, the struct definition should be moved into a separate file. The instances below are the unused definitions.
Click to show 9 findings
File: v2-periphery/src/types/DataTypes.sol
struct CancelMultiple {
ISablierV2Lockup lockup;
uint256[] streamIds;
}
struct CreateWithDurationsLD {
address sender;
address recipient;
uint128 totalAmount;
bool cancelable;
bool transferable;
LockupDynamic.SegmentWithDuration[] segments;
Broker broker;
}
struct CreateWithDurationsLL {
address sender;
address recipient;
uint128 totalAmount;
bool cancelable;
bool transferable;
LockupLinear.Durations durations;
Broker broker;
}
struct CreateWithDurationsLT {
address sender;
address recipient;
uint128 totalAmount;
bool cancelable;
bool transferable;
LockupTranched.TrancheWithDuration[] tranches;
Broker broker;
}
struct CreateWithTimestampsLD {
address sender;
address recipient;
uint128 totalAmount;
bool cancelable;
bool transferable;
uint40 startTime;
LockupDynamic.Segment[] segments;
Broker broker;
}
struct CreateWithTimestampsLL {
address sender;
address recipient;
uint128 totalAmount;
bool cancelable;
bool transferable;
LockupLinear.Timestamps timestamps;
Broker broker;
}
struct CreateWithTimestampsLT {
address sender;
address recipient;
uint128 totalAmount;
bool cancelable;
bool transferable;
uint40 startTime;
LockupTranched.Tranche[] tranches;
Broker broker;
}
struct ConstructorParams {
IERC20 asset;
bool cancelable;
uint40 expiration;
address initialAdmin;
string ipfsCID;
bytes32 merkleRoot;
string name;
bool transferable;
}
struct TrancheWithPercentage {
UD2x18 unlockPercentage;
uint40 duration;
}
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/types/DataTypes.sol#L120:124
NC036 - Events are missing sender information:
When an action is triggered based on a user's action, not being able to filter based on who triggered the action makes event processing a lot more cumbersome. Including the msg.sender the events of these types of action will make events much more useful to end users. Include msg.sender
in the event output.
Click to show 5 findings
File: v2-core/src/abstracts/SablierV2Lockup.sol
304 emit ISablierV2Lockup.RenounceLockupStream(streamId);
328 emit BatchMetadataUpdate({ _fromTokenId: 1, _toTokenId: nextStreamId - 1 });
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/abstracts/SablierV2Lockup.sol#L0:0
File: v2-periphery/src/SablierV2MerkleLL.sol
94 emit Claim(index, recipient, amount, streamId);
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/SablierV2MerkleLL.sol#L0:0
File: v2-periphery/src/SablierV2MerkleLT.sol
112 emit Claim(index, recipient, amount, streamId);
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/SablierV2MerkleLT.sol#L0:0
File: v2-periphery/src/SablierV2MerkleLockupFactory.sol
39 emit CreateMerkleLL(merkleLL, baseParams, lockupLinear, streamDurations, aggregateAmount, recipientCount);
74 emit CreateMerkleLT(
75 merkleLT,
76 baseParams,
77 lockupTranched,
78 tranchesWithPercentages,
79 totalDuration,
80 aggregateAmount,
81 recipientCount
82 );
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/SablierV2MerkleLockupFactory.sol#L0:0
File: v2-periphery/src/abstracts/SablierV2MerkleLockup.sol
121 emit Clawback(admin, to, amount);
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-periphery/src/abstracts/SablierV2MerkleLockup.sol#L0:0
NC037 - Enum values should be used in place of constant array indexes:
Create a commented enum value to use in place of constant array indexes, this makes the code far easier to understand.
File: v2-core/src/SablierV2LockupDynamic.sol
229 uint40 currentSegmentTimestamp = segments[0].timestamp;
292 SD59x18 exponent = _segments[streamId][0].exponent.intoSD59x18();
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/SablierV2LockupDynamic.sol#L0:0
File: v2-core/src/SablierV2LockupTranched.sol
188 if (tranches[0].timestamp > blockTimestamp) {
200 uint128 streamedAmount = tranches[0].amount;
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/SablierV2LockupTranched.sol#L0:0
File: v2-core/src/libraries/Helpers.sol
32 segmentsWithTimestamps[0] = LockupDynamic.Segment({
33 amount: segments[0].amount,
34 exponent: segments[0].exponent,
35 timestamp: startTime + segments[0].duration
65 tranchesWithTimestamps[0] =
66 LockupTranched.Tranche({ amount: tranches[0].amount, timestamp: startTime + tranches[0].duration });
66 LockupTranched.Tranche({ amount: tranches[0].amount, timestamp: startTime + tranches[0].duration });
236 if (startTime >= segments[0].timestamp) {
238 startTime, segments[0].timestamp
299 if (startTime >= tranches[0].timestamp) {
301 startTime, tranches[0].timestamp
https://github.com/Cyfrin/2024-05-Sablier/tree/main/v2-core/src/libraries/Helpers.sol#L0:0