When a stream sender of a FjordToken
stream in SablierV2LockUp
cancels a stream, the nonclaimable but VestedStaked
FjordToken
tokens will be refunded to the stream sender. The lack of implementattion of the supportInterface
function in the FjordStaking
contract makes notifying the FjordStaking
contract through FjordStaking::onStreamCanceled
to unstake these withdrawn tokens totally impossible.
Stream recipients can stake tokens vested in a SablierV2LockUp
contracts, and then transfer the recipient rights of the stream to the address of FjordStaking
contract, to ensure that no more tokens are withdrawn from this stream by the recipient.
Code from FjordStaking::StakeVested
Line 435
Issues arise when the stream sender decides, to cancel the stream. During this cancellation, the function FjordStaking::onStreamCanceled
is supposed to be called to ensure that the withdrawn deposited amount is deducted so that it stops accuring rewards for the stream owner/reciptient.
But in the logic of SablierV2LockUp::_cancel(streamId)
, for the function FjordStaking::onStreamCanceled
to called by the SablierV2LockUp
contract, the stream recipient, in this case the FjordStaking
contract, has to be _allowedToHook[recipient]
.
This leads to two issues:
The address of FjordStaking
contract has to be allowed to hook in FjordStaking::allowToHook(address recipient)
but this is an adminOnly function where the admin of the sablier contract may refuse to call this functiom on the FjordStaking
contract address.
Another issue which makes it totally impossible for the FjordStaking::onStreamCanceled
to be called is the fact that even if the admin of the sablier contract decides to do so, he cannot. Allow me to explain.
According to the sablier documentation a recipient must:-
In SablierV2LockUp::allowToHook(address recipient)
function a check call is made to the recipient contract to see if it implements the type(ISablierLockupRecipient).interfaceId
supportsInterface which the FjordStaking
contract does not.
As you can see, it reverts, and the admin cannot allow the contract to hook. The check in SablierV2LockUp::_cancel(streamId)
can't be true and the FjordStaking::onStreamCanceled
will never be called.
There is nowhere in the readme
of this contest where it says that stream senders will be trusted, they only have to be authorised.
The recipient of the stream will continue earning rewards forever for tokens that have already been withdrawn, hence a loss of rewards by the contract.
Manual Review
Consider implementing the support interface required by the Sablier contract so that you can be allowed to hook and notified when such withdraws are made.
Make sure the FjordStaking
contract is allowed to hook.
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.