xanoutas/solidity-security-findings huggingface dataset:
DOS in claim function
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/WithdrawProxy.sol#L260


# Vulnerability details

## DOS in claim function 

liquidationWithdrawRatio is the ratio of withdrawing to remaining LPs for the current epoch boundary. Definition sources are given below. 

Source:  https://docs.astaria.xyz/docs/smart-contracts/withdrawproxy

Source: https://github.com/code-423n4/2023-01-astaria/blob/main/src/interfaces/IWithdrawProxy.sol#L28

If liquidationWithdrawRatio is above the 1e18 then (1e18 - s.withdrawRatio) is negative and so claim function revert. 

Proof of Concept

Lets consider withdrawing amount is 100.1WETH and remaining LPs amount is 100 wei 
liquidationWithdrawRatio = 100.1e18/100 = 1.001e18 
So (1e18 - s.withdrawRatio) is negative 

i.e. this modelling not working when LPs withdraw approximately their total liquidy at once.


    260   (s.expected - balance).mulWadDown(1e18 - s.withdrawRatio)

https://github.com/code-423n4/2023-01-astaria/blob/main/src/WithdrawProxy.sol#L260

    264   (balance - s.expected).mulWadDown(1e18 - s.withdrawRatio)

https://github.com/code-423n4/2023-01-astaria/blob/main/src/WithdrawProxy.sol#L264

    281   ERC20(asset()).safeTransfer(VAULT(), balance);
    
https://github.com/code-423n4/2023-01-astaria/blob/main/src/WithdrawProxy.sol#L281

Tools Used 

Vs code


Recommended Mitigation Steps

Define another set of equations when (1e18 - s.withdrawRatio) becomes negative in if statement. Here consider the (s.withdrawRatio - 1e18) and need to do mathematical
modelling respectively.
Incorrectly assumed payer in `_payment()` fn can allows attackers to make payments on behalf of other addresses and resulting financial loss for other users
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L790-L881


# Vulnerability details

## Impact

An attacker could potentially make payments on behalf of other addresses by calling the `_payment()` function and specifying a malicious `msg.sender`. This would allow the attacker to make unauthorized payments and potentially steal funds from the contract.

## Proof of Concept

let's say :

- the attacker was "Bob", 
- the victim was "Alice"
- the payee was "lien contract"


so here was the POC :

1.) First let's assumes that Bob wants to pay off a lien of 100 WETH that he has taken out on a collateral. The lien has a remaining interest of 10 WETH and is set to end in 1 hour. Then Bob creates a malicious contract that pretends to be a valid `user` (the `payer`).

2.) Bob creates a malicious contract that calls the `_payment()` function, but sends a `msg.sender` that is different from the `actual payer`. That should be passing in the address of the lien he wants to make a payment on behalf of, the amount he wants to pay, and the address of the victim (let's call the victim Alice).

3.) Alice, as the payer and sends 110 WETH as the amount to pay off the lien. 

4.) The malicious contract calls the `_payment()` function with Alice as `the msg.sender` and the function, assuming that the `msg.sender` is the `payer`, transfers the 110 WETH to the `payee`, paying off the lien and transferring the remaining 10 WETH to `Alice`. Because the `_payment()` function does not check the actual payer, it assumes that the `msg.sender` is the `payer`, and so it processes the payment from Alice's address to the lien.

5.) In this scenario, Bob has successfully paid off the lien on behalf of Alice without Alice known or consent, and Alice now holds 10 WETH that she did not intend to pay. As a result, Bob is able to make a payment on behalf of Alice without her knowledge or consent, potentially leading to a loss of funds for Alice.

This could potentially use this vulnerability to make unauthorized payments to the others, which could also result in financial loss for other users.

## Tools Used

Manual Review 

## Recommended Mitigation Steps

e.g :

```
    // Check if the payer is the msg.sender
    if (payer != msg.sender) {
        revert InvalidPayerAddress();
    }
    // rest of the code
}
```
In this example, we added an additional check before any further processing in the function to ensure that the address passed as the `payer` is the same as `msg.sender`. If the payer address is different from msg.sender, the function would likely reverts.
Signatures cannot be invalidated
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L246
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L313
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L287


# Vulnerability details

## Impact
Once signatures are revealed on-chain, they become public. Since the signature does not contain any dynamic data that would be validated by the smart contract, for example a timestamp that should not be too far in the past, they cannot be invalidated and can be replayed. Note that the signatures are coming as a user input provided to public/external methods as calldata, and those can be called repeatedly with the same signatures.

## Proof of Concept
See the links to code

## Tools Used
None

## Recommended Mitigation Steps
Include a signature invalidation mechanisms, such as timestamps or nonces.
Improper validations in Clearinghouse. possible to lock collateral NFT in contract.
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/ClearingHouse.sol#L114-L178


# Vulnerability details

When a borrower does not return the borrowed funds on time, a liquidator can trigger a liquidation.
In that case the collateral NFT will be listed in an Seaport dutch auction.
The auction requests settlementToken and a fake ClearingHouse NFT.
When a buyer bids enough of the settlementToken, openSea auction will accept the offer, transfer the NFT from ClearingHouse to bidder, move settlementToken from bidder to ClearingHouse, and 'transfers' the fake clearinghouse NFT to clearinghouse. This call to [ClearingHouse.safeTransferFrom](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/ClearingHouse.sol#L169-L178) triggers the further processing of the liquidation. It will pay the debt with the funds received from Seaport, and delete data from LienToken and CollateralToken for this collateral NFT. 

The problem is that the `ClearingHouse.safeTransferFrom` can be called by anyone and assumes valid call parameters. One of the parameters `identifier` is used to pass the paymentToken address. This can easily be modified to let the contract accept any ERC20 token as `paymentToken` to payoff the debt.
This allows a malicious actor to lock a user's collateral NFT and cancel the auction. 
This could be misused to completely block any liquidatons.

The steps to reproduce: 

    1. Normal flow: borrow funds via requestLienPosition
    2. borrowed funds are not paid back before stack.point.end 
    3. liquidator calls AstariaRouter.liquidate(...)

    At this time a Seaport auction is initiated and CollateralToken state for this collateralID is updated to be in auction. 
    All fine so far.

    4. An evil actor can now call ClearingHouse.safeTransferFrom with dummy data and a dummy ERC20  token address as paymentToken

After this call, the Collateral NFT will still be in de ClearingHouse contract, but references to the NFT are cleaned up from both CollateralToken and LienToken.
This results in the NFT being locked in the contract without any way to get it out.

## Technical details: 
When a liquidation is started, [_generateValidOrderParameters](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L425) is called to generate the Seaport order params. It sets [settlementToken as the identifierOrCriteria](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L456).

ClearingHouse assumes that `safeTransferFrom` will only be called by Seaport after a succesful auction, and assumes the identifier is the `settlementToken` value that was set for the order.
The _execute function is called, which [converts the identifier parameter to a paymentToken address](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc980
Signatures signing the strategy terms can be replayed cross-chain
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L246


# Vulnerability details

## Impact
The signatures of terms do not have any chain-specific value, such as chain ID, encoded in them and validated by the smart contract. As such, these signatures are replayable across chains. 

## Proof of Concept
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L246

## Tools Used
None

## Recommended Mitigation Steps
Include chain ID in the payload to be signed, and validate it in the smart contract.
`transferFrom` function does not follow the "Checks Effects Interactions pattern"
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC20-Cloned.sol#L81


# Vulnerability details

## Impact
There is a reentrancy issue on `transferFrom` function. 
`transferFrom` function has no Reentrancy protection or does not follow check-effect-iteration pattern in `ERC20-Cloned.sol` contract.

## Proof of Concept
In `ERC20-Cloned.sol`:
```
function transferFrom( //@audit - reentrancy
    address from,
    address to,
    uint256 amount
  ) public virtual returns (bool) {
    ERC20Data storage s = _loadERC20Slot();
    uint256 allowed = s.allowance[from][msg.sender]; // Saves gas for limited approvals.

    if (allowed != type(uint256).max) {
      s.allowance[from][msg.sender] = allowed - amount;
    }

    s.balanceOf[from] -= amount;

    // Cannot overflow because the sum of all user
    // balances can't exceed the max uint256 value.
    unchecked {
      s.balanceOf[to] += amount;
    }

    emit Transfer(from, to, amount);

    return true;
  }
```

## Tools Used
Manual analysis

## Recommended Mitigation Steps

Add reentrancy guard to `transferFrom` or use [check-effect-iteration pattern](https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html).
Timestamp Manipulation in `_payment` fn may lead into financial loss
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L790-L881
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L805-L807


# Vulnerability details

## Impact

The impact of the issue is that an attacker may be able to manipulate the block timestamp, which could allow them to pay less than the full amount owed on a loan. This could result in financial losses for the lender and potentially allow the attacker to gain unauthorized access to the collateral associated with the loan. This could also potentially lead to the liquidation of the collateral and further financial losses for the lender.

## Proof of Concept

Proof of concept for manipulating the block timestamp in the `_payment()` function:

1.) An attacker could modify the timestamp of the current block by using a malicious miner to mine blocks with a manipulated timestamp.
2.) The attacker then calls the `_payment()` function and passes in a position of a lien in the activeStack array that has already exceeded its end time.
3.) Because the block timestamp has been manipulated, the if (block.timestamp >= end) check in the `_payment()` function will evaluate to false, allowing the attacker to make a payment on a lien that should no longer be active.

This issue could lead to potential financial loss for the contract owner and its users.

## Tools Used

Manual review

## Recommended Mitigation Steps

To prevent any past or future timestamps from being used in the `_payment()` function, you can use the check "if (block.timestamp < stack.point.last)" to ensure that the current timestamp is greater than the last timestamp recorded in the point struct. This will prevent any past timestamps from being used.

e.g : 
```
if(block.timestamp < stack.point.last) {
      revert("Invalid block timestamp");
    }
```
First PublicVault depositor can be front-run and have part of their deposit stolen
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/PublicVault.sol#L251-L265
https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L112


# Vulnerability details

## Description

The first deposit with a `totalSupply` of zero shares will mint shares equal to the deposited amount.

```solidity
File: lib/gpl/src/ERC4626-Cloned.sol

112:     return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());

```
[Link to Code](https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L112)

```solidity
File: PublicVault.sol

    function deposit(uint256 amount, address receiver)
      public
      override(ERC4626Cloned)
      whenNotPaused
      returns (uint256)
    {
      VIData storage s = _loadVISlot();
      if (s.allowListEnabled) {
        require(s.allowList[receiver]);
      }

      uint256 assets = totalAssets();

      return super.deposit(amount, receiver);
    }

```
[Link to Code](https://github.com/code-423n4/2023-01-astaria/blob/main/src/PublicVault.sol#L251-L265)

Problems with the code:
1. Integer division negatively affect the user.
2. Can be manipulated to cause a large loss, specifically for first victim.

## Impact

It can lead to some part of Fund getting stolen from First Depositor (which will be the LP Provider).

## Proof of Concept

Consider the following situation:
1. Attacker deposits 1 wei of WETH.
2. Next, Attacker transfers 100 WETH to the contract.
3. Victim deposits 200 WETH.
3. Attacker withdraws 1 share.

[Here](https://drive.google.com/file/d/1GNRAl0M3pDdiMhyaIp3UN-l3FmqiXGnG/view?usp=sharing) is the Detail analysis of the above PoC done by Spearbit.

This analysis confirms this clear Path of attack which can be used by the attacker.

## Tools Used

Manual Review

## Recommended Mitigation Steps

1. Need to Enforce a minimum deposit that can't be withdrawn.
2. So, mint some of the initial amount to the zero address.
3. Most legit first depositors will mint thousands of shares, so not a big cost.
payDebtViaClearingHouse function is vulnerable to reentrancy attacks
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/LienToken.sol#L497


# Vulnerability details

## Impact
Attacker can replay the dept payment for the same collateralStateHash of collateralId 

## Proof of Concept
The LienToken. payDebtViaClearingHouse function does pay dept to the caller via the internal _payDebt function, after that it deletes the collateral hash state s.collateralStateHash[collateralId] :

```
_payDebt(s, token, payment, msg.sender, auctionStack);
    delete s.collateralStateHash[collateralId];
```
The _payDebt uses the _paymentAH function, that function makes an external transfering call `tokenTransferFrom` line 643, if that call is hooked an attacker can replay the LienToken. payDebtViaClearingHouse call before the s.collateralStateHash[collateralId] is deleted allowing them to get the dept paid over and over for a single s.collateralStateHash[collateralId]

## Tools Used
Manual

## Recommended Mitigation Steps
Make the function prevent against reentrancy
Owner of private Vault is not going to be able to withdraw funds
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/Vault.sol#L70


# Vulnerability details

## Impact
Funds in private Vault will be locked forever.

## Proof of Concept
A strategist can deploy a PrivateVault funded with his own capital. 
The problem is when the owner() of the vault wants to withdraw the funds and calls withdraw():
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/Vault.sol#L70


```solidity
function withdraw(uint256 amount) external {
    require(msg.sender == owner());
    ERC20(asset()).safeTransferFrom(address(this), msg.sender, amount); 
  }
``` 
We can see that an ERC20.safeTransferFrom(address(this), ) is being executed instead of just ERC20.safeTransfer, since the contract has not allowed itself, this transaction will always fail and the funds will remain locked in the contract.

## Tools Used
Manual review

## Recommended Mitigation Steps
Use ERC20.safeTransfer(msg.sender,amount)
The conversion between `withdrawRatio` and the amount of asset is inconsistent
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/WithdrawProxy.sol#L271-L274
https://github.com/code-423n4/2023-01-astaria/blob/main/src/PublicVault.sol#L307-L319


# Vulnerability details

## Impact

When [converting assets to `withdrawRatio`](https://github.com/code-423n4/2023-01-astaria/blob/main/src/PublicVault.sol#L307-L319), it projects the ratio from `0 ~ 1` to `0 ~ 1e18`; however, when converting [`withdrawRatio` back to assets](https://github.com/code-423n4/2023-01-astaria/blob/main/src/WithdrawProxy.sol#L271-L274), it projects the `withdrawRatio` value from `0 ~ 10**ERC20(asset()).decimals()` to `0 ~ 1`. The conversion holds only when `ERC20(asset()).decimals() == 18`.

When using a ERC20 token, which `decimals` is not `18`, as underlying asset of the Vault, the value of `transferAmount` calculated in `WithdrawProxy.claim()` is incorrect. This will result in incorrectly transferring assets in `WithdrawProxy.claim()`.

As the result, as long as the asset's `decimals` is not `18`, it's easy for strategists/borrowers/LPs to exploit this vulnerability depending on the value of its `decimals` larger or less than `18`.

## POC

The reasons are:
1. `withdrawRatio` is calculated in `PublicVault.processEpoch()` from L314 to L316. We can see that the value of `withdrawRatio` is projected to `1e18` when it's `100%`. L318 set the calculated `withdrawRatio` to `currentWithdrawProxy`.

```solidity
File: https://github.com/code-423n4/2023-01-astaria/blob/main/src/PublicVault.sol

        // reset liquidationWithdrawRatio to prepare for re calcualtion
308:    s.liquidationWithdrawRatio = 0;

        // check if there are LPs withdrawing this epoch 
        if ((address(currentWithdrawProxy) != address(0))) {
          uint256 proxySupply = currentWithdrawProxy.totalSupply();

//@audit The below formula projects the ratio from `0 ~ 1` to `0 ~ 1e18`
314:      s.liquidationWithdrawRatio = proxySupply
315:        .mulDivDown(1e18, totalSupply())
316:        .safeCastTo88();

318:      currentWithdrawProxy.setWithdrawRatio(s.liquidationWithdrawRatio);
          uint256 expected = currentWithdrawProxy.getExpected();
```

2. When the `withdrawRatio` is converted back to the value of asset in `WithdrawProxy.claim()`, it uses `10**ERC20(asset()).decimals()` to calculate the actual amount of asset on L271-273. This will be correct only when `10**ERC20(asset()).decimals() == 1e18`. However, not all ERC20 decimals are 18.

```solidity
File: https://github.com/code-423n4/2023-01-astaria/blob/main/src/WithdrawProxy.sol

271:      transferAmount = uint256(s.withdrawRatio).mulDivDown(
            balance,
273:        10**ERC20(asset()).decimals()
          );
```

## Tools Used
Manual audit

## Recommended Mitigation Steps

Change L273 of `WithdrawProxy.claim()` to `1e18` will solve the issue:
```solidity
File: https://github.com/code-423n4/2023-01-astaria/blob/main/src/WithdrawProxy.sol

271:      transferAmount = uint256(s.withdrawRatio).
ERC4626Cloned at maxDeposit() doesn't verify if the vault is in a "healthy" state to allow more deposits
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L147


# Vulnerability details

## Impact
the function maxDeposit() should have a function to check if the "vault" is "healthy" in the sense of having assets backing the circulating shares before allowing more assets to be deposited. and without checking properly if the vault is healthy or not, the user may be at risk of depositing assets without sufficient backing. This may lead to undesirable situations for both Astaria team and its users if users want to redeem all their shares at once and even if they signal it in advance.

## Proof of Concept
https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L147
```
 function maxDeposit(address) public view virtual returns (uint256) {
    return type(uint256).max;
}
```

## Tools Used
Inspection

## Recommended Mitigation Steps
Consider adding an internal function "_isVaultHealthy()" to MaxDeposit to check the state of the vault before allowing more deposits.

```
//before
function maxDeposit(address) public view virtual returns (uint256) {
   return type(uint256).max;
}

//after
function maxDeposit(address) public view virtual override returns (uint256) {
        return _isVaultHealthy() ? type(uint256).max : 0;
 }

function _isVaultHealthy() private view returns (bool) {
        return totalAssets() > 0 || totalSupply() == 0;
    }
```