elapsedTime
belowThere's no check for _streams[streamId].startTime > block.timestamp
. Resulting in a waste of gas to arrive to return 0
.
Contrasting with SablierV2LockupTranched._calculateStreamedAmount()
and SablierV2LockupDynamic_calculateStreamedAmount()
, there's no check for _streams[streamId].startTime > block.timestamp
in SablierV2LockupLinear
.
When cliffTime is set to 0, there will be a waste of gas in unnecesary math. Further impact is prevented by the implementation of the bug check at the end of the function:
Thus,return 0
will still be the outcome. However, there's no need to run all the above math wasting gas unnecesarily.
Manual check
Replace L193-L195 with the below code and remove L207.
Some ERC20 tokens will revert on max approve.
Affects
https://github.com/Cyfrin/2024-05-Sablier/blob/43d7e752a68bba2a1d73d3d6466c3059079ed0c6/v2-periphery/src/SablierV2MerkleLL.sol#L40-L52
And
https://github.com/Cyfrin/2024-05-Sablier/blob/43d7e752a68bba2a1d73d3d6466c3059079ed0c6/v2-periphery/src/SablierV2MerkleLT.sol#L40-L58
Not every ERC20 token allows for type(uint256).max
approve. This is not solved by forceApprove()
since its intention is different, as it can be seen in its natSpec:
Contract creation will revert in
https://github.com/Cyfrin/2024-05-Sablier/blob/43d7e752a68bba2a1d73d3d6466c3059079ed0c6/v2-periphery/src/SablierV2MerkleLockupFactory.sol#L25
And
https://github.com/Cyfrin/2024-05-Sablier/blob/43d7e752a68bba2a1d73d3d6466c3059079ed0c6/v2-periphery/src/SablierV2MerkleLockupFactory.sol#L43
Manual check
Use aggregateAmount
instead of type(uint256).max
ERC20 is approved in SablierV2MerkleLL.constructor()
and SablierV2MerkleLT.constructor()
but not transfered by sender. Should be transfered in SablierV2MerkleLockupFactory.createMerkleLL()
and SablierV2MerkleLockupFactory.createMerkleLT()
, following how the protocol handles it. To prevent claims to revert because of sender forgetting to do it afterwards.
In the constructors of SablierV2MerkleLL
and SablierV2MerkleLT
, the ERC20 holded by the contracts is approved to be handled by SablierV2MerkleLockupFactory. But following protocol money workflow, a recipient can claim without having the ERC20 yet deposited. This would result in an unclear revert()
as a result of a failed SablierV2LockupLinear.createWithDurations()
or SablierV2LockupTranched.createWithDurations()
Example for Linear Airstream:
Call to
https://github.com/Cyfrin/2024-05-Sablier/blob/43d7e752a68bba2a1d73d3d6466c3059079ed0c6/v2-periphery/src/SablierV2MerkleLockupFactory.sol#L25-L40
Which triggers the constructor()
https://github.com/Cyfrin/2024-05-Sablier/blob/43d7e752a68bba2a1d73d3d6466c3059079ed0c6/v2-periphery/src/SablierV2MerkleLL.sol#L40-L52
When claiming
https://github.com/Cyfrin/2024-05-Sablier/blob/43d7e752a68bba2a1d73d3d6466c3059079ed0c6/v2-periphery/src/SablierV2MerkleLL.sol#L59-L95
The below line reverts
https://github.com/Cyfrin/2024-05-Sablier/blob/43d7e752a68bba2a1d73d3d6466c3059079ed0c6/v2-core/src/SablierV2LockupLinear.sol#L277
If the sender forgets to send funds before recipients claim, they won't be able to claim the stream.
Manual check
Do the transfer of ERC20 to the SablierV2MerkleLL
and SablierV2MerkleLT
contracts in SablierV2MerkleLockupFactory.SablierV2MerkleLockupFactory:L37 and SablierV2MerkleLockupFactory.SablierV2MerkleLockupFactory:L72
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.