The cancel of streamId can't change the stake state of streamId. The stake amount of streamId is wrong and the user will get more reward.
Paste code below in test/intergration folder.
pragma solidity =0.8.21;
import { FjordStaking } from "../../src/FjordStaking.sol";
import { FjordPoints } from "../../src/FjordPoints.sol";
import { FjordToken } from "../../src/FjordToken.sol";
import { ISablierV2LockupLinear } from "lib/v2-core/src/interfaces/ISablierV2LockupLinear.sol";
import { ISablierV2Lockup } from "lib/v2-core/src/interfaces/ISablierV2Lockup.sol";
import { Broker, LockupLinear } from "lib/v2-core/src/types/DataTypes.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ud60x18 } from "@prb/math/src/UD60x18.sol";
import { Test } from "forge-std/Test.sol";
contract HookRevert is Test {
FjordStaking stake;
FjordPoints points;
FjordToken fjo;
uint256 streamId;
address deployer = makeAddr("deployer");
address rewardAdmin = makeAddr("rewardAdmin");
address sablierSender = makeAddr("sablierSender");
address user = makeAddr("user");
address internal constant SABLIER_ADDRESS = address(0xB10daee1FCF62243aE27776D7a92D39dC8740f95);
ISablierV2LockupLinear SABLIER = ISablierV2LockupLinear(SABLIER_ADDRESS);
function setUp() public {
uint256 mainnetFork = vm.createFork(vm.envString("ETHEREUM_RPC"), 18258796);
vm.selectFork(mainnetFork);
vm.startPrank(deployer);
fjo = new FjordToken();
points = new FjordPoints();
stake = new FjordStaking(
address(fjo), rewardAdmin, SABLIER_ADDRESS, sablierSender, address(points)
);
points.setStakingContract(address(stake));
vm.stopPrank();
streamId = createStream(sablierSender, user, IERC20(address(fjo)), true, 1 ether);
}
function test_hookRevert() public {
vm.startPrank(user);
vm.warp(block.timestamp + 5 days);
SABLIER.approve(address(stake), streamId);
stake.stakeVested(streamId);
vm.stopPrank();
vm.startPrank(sablierSender);
ISablierV2Lockup(SABLIER_ADDRESS).cancel(streamId);
vm.stopPrank();
}
function createStream(
address sender,
address recipient,
IERC20 asset,
bool isCancelable,
uint256 amount
) internal returns (uint256 streamID) {
deal(address(asset), sender, amount);
vm.prank(sender);
asset.approve(address(SABLIER), amount);
LockupLinear.CreateWithRange memory params;
params.sender = sender;
params.recipient = recipient;
params.totalAmount = uint128(amount);
params.asset = IERC20(address(asset));
params.cancelable = isCancelable;
params.range = LockupLinear.Range({
start: uint40(block.timestamp + 1 days),
cliff: uint40(block.timestamp + 1 days),
end: uint40(block.timestamp + 11 days)
});
params.broker = Broker(address(0), ud60x18(0));
vm.prank(sender);
streamID = SABLIER.createWithRange(params);
}
}
├─ [79614] 0xB10daee1FCF62243aE27776D7a92D39dC8740f95::cancel(58)
│ ├─ [29606] FjordToken::transfer(sablierSender: [0xB9D6e253E40B396bA13B0f59B7816192708803c9], 600000000000000000 [6e17])
│ │ ├─ emit Transfer(from: 0xB10daee1FCF62243aE27776D7a92D39dC8740f95, to: sablierSender: [0xB9D6e253E40B396bA13B0f59B7816192708803c9], value: 600000000000000000 [6e17])
│ │ └─ ← [Return] true
│ ├─ [15460] FjordStaking::onStreamCanceled(58, sablierSender: [0xB9D6e253E40B396bA13B0f59B7816192708803c9], 600000000000000000 [6e17], 400000000000000000 [4e17])
│ │ ├─ [8365] FjordPoints::onUnstaked(0xB10daee1FCF62243aE27776D7a92D39dC8740f95, 600000000000000000 [6e17])
│ │ │ └─ ← [Revert] UnstakingAmountExceedsStakedAmount()
│ │ └─ ← [Revert] UnstakingAmountExceedsStakedAmount()
│ ├─ emit CancelLockupStream(streamId: 58, sender: sablierSender: [0xB9D6e253E40B396bA13B0f59B7816192708803c9], recipient: FjordStaking: [0xfF2Bd636B9Fc89645C2D336aeaDE2E4AbaFe1eA5], senderAmount: 600000000000000000 [6e17], recipientAmount: 400000000000000000 [4e17])
│ ├─ emit MetadataUpdate(: 58)
│ └─ ← [Return]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
└─ ← [Stop]