You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Oct 1, 2023. It is now read-only.
sherlock-admin opened this issue
Mar 27, 2023
· 0 comments
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelMediumA valid Medium severity issueRewardA payout will be made for this issue
Adversary can trigger a regular end epoch for a null epoch and cause premium vault users to lose funds
Summary
Premium vault depositors lose their original deposits if the collateral vault has zero TVL and the ControllerPeggedAssetV2.triggerEndEpoch function is incorrectly called for a null epoch.
Vulnerability Detail
An epoch can be triggered invalid (i.e., null epoch) if one of the vaults has zero TVL by calling the ControllerPeggedAssetV2.triggerNullEpoch function. The counterparty vault, which has a non-zero TVL, will get the deposits refunded, and users can withdraw their original deposits.
However, even though an epoch qualifies as a null epoch, the ControllerPeggedAssetV2.triggerEndEpoch function can still be called. Incorrectly triggering the regular epoch's end will set the claimable TVL for the premium vault to 0 (line 181) and the premiums will be sent to the collateral vault.
If the premium vault has non-zero TVL and the collateral vault has zero TVL, premium vault depositors lose their original deposits.
Impact
An adversary can wrongfully call the triggerEndEpoch function for a null epoch and cause the premium vault depositors not to receive their deposits back.
144: function triggerEndEpoch(uint256_marketId, uint256_epochId) public {
145: address[2] memory vaults = vaultFactory.getVaults(_marketId);
146:
147: if (vaults[0] ==address(0) || vaults[1] ==address(0))
148: revertMarketDoesNotExist(_marketId);
149:
150: IVaultV2 premiumVault =IVaultV2(vaults[0]);
151: IVaultV2 collateralVault =IVaultV2(vaults[1]);
152:
153: if (
154: premiumVault.epochExists(_epochId) ==false||155: collateralVault.epochExists(_epochId) ==false156: ) revertEpochNotExist();
157:
158: (, uint40epochEnd, ) = premiumVault.getEpochConfig(_epochId);
159:
160: if (block.timestamp<=uint256(epochEnd)) revertEpochNotExpired();
161:
162: //require this function cannot be called twice in the same epoch for the same vault163: if (premiumVault.epochResolved(_epochId)) revertEpochFinishedAlready();
164: if (collateralVault.epochResolved(_epochId))
165: revertEpochFinishedAlready();
166:
167: premiumVault.resolveEpoch(_epochId);
168: collateralVault.resolveEpoch(_epochId);
169:
170: uint256 epochFee = vaultFactory.getEpochFee(_epochId);
171:
172: uint256 premiumTVL = premiumVault.finalTVL(_epochId);
173: uint256 collateralTVL = collateralVault.finalTVL(_epochId);
174:
175: uint256 premiumFee =calculateWithdrawalFeeValue(premiumTVL, epochFee);
176:
177: uint256 premiumTVLAfterFee = premiumTVL - premiumFee;
178: uint256 collateralTVLAfterFee = collateralTVL + premiumTVLAfterFee;
179:
180: // strike price is not reached so premium is entiled to 0181: @> premiumVault.setClaimTVL(_epochId, 0); // @audit-info premium vault's claim TVL is set to 0182: // strike price is not reached so collateral is entitled to collateralTVL + premiumTVLAfterFee183: collateralVault.setClaimTVL(_epochId, collateralTVLAfterFee);
184:
185: // send premium fees to treasury and remaining TVL to collateral vault186: premiumVault.sendTokens(_epochId, premiumFee, treasury);
187: // strike price reached so collateral is entitled to collateralTVLAfterFee188: premiumVault.sendTokens(
189: _epochId,
190: premiumTVLAfterFee,
191: address(collateralVault)
192: );
193:
194: emitEpochResolved(
195: _epochId,
196: _marketId,
197: VaultTVL(collateralTVLAfterFee, collateralTVL, 0, premiumTVL),
198: false,
199: block.timestamp,
200: 0201: );
202: }
Tool used
Manual Review
Recommendation
Consider adding checks to the triggerEndEpoch function to ensure that it is not called for null epochs (same as it is accomplished in the triggerDepeg function in lines 81-86).
Sign up for freeto subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelMediumA valid Medium severity issueRewardA payout will be made for this issue
berndartmueller
high
Adversary can trigger a regular end epoch for a null epoch and cause premium vault users to lose funds
Summary
Premium vault depositors lose their original deposits if the collateral vault has zero TVL and the
ControllerPeggedAssetV2.triggerEndEpoch
function is incorrectly called for a null epoch.Vulnerability Detail
An epoch can be triggered invalid (i.e., null epoch) if one of the vaults has zero TVL by calling the
ControllerPeggedAssetV2.triggerNullEpoch
function. The counterparty vault, which has a non-zero TVL, will get the deposits refunded, and users can withdraw their original deposits.However, even though an epoch qualifies as a null epoch, the
ControllerPeggedAssetV2.triggerEndEpoch
function can still be called. Incorrectly triggering the regular epoch's end will set the claimable TVL for the premium vault to0
(line 181) and the premiums will be sent to the collateral vault.If the premium vault has non-zero TVL and the collateral vault has zero TVL, premium vault depositors lose their original deposits.
Impact
An adversary can wrongfully call the
triggerEndEpoch
function for a null epoch and cause the premium vault depositors not to receive their deposits back.Code Snippet
v2/Controllers/ControllerPeggedAssetV2.sol - triggerEndEpoch()
Tool used
Manual Review
Recommendation
Consider adding checks to the
triggerEndEpoch
function to ensure that it is not called for null epochs (same as it is accomplished in thetriggerDepeg
function in lines 81-86).Duplicate of #108
The text was updated successfully, but these errors were encountered: