When doing withdraw() or withdrawAll() in StakedCitadel.sol, it will call the internal function _withdraw(). The function then transfers tokens to the vesting contract, which should be StakedCitadelVester.sol. However, IVesting(vesting).setupVesting() is not implemented in StakedCitadelVester.sol. This mistake makes the withdraw functions totally unusable.
Proof of Concept
In StakedCitadel.sol/_withdraw(), it uses IVesting(vesting).setupVesting(msg.sender, _amount, block.timestamp); to setup vesting.
/**
* @dev setup vesting for recipient.
* @notice note that a given address can only have one active vest at a time.
* @notice adding a new vest before claiming completely from the previous will re-lock the previous amount according to the new vesting timeline.
* @param recipient The account for which vesting will be setup.
* @param _amount amount that will be vested
* @param _unlockBegin The time at which unlocking of tokens will begin.
*/
function vest(
address recipient,
uint256 _amount,
uint256 _unlockBegin
) external {
require(msg.sender == vault, "StakedCitadelVester: only xCTDL vault");
require(_amount > 0, "StakedCitadelVester: cannot vest 0");
vesting[recipient].lockedAmounts =
vesting[recipient].lockedAmounts +
_amount;
vesting[recipient].unlockBegin = _unlockBegin;
vesting[recipient].unlockEnd = _unlockBegin + vestingDuration;
emit Vest(
recipient,
vesting[recipient].lockedAmounts,
_unlockBegin,
vesting[recipient].unlockEnd
);
}
Tools Used
vim
Recommended Mitigation Steps
Either
replace IVesting(vesting).setupVesting with IVesting(vesting).vest in StakedCitadel.sol
or
replace vest with setupVesting in StakedCitadelVester.sol
Lines of code
https://github.com/code-423n4/2022-04-badger-citadel/blob/main/src/StakedCitadel.sol#L830 https://github.com/code-423n4/2022-04-badger-citadel/blob/main/src/StakedCitadelVester.sol#L125
Vulnerability details
Impact
When doing
withdraw()
orwithdrawAll()
inStakedCitadel.sol
, it will call the internal function_withdraw()
. The function then transfers tokens to the vesting contract, which should beStakedCitadelVester.sol
. However,IVesting(vesting).setupVesting()
is not implemented inStakedCitadelVester.sol
. This mistake makes the withdraw functions totally unusable.Proof of Concept
In
StakedCitadel.sol/_withdraw()
, it usesIVesting(vesting).setupVesting(msg.sender, _amount, block.timestamp);
to setup vesting.https://github.com/code-423n4/2022-04-badger-citadel/blob/main/src/StakedCitadel.sol#L830
However in
StakedCitadelVester.sol
. The setup function is actuallyvest()
.setupVesting()
is not implemented inStakedCitadelVester.sol
https://github.com/code-423n4/2022-04-badger-citadel/blob/main/src/StakedCitadelVester.sol#L125
Tools Used
vim
Recommended Mitigation Steps
Either
replace
IVesting(vesting).setupVesting
withIVesting(vesting).vest
inStakedCitadel.sol
or
replace
vest
withsetupVesting
inStakedCitadelVester.sol