Impact
There are requirements concerning the LiquidationPool stated in the The Standard whitepaper. These are enforced to keep the ecosystem stable and its stablecoins pegged to their respective real-world currency.
Not complying with the requirements may contribue to the collapsing of the ecosystem.
In order to do so, The Standard wants to enforce the following :
2.8. Liquidation of Smart Vaults
...
This process is essential for maintaining the peg of sEURO to the Euro and ensuring that the system remains over-collateralized
...
The liquidation pool comprises sEURO and TST tokens staked by participants in a 1:1 ratio
...
Participants can withdraw their TST and sEURO from the pool at any time, but they must always maintain an equal or higher amount of TST compared to sEURO staked
...
The minimum stake for participating in the liquidation pool is 100 sEURO.
The function responsible for staking assets in the Pool is increasePosition()
https://github.com/Cyfrin/2023-12-the-standard/blob/main/contracts/LiquidationPool.sol#L134-L142
function increasePosition(uint256 _tstVal, uint256 _eurosVal) external {
require(_tstVal > 0 || _eurosVal > 0);
consolidatePendingStakes();
ILiquidationPoolManager(manager).distributeFees();
if (_tstVal > 0) IERC20(TST).safeTransferFrom(msg.sender, address(this), _tstVal);
if (_eurosVal > 0) IERC20(EUROs).safeTransferFrom(msg.sender, address(this), _eurosVal);
pendingStakes.push(PendingStake(msg.sender, block.timestamp, _tstVal, _eurosVal));
addUniqueHolder(msg.sender);
}
As we can see, there are no require() statements or anything checks that enforce the user to stake only a 1:1 ratio or a minimum of 100 EUROs
The function responsible for unstaking assets in the Pool is decreasePosition()
https://github.com/Cyfrin/2023-12-the-standard/blob/main/contracts/LiquidationPool.sol#L149-L162
function decreasePosition(uint256 _tstVal, uint256 _eurosVal) external {
consolidatePendingStakes();
ILiquidationPoolManager(manager).distributeFees();
require(_tstVal <= positions[msg.sender].TST && _eurosVal <= positions[msg.sender].EUROs, "invalid-decr-amount");
if (_tstVal > 0) {
IERC20(TST).safeTransfer(msg.sender, _tstVal);
positions[msg.sender].TST -= _tstVal;
}
if (_eurosVal > 0) {
IERC20(EUROs).safeTransfer(msg.sender, _eurosVal);
positions[msg.sender].EUROs -= _eurosVal;
}
if (empty(positions[msg.sender])) deletePosition(positions[msg.sender]);
}
As we can see, there are no require() statements or anything checks that enforce the user to leave an equal or higher amount of TST when unstaking.
Tools used
Manual analysis
Recommended mitigation steps
Enforce the stated requirements