xanoutas/solidity-security-findings huggingface dataset:
sakshamguruji - raBalance and paBalance Not Decremented When Redeeming Excess
Audit: 2024-08-cork-protocol-judging
Severity: HIGH

sakshamguruji

High

# raBalance and paBalance Not Decremented When Redeeming Excess

## Summary

When redeem() is invoked , user's LV is redeemed for RA and PA and after redemption the raBalance and paBalance are adjusted , but if the redemption was an excess redemption then the raBalance and paBalance have not been adjusted .

## Vulnerability Detail

1.) When redeeming after expiry the LP is liquidated and redeem is invoked ->

https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultLib.sol#L549

But this can be an excess redeem too , which is a redeem where DS has been expired and now the user can redeem LV which was not requested pre expiry.

2.) In the redeem() since we are redeeming excess (In an excess redeem we would still need to decrement the raBalance and paBalance since there can be some LV which were requested pre expiry and some which were excess) ->

https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultPoolLib.sol#L89

`_redeemExcessFromPool` calls `__tryRedeemExcessFromAmmPool` ->


```solidity
function __tryRedeemfromWithdrawalPool(VaultPool storage self, uint256 amount)
        internal
        view
        returns (uint256 ra, uint256 pa)
    {
        ra = MathHelper.calculateRedeemAmountWithExchangeRate(amount, self.withdrawalPool.raExchangeRate);

        pa = MathHelper.calculateRedeemAmountWithExchangeRate(amount, self.withdrawalPool.paExchangeRate);
    }

    function __tryRedeemExcessFromAmmPool(VaultPool storage self, uint256 amountAttributed, uint256 excessAmount)
        internal
        view
        returns (uint256 ra, uint256 pa, uint256 withdrawnFromAmm)
    {
        (ra, pa) = __tryRedeemfromWithdrawalPool(self, amountAttributed);

        withdrawnFromAmm =
            MathHelper.calculateRedeemAmountWithExchangeRate(excessAmount, self.withdrawalPool.raExchangeRate);

        ra += withdrawnFromAmm;
    }
```

And nowhere is `self.withdrawalPool.raBalance -= ra;` and `self.withdrawalPool.paBalance -= pa;` decremented like they are decremented for a non excess redemotion here https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultPoolLib.sol#L133 .

3.) This means `self.withdrawalPool.raBalance` `self.withdrawalPool.paBalance` is accounting more value than the correct one , therefore , when reserve() is called for the next iteration the `totalRa` will be storing incorrect value ->

https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultPoolLib.sol#L17

4.) And the values `(uint256 attributedToWithdraw, uint256 attributedToAmm, uint256 ratePerLv)` would be incorrect since an incorrect 
`totalRa` was passed here ->

`MathHelper.separateLiquidity(totalRa, totalLvIssued, totalLvWithdrawn)`

The ratePerLv will be higher and users get more than expected Ra AND PA.

## Impact

Incorreect redemption amounts due to not accounting raB
0xNirix - Missing Exchange Rate consideration in unsafeIssueToLv causes excessive CT/DS token Issuance
Audit: 2024-08-cork-protocol-judging
Severity: HIGH

0xNirix

Medium

# Missing Exchange Rate consideration in unsafeIssueToLv causes excessive CT/DS token Issuance

### Summary

The protocol will issue excess CT/DS tokens during both user deposits and fee deposits due to missing exchange rate consideration in unsafeIssueToLv, leading to unintended gains and potential economic imbalance.

### Root Cause

In VaultLibrary.sol:__provideLiquidity call to PsmLib.sol:unsafeIssueToLv, the functions issue CT/DS tokens in a 1:1 ratio with RA without considering the current exchange rate

https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/PsmLib.sol#L115

```solidity
function __provideLiquidity(
    State storage self,
    uint256 raAmount,
    uint256 ctAmount,
    IDsFlashSwapCore flashSwapRouter,
    address ctAddress,
    IUniswapV2Router02 ammRouter,
    uint256 dsId
) internal {
    // ... (other code)
    PsmLibrary.unsafeIssueToLv(self, ctAmount);
    // ... (other code)
}
```
```solidity
// PsmLib.sol
function unsafeIssueToLv(State storage self, uint256 amount) internal {
    uint256 dsId = self.globalAssetIdx;
    DepegSwap storage ds = self.ds[dsId];
    self.psm.balances.ra.incLocked(amount);
    ds.issue(address(this), amount);
}
```

### Internal pre-conditions

1.Exchange rate between RA and CT/DS needs to be greater than 1.

### External pre-conditions

_No response_

### Attack Path

1. User deposits 200 RA or the protocol collects 200 RA as fees when the exchange rate is 1.2 (1 RA = 1.2 CT/DS).
2. For user deposits, the deposit function in VaultLibrary is called. For fees, provideLiquidityWithFee is called. Both eventually call __provideLiquidityWithRatio.
3. __provideLiquidityWithRatio calls __provideLiquidity, which uses unsafeIssueToLv to mint CT/DS tokens.
4. Assuming a 50:50 ratio for RA and CS during rationing, instead of minting 83.33 CT/DS tokens (100 / 1.2), the function mints 100 CT/DS tokens in exchange of 100 RA
5. For user deposits, the user receives 100 LV tokens. For fees, the protocol receives 100 CT/DS tokens to be added to liquidity.

### Impact

The protocol issues more CT/DS tokens than it should as shown in attack path, leading to various problems like

Token Dilution: Excess issuance of CT/DS tokens dilutes their value, potentially affecting all token holders.
Unintended Gains: Both users (via LV tokens) and the protocol (via fee collection) receive more CT/DS value than intended based on the true RA value.

### PoC

_No response_

### Mitigation

Modify unsafeIssueToLv to account for the exchange rate.

Duplicate of #119
0xNirix - Lack of exchange rate consideration during lvRedeemRaWithCtDs will cause loss for users and protocol
Audit: 2024-08-cork-protocol-judging
Severity: HIGH

0xNirix

Medium

# Lack of exchange rate consideration during lvRedeemRaWithCtDs will cause loss for users and protocol

### Summary

The absence of exchange rate consideration in the lvRedeemRaWithCtDs function will cause an unfair redemption process for users and value loss for the protocol. Users will receive less RA than the current market value of their LV tokens when redeeming early, and the protocol will suffer a similar loss when liquidating LP during new issuance.


### Root Cause

In PSMLib:lvRedeemRaWithCtDs the function burns CT and DS tokens without considering their current value relative to RA, effectively treating them as always equal in value to RA
https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/PsmLib.sol#L125
 lvRedeemRaWithCtDs function:
```solidity 
function lvRedeemRaWithCtDs(State storage self, uint256 amount, uint256 dsId) internal {
    DepegSwap storage ds = self.ds[dsId];
    ds.burnBothforSelf(amount);
}
```
The issue here is that this function simply burns the CT and DS tokens without considering their current value relative to RA. It implicitly assumes a 1:1 ratio.

For example this function is used in early redemption:
```solidity
function _redeemCtDsAndSellExcessCt(
    State storage self,
    uint256 dsId,
    IUniswapV2Router02 ammRouter,
    IDsFlashSwapCore flashSwapRouter,
    uint256 ammCtBalance
) internal returns (uint256 ra) {
    uint256 reservedDs = flashSwapRouter.getLvReserve(self.info.toId(), dsId);
    uint256 redeemAmount = reservedDs >= ammCtBalance ? ammCtBalance : reservedDs;
    reservedDs = flashSwapRouter.emptyReservePartial(self.info.toId(), dsId, redeemAmount);
    ra += redeemAmount;
    PsmLibrary.lvRedeemRaWithCtDs(self, redeemAmount, dsId);
   
}
```
In this function, lvRedeemRaWithCtDs is called with redeemAmount, but the ra is simply incremented by redeemAmount, assuming a 1:1 ratio.

### Internal pre-conditions

1. The exchange rate between CT/DS and RA needs to be greater than 1:1


### External pre-conditions

_No response_

### Attack Path

1. User calls redeemEarly function with a certain amount of LV tokens
2. redeemEarly calls _liquidateLpPartial, which liquidates LP tokens for CT and RA
3. _liquidateLpPartial then calls _redeemCtDsAndSellExcessCt, which in turn calls lvRedeemRaWithCtDs
4. lvRedeemRaWithCtDs burns the CT and DS tokens at a 1:1 ratio with RA, ignoring their current market value
5. User receives less RA than the current market value of their original LV tokens

Similarly for protocol during new Issuance, _liquidatedLp calls lvRedeemRaWithCtDs.

### Impact

The users redeeming LV tokens early suffer a loss proportional to the difference between the current market value of CT/DS and the 1:1 ratio used in the redemption. The protocol suffers a similar loss when liquidating LP during new issuance. 

### PoC

_No response_

### Mitigation

Implement exchange rate for lvRedeemRaWithCtDs

Duplicate of #119
4b - No slippage in `_redeemCtDsAndSellExcessCt`
Audit: 2024-08-cork-protocol-judging
Severity: HIGH

4b

Medium

# No slippage in `_redeemCtDsAndSellExcessCt`

### Summary

`amountOutMin` is set to zero when calling `swapExactTokensForTokens` in _redeemCtDsAndSellExcessCt.

### Root Cause

in [line 345](https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultLib.sol#L345) `amountOutMin` is set to zero.

### Internal pre-conditions

1. when `_redeemCtDsAndSellExcessCt` is called 

### External pre-conditions

price of tokenOut falls while redeeming


### Attack Path

1. User calls `redeemEarlyLv`
2. functions invoke respective functions that lead to the swap
3. External conditions kick in to make amountOut lower than expected
4. No slippage so it goes on with the swap


### Impact

when redeeming lv, somtimes caller can get lower amount than expected. 

### PoC

our function 
`ammRouter.swapExactTokensForTokens(ctSellAmount, 0, path, address(this), block.timestamp)[1];`

`uniswapv2router02 swapExactTokensForTokens`
```solidity
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external virtual override ensure(deadline) returns (uint[] memory amounts) {
```

from the comparison we can see that the 0 passed in from our function is the amount0Min


### Mitigation

Add an amountOutMin value 

Duplicate of #66
4b - Deadline cannot be block.timestamp in `VaultLib::_redeemCtDsAndSellExcessCt`
Audit: 2024-08-cork-protocol-judging
Severity: HIGH

4b

Medium

# Deadline cannot be block.timestamp in `VaultLib::_redeemCtDsAndSellExcessCt`

### Summary

on line 345 of `VaultLib::_redeemCtDsAndSellExcessCt`, the function `swapExactTokensForTokens()` is called but the deadline parameter of the function is initialised to block.timestamp which offers no protection

### Root Cause

on [line 345](https://github.com/sherlock-audit/2024-08-cork-protocol/blob/main/Depeg-swap/contracts/libraries/VaultLib.sol#L345) the `deadline` param of the `swapExactTokensForTokens` is being initialised to block.timestamp

### Internal pre-conditions

whenever user calls `redeemEarlyLv` in the vault contract.

### External pre-conditions

No external pre-con

### Attack Path

1. When user calls `redeemEarlyLv`
2. Then it makes a call to the vaultlib `redeemEarly` using the current state storage
3. A call is made to _liquidateLpPartial
4. then we try to _redeemCtDsAndSellExcessCt 
5. in `_redeemCtDsAndSellExcessCt` a call is made to `ammRouter.swapExactTokensForTokens`.
6. which makes an external call to uniswaps router v2 with the provided data

### Impact

There is no real protection or deadline

### PoC

looking into the function the problem is from this line 
`ra += ammRouter.swapExactTokensForTokens(ctSellAmount, 0, path, address(this),block.timestamp)[1];`

which intend makes a `swapExactTokensForTokens` call to an amm router which is uniswapV2's router02, which looks like this;

```solidity
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external virtual override ensure(deadline) returns (uint[] memory amounts) {
```
so as we can see, in the function declaration there is an ensure modifier which makes sure the deadline has not passed.

```solidity
    modifier ensure(uint deadline) {
        require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED');
        _;
    }
```

so evaluating when you have a deadline of block.timestamp, we can confirm deadline will never be reached, because block.timestamp == block.timestamp always.

### Mitigation

Add a real deadline either a user passed in timestamp or any other implementation

Duplicate of #66
vinica_boy - Exchange rate between RA:CT+DS is not used providing RA tokens to liquidity vault
Audit: 2024-08-cork-protocol-judging
Severity: HIGH

vinica_boy

High

# Exchange rate between RA:CT+DS is not used providing RA tokens to liquidity vault

## Summary

In the Vault Deposit, a portion of the Redemption Asset is used to mint Cover Token + Depeg Swap. Exchange rate is not applied here and for each CT minted we lock the same amount of RA.
## Vulnerability Detail
The `deposit()` function in `VaultLib.sol` is responsible for depositing RA into the Liquidity Vault, with a portion of this RA being used to mint CT + DS for providing liquidity to the AMM pair. However, this process does not account for the actual exchange rate between RA and CT + DS, assuming a 1:1 exchange rate.

In the `__provideLiquidity()` function, the minted CT tokens and the corresponding RA are provided as liquidity to the AMM. However, when `PsmLibrary.unsafeIssueToLv()` is called to account for the locked RA used to mint CT + DS, it incorrectly assumes an exchange rate of 1:1 between RA and CT.
```solidity
function __provideLiquidity(
        State storage self,
        uint256 raAmount,
        uint256 ctAmount,
        IDsFlashSwapCore flashSwapRouter,
        address ctAddress,
        IUniswapV2Router02 ammRouter,
        uint256 dsId
    ) internal {
        // no need to provide liquidity if the amount is 0
        if (raAmount == 0 && ctAmount == 0) {
            return;
        }

        PsmLibrary.unsafeIssueToLv(self, ctAmount);

        __addLiquidityToAmmUnchecked(self, raAmount, ctAmount, self.info.redemptionAsset(), ctAddress, ammRouter);

        _addFlashSwapReserve(self, flashSwapRouter, self.ds[dsId], ctAmount);
    }
```

`PsmLibrary.unsafeIssueToLv()` is used to account for the RA token locked in order to mint the CT+DS.

```solidity
function unsafeIssueToLv(State storage self, uint256 amount) internal {
        uint256 dsId = self.globalAssetIdx;

        DepegSwap storage ds = self.ds[dsId];

        self.psm.balances.ra.incLocked(amount);

        ds.issue(address(this), amount);
    }
```

The RA amount locked is equal to the CT amount minted which is equal to exchange rate = 1. Since exchange rate can be different than one, this function should account for it and lock the correct RA based on the exchange rate.

This issue can result in users receiving either fewer or more rewards, depending on whether the exchange rate is higher or lower than 1. Apart from that users might not be incentivized to deposit RA to the vault, but instead directly min DS+CT in the PSM and provide liquidity directly to the AMM pair.
## Impact

Wrong amount of rewards distributed for users
## Code Snippet

`VaultLib.deposit()`:
https://github.com/sherlock-audit/2024-08-cork-protocol/blob/db23bf67e45781b00ee6de5f6f23e621af16bd7e/Depeg-swap/contracts/libraries/VaultLib.sol#L191
`VaultLib.__provideLiquidity()`:
https://github.com/sherlock-audit/2024-08-cork-protocol/blob/db23bf67e45781b00ee6de5f6f23e621af16bd7e/Depeg-swap/contracts/libraries/VaultLib.sol#L153
## Tool used

Manual Review

## Recommendation

Use exchang
KupiaSec - The `api.burn` function should have cool down period
Audit: 2024-08-velar-artha-judging
Severity: HIGH

KupiaSec

High

# The `api.burn` function should have cool down period

### Summary

Liquidity providers can burn their liquidity tokens anytime regardless minting time.
Attackers can take fees without contributing to the pool using this vulnerability.

### Root Cause

There is no cool down period in the [`api.burn`](https://github.com/sherlock-audit/2024-08-velar-artha/blob/18ef2d8dc0162aca79bd71710f08a3c18c94a36e/gl-sherlock/contracts/api.vy#L104-L128) function.

### Internal pre-conditions

None

### External pre-conditions

None

### Attack Path

1. Bob(lp) mints 100 `lp_token` by depositing 100 in quote token and the total supply of `lp_token` is 100.
2. Alice opens the long position.
3. The following steps are performed in one transaction:
    - Alice mints 1000 `lp_token` by depositing 1000
    - Alice closes the long position: she has to pay 10 fees to the pool and the pool's total reserve is `1000 + 100 + 10 = 1110`.
    - Alice burns 1000 `lp_token`: Alice receives `1000 * 1110 / 1100 = 1009`

Alice pays 10 fees while closing the position and receives additional 9 fees while burning.
Even though Alice's minted 1000 `lp_token` did not contribute to the users' positions, she received fees and this is unfair for other liquidity providers.

This vulnerability is available for attackers to frontrun the closing position.

### Impact

Fees are distributed to liquidity providers unfairly.

### PoC

None

### Mitigation

It is recommended to add the cool down period in the `api.burn` function and make burning available after cool down period.

Duplicate of #94
bughuntoor - User can sandwich their own position close to get back all of their position fees
Audit: 2024-08-velar-artha-judging
Severity: HIGH

bughuntoor

High

# User can sandwich their own position close to get back all of their position fees

## Summary
User can sandwich their own position close to get back all of their position fees

## Vulnerability Detail
Within the protocol, borrowing fees are only distributed to LP providers when the position is closed. Up until then, they remain within the position.
The problem is that in this way, fees are distributed evenly to LP providers, without taking into account the longevity of their LP provision.

This allows a user to avoid paying fees in the following way:
1. Flashloan a large sum and add it as liquidity
2. Close their position and let the fees be distributed (with most going back to them as they've got majority in the pool)
3. WIthdraw their LP tokens 
4. Pay back the flashloan

## Impact
Users can avoid paying borrowing fees.

## Code Snippet
https://github.com/sherlock-audit/2024-08-velar-artha/blob/main/gl-sherlock/contracts/positions.vy#L156

## Tool used

Manual Review

## Recommendation
Implement a system where fees are gradually distributed to LP providers.
0xbranded - Fee Precision Loss Disrupts Liquidations and Causes Loss of Funds
Audit: 2024-08-velar-artha-judging
Severity: HIGH

0xbranded

High

# Fee Precision Loss Disrupts Liquidations and Causes Loss of Funds

## Summary
Borrowing and funding fees of both longs/shorts suffer from two distinct sources of precision loss. The level of precision loss is large enough to consistently occur at a significant level, and can even result in total omission of fee payment for periods of time. This error is especially disruptive given the sensitive nature of funding fee calculations both in determining liquidations (a core functionality), as well as payments received by LPs and funding recipients (representing a significant loss). 

## Vulnerability Detail
The first of the aforementioned sources of precision loss is relating to the `DENOM` parameter defined and used in `apply` of [`math.vy`](https://github.com/sherlock-audit/2024-08-velar-artha/blob/main/gl-sherlock/contracts/math.vy#L163-L172):

```vyper
DENOM: constant(uint256) = 1_000_000_000

def apply(x: uint256, numerator: uint256) -> Fee:
  fee      : uint256 = (x * numerator) / DENOM
...
  return Fee({x: x, fee: fee_, remaining: remaining})
```

This function is in turn referenced (to extract the `fee` parameter in particular) in several locations throughout [`fees.vy`](https://github.com/sherlock-audit/2024-08-velar-artha/blob/main/gl-sherlock/contracts/fees.vy#L265), namely in determining the funding and borrowing payments made by positions open for a duration of time:

```vyper
  paid_long_term      : uint256 = self.apply(fs.long_collateral, fs.funding_long * new_terms)
...
  paid_short_term     : uint256 = self.apply(fs.short_collateral, fs.funding_short * new_terms)
...
    P_b   : uint256 = self.apply(collateral, period.borrowing_long) if long else (
                      self.apply(collateral, period.borrowing_short) )
    P_f   : uint256 = self.apply(collateral, period.funding_long) if long else (
                      self.apply(collateral, period.funding_short) )
```

The comments for `DENOM` specify that it's a "magic number which depends on the smallest fee one wants to support and the blocktime." In fact, given its current value of $10^{-9}$, the smallest representable fee per block is $10^{-7}$%. Given the average blocktimes of 2.0 sec on the [BOB chain](https://explorer.gobob.xyz/), there are 15_778_800 blocks in a standard calendar year. Combined with the fee per block, this translates to an annual fee of 1.578%.

However, this is also the interval size for annualized fees under the current system. As a result, any fee falling below the next interval will be rounded down. For example, given an annualized funding rate in the neighborhood of 15%, there is potential for a nearly 10% error in the interest rate if rounding occurs just before the next interval. This error is magnified the smaller the funding rates become. An annual fee of 3.1% would round down to 1.578%, representing an error of nearly 50%. And any annualized fees below 1.578% will not be recorded, representing a 100% error.

The second source of
0x37 - Traders may decrease their trading loss via mint/burn
Audit: 2024-08-velar-artha-judging
Severity: HIGH

0x37

High

# Traders may decrease their trading loss via mint/burn

## Summary
When traders have some trading loss, they can decrease their trading loss via mint LP before closing position and burn LP after closing position.

## Vulnerability Detail
When traders open one position with long or short size, traders have some negative unrealized Pnl. When traders close their positions, LP holders as traders' counterparty, will take traders' loss as their profits.
The problem is that there is not any limitation for mint()/burn() functions. Traders can make use of this problem to decrease their trading loss.
For example:
1. Alice opens one Long position in BTC/USDT market.
2. BTC price decreases and Alice's long position has some negative Pnl.
3. Alice wants to close her position.
4. Alice borrows one huge amount of BTC/USDT and mint in this BTC/USDT market to own lots of shares.
5. Alice closes her position and her loss will become LP's profit, this will increase LP share's price.
6. Alice burns her share with one higher share price.

In this way, Alice can avoid most of her trading loss.

## Impact
Traders have ways to avoid trading loss. This means that LPs will lose some profits that they deserve.

## Code Snippet
https://github.com/sherlock-audit/2024-08-velar-artha/blob/main/gl-sherlock/contracts/core.vy#L154-L226

## Tool used
Manual Review

## Recommendation
Add one LP locking mechanism. When someone mints some shares in the market, he cannot burn his shares immediately. After a cool down period, he can burn his shares.

Duplicate of #94