xanoutas/solidity-security-findings huggingface dataset:
Auctioned NFT may be repaid with a fake token, leaving protocol in a corrupted state
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The protocol is left in a corrupted state, with:
1. the auctioned NFT being locked in its clearing house;
1. the wrapping collateral NFT being burnt;
1. the lien being fully repaid with fake ERC20 tokens;
1. liquidity providers being left with a loss;
## Proof of Concept
To liquidate NFTs the protocol integrates with Seaport:
1. [a Seaport order is created](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L487-L493) to sell borrower's NFT;
1. the order specifies two considerations: 1) [the ERC20 token](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L445-L452) that must be paid to buy the NFT (e.g. WETH; it matches the asset of a vault); 2) [the clearing house of the auctioned NFT](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L453-L460), which partially implements the [safeTransferFrom](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/ClearingHouse.sol#L169) function from the ERC1155 standard.
1. the clearing house consideration serves as as a hook that, when called by Seaport after receiving the ERC20 tokens, repays the debt and finalizes the state of the auction in the protocol.

The `safeTransferFrom` function of `ClearingHouse` is expected to be called only by Seaport (specifically, [the allowed conduit](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L472)). However, it doesn't implement access control, allowing anyone to call it with fake input values and corrupt the state of the protocol
### Exploit Scenario
1. Bob's NFT was liquidated and is being auctioned on Seaport.
1. Alice calls the `safeTransferFrom` function of `ClearingHouse` to repay Bob's debt with fake ERC20 tokens and corrupt the state of the protocol.
1. As a result:
        1. Bob's NFT is locked in its clearing house;
        1. the wrapping collateral NFT was burnt;
        1. the lien was fully repaid with fake ERC20 tokens;
        1. liquidity providers, from which Bob borrowed, were left with a loss.

The following PoC demonstrates this scenario
```solidity
// src/test/AstariaTest.t.sol
...
import {MockERC20} from "solmate/test/utils/mocks/MockERC20.sol";
...

contract AstariaTest is TestHelpers {
    ...
    function testFakeAuctionPayment_AUDIT() public {
        address borrower = address(69);
        address liquidator = address(7);

        // Create and liquidate a loan.
        (address publicVault, ILienToken.Stack[] memory stack) = setupLiquidation(
            borrower
        );

        vm.startPrank(liquidator);
        OrderParameters memory listedOrder = ASTARIA_RO
Funds cannot be withdrawn from private vaults
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Deposited funds are locked indefinitely in private vaults.
## Proof of Concept
The `withdraw` function of `Vault` calls `safeTransferFrom` with the `from` address set to `address(this)` to withdraw funds for the caller ([Vault.sol#L72](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/Vault.sol#L72)), which requires that the contract has approved token spending to itself. This can be seen from, for example, [the OpenZeppelin ERC20 implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L160):
```solidity
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
    address spender = _msgSender();
    _spendAllowance(from, spender, amount);
    _transfer(from, to, amount);
    return true;
}

function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
    uint256 currentAllowance = allowance(owner, spender);
    if (currentAllowance != type(uint256).max) {
        require(currentAllowance >= amount, "ERC20: insufficient allowance");
        unchecked {
            _approve(owner, spender, currentAllowance - amount);
        }
    }
}
```
However, the contract never does an approve to self. As a result, the call to `transferFrom` will always fail due to insufficient allowance.

### Exploit Scenario
1. Bob creates a private vault and deposits funds into it.
1. Bob tries to withdraw funds from the vault by calling `withdraw` but the call reverts.
1. Bob doesn't heavy any other options to withdraw his funds from the vault.
## Tools Used
Manual review
## Recommended Mitigation Steps
Consider using `safeTransfer(msg.sender, amount)` instead of `safeTransferFrom(address(this), msg.sender, amount)`.
Inexistent Sanitization of Clearing House Payment Token
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/ClearingHouse.sol#L172
https://github.com/code-423n4/2023-01-astaria/blob/main/src/ClearingHouse.sol#L123
https://github.com/code-423n4/2023-01-astaria/blob/main/src/ClearingHouse.sol#L143-L166
https://github.com/code-423n4/2023-01-astaria/blob/main/src/LienToken.sol#L498
https://github.com/code-423n4/2023-01-astaria/blob/main/src/LienToken.sol#L523
https://github.com/code-423n4/2023-01-astaria/blob/main/src/LienToken.sol#L642-L643


# Vulnerability details

## Impact

The payment token supplied encoded to the `safeTransferFrom` function call is not sanitized, permitting arbitrary payment tokens of any value to be provided instead of the actual intended one that was defined in the `LienToken` implementation's `lien.token` value. As a result, it is possible to pay debts using a worthless or malicious token, significantly compromising the integrity of the system.

## Proof of Concept

A direct invocation of `safeTransferFrom` with an `identifier` argument of an arbitrary token will successfully "pay" the debt of a Lien token incorrectly. The `currentOfferPrice` computations used within `ClearingHouse` will also become meaningless as they will be done on the basis of a different token than the one provided for the payment of debts.

## Tools Used

Manual review of the codebase.

## Recommended Mitigation Steps

We advise the payment token to be queried via the `LienToken` itself rather than accepted as an argument, disallowing worthless / malicious tokens from being able to repay debts.
Borrower could lose NFT value if liquidationInitialAsk price is significantly reduced during refinance
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/AstariaRouter.sol#L684-L703
https://github.com/code-423n4/2023-01-astaria/blob/main/src/LienToken.sol#L165-L170


# Vulnerability details


## Impact
When a refinance is executed, the loan stack is replaced with the new loan terms, which includes the new liquidationInitialAsk by the strategist/vault. The refinance logic only ensure a better loan term and that liquidationInitialAsk cannot be less then potential debt. There is no check for a reduction of the liquidationInitialAsk (i.e. the valuation of the NFT).

However, as anyone can refinance the loan without the borrower(NFT owner)'s consent, the NFT's valuation could be marked down all the way to the potential debt. For example, If the borrower only borrow 1 % of the NFT valuation, someone could deliberately mark down the liquidationInitialAsk all the down to 1%. The borrower will not be aware of this as the refinance doesn’t require actions on his part.

If the loan expires outstanding, the borrower will lose a significant value of the NFT during liquidation. 

https://github.com/code-423n4/2023-01-astaria/blob/main/src/AstariaRouter.sol#L684-L703

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

## Recommended Mitigation Steps
Either check that liquidationInitialAsk does not change during refinance or allow borrower to set a slippage.
Public Vault mint() function always transfer 10e18 worth of asset when totalSupply == 0, potentially transfering more asset than specified
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details


##Impact

The previewMint() in PublicVault (inherited from ERC4626Cloned) always return 10e18 when totalSupply ==0.  This will result in a transfer of 10e18 worth of asset when calling mint(), regardless of the shares amount that the user wish to mint. This may lead to an asset transfer that exceeded what the user specified as the share amount.

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

## Recommended Mitigation Steps
Return the specified share count when supply == 0.
Upgraded Q -> 2 from #415 [1677231136540]
Audit: 2023-01-astaria-findings
Severity: MEDIUM

Judge has assessed an item in Issue #415 as 2 risk. The relevant finding follows:

 2 - The PrivateVault deposit can be executed even when the vault was paused.
There is not restriction for deposit in the Private vault.

Recommendation
Add a whenNotPaused() modifier for the deposit() function.
Upgraded Q -> 2 from #596 [1677228840417]
Audit: 2023-01-astaria-findings
Severity: MEDIUM

Judge has assessed an item in Issue #596 as 2 risk. The relevant finding follows:

 withdraw and redeem
https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626RouterBase.sol#L41-L52

function withdraw(
  IERC4626 vault,
  address to,
  uint256 amount,
  uint256 maxSharesOut
) public payable virtual override returns (uint256 sharesOut) {

  ERC20(address(vault)).safeApprove(address(vault), amount);
  if ((sharesOut = vault.withdraw(amount, to, msg.sender)) > maxSharesOut) {
    revert MaxSharesError();
  }
}
https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626RouterBase.sol#L55-L66

function redeem(
  IERC4626 vault,
  address to,
  uint256 shares,
  uint256 minAmountOut
) public payable virtual override returns (uint256 amountOut) {

  ERC20(address(vault)).safeApprove(address(vault), shares);
  if ((amountOut = vault.redeem(shares, to, msg.sender)) < minAmountOut) {
    revert MinAmountError();
  }
}
Both function calls to ERC20.approve are not valid, since ERC4626.withdraw will burn the shares and no transfers of shares are needed.
Upgraded Q -> M from #55 [1674745091248]
Audit: 2023-01-astaria-findings
Severity: MEDIUM

Judge has assessed an item in Issue #55 as M risk. The relevant finding follows:

 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L106
minimum deposit amount for tokens with non standart decimals value are too high. 0.1 can be quite a lot for tokens with small totalAmount, so this requirement can become too restrictive. For example, WBTC token have 8 decimals, so minimum deposit for it would be around $1.7k.
Upgraded Q -> M from #598 [1674741121008]
Audit: 2023-01-astaria-findings
Severity: MEDIUM

Judge has assessed an item in Issue #598 as M risk. The relevant finding follows:

 Low:
1.deposit() check wrong variant

  function deposit(uint256 assets, address receiver)
    public
    virtual
    returns (uint256 shares)
  {

-    require(shares > minDepositAmount(), "VALUE_TOO_SMALL");
+    require(assets > minDepositAmount(), "VALUE_TOO_SMALL");
Upgraded Q -> M from #598 [1674741102558]
Audit: 2023-01-astaria-findings
Severity: MEDIUM

Judge has assessed an item in Issue #598 as M risk. The relevant finding follows:

 2.minDepositAmount() When the asset is btc, the minDepositAmount is too large

when asset == btc , minDepositAmount = 0.1 btc , equal 2000 usd
suggest:

  function minDepositAmount()
    public
    view
    virtual
    override(ERC4626Cloned)
    returns (uint256)
  {
    if (ERC20(asset()).decimals() == uint8(18)) {
      return 100 gwei;
    } else {
-     return 10**(ERC20(asset()).decimals() - 1);
+     return 10**(ERC20(asset()).decimals() /2);
    }
  }
Transfer of assets should come before deleting and burning the collateral id 
Audit: 2023-01-astaria-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

Clldata id is burnt and deleted before transfer


## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

Here, the calldata id is burnt and deleted before transfer

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

## Tools Used

Manual Review

## Recommended Mitigation Steps

Transfer of asset should be called before burning and deleting the calldataid
Interest is much lower than what it should be
Audit: 2023-01-astaria-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/AstariaRouter.sol#L112-L115
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L255-L263


# Vulnerability details

Protocol interest calculation is said in the docs to be as follow:

```
To convert a standard annualized simple interest rate to an Astaria-compatible interest per second value, divide by 3153600031536000 (seconds per year) and multiply by 10^18
```

This is not what is enforced in the contracts, which use much lower values:

```solidity
112: s.minInterestBPS = uint32((uint256(1e15) * 5) / (365 days));
113:     s.minEpochLength = uint32(7 days);
114:     s.maxEpochLength = uint32(45 days);
115:     s.maxInterestRate = ((uint256(1e16) * 200) / (365 days)).safeCastTo88();
```

This breaks refinancing, and interest calculation, as the interests will be much lower than expected, essentially grieving lenders.

## Impact

Medium


## Tools Used

Manual Analysis

## Mitigation

```diff
-112: s.minInterestBPS = uint32((uint256(1e15) * 5) / (365 days));
+112: s.minInterestBPS = uint32((uint256(1e18) * 5) / (365 days));
113:     s.minEpochLength = uint32(7 days);
114:     s.maxEpochLength = uint32(45 days);
-115:     s.maxInterestRate = ((uint256(1e16) * 200) / (365 days)).safeCastTo88();
+115:     s.maxInterestRate = ((uint256(1e18) * 20000) / (365 days)).safeCastTo88();
```
Solmate's ERC20 does not check for token contract's existence
Audit: 2023-01-astaria-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

Not checking for token existence is a know issue for Solmate. This can cause unexpected contract functionality for transfers implemented in the codes.


## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

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

And some other parts of the code, it is better to use OpenZeppelin's SafeERC20

## Tools Used

Manual Review

## Recommended Mitigation Steps

Consider using OpenZeppelin's SafeERC20, it checks that an address does indeed have a contract
createLien() The first LienToken does not check for liquidationInitialAsk and maxPotentialDebt
Audit: 2023-01-astaria-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Illegal  liquidationInitialAsk and maxPotentialDebt may result in bids amount do not cover the debt

## Proof of Concept
With the current implementation, the first LienToken does not check liquidationInitialAsk and maxPotentialDebt

```solidity
  function _appendStack(
    LienStorage storage s,
    Stack[] memory stack,
    Stack memory newSlot
  ) internal returns (Stack[] memory newStack) {
    if (stack.length >= s.maxLiens) {
      revert InvalidState(InvalidStates.MAX_LIENS);
    }

    newStack = new Stack[](stack.length + 1);
    newStack[stack.length] = newSlot;

    uint256 potentialDebt = _getOwed(newSlot, newSlot.point.end);
    //****@audit check in for () ,so   first LienToken not check  liquidationInitialAsk****//
    for (uint256 i = stack.length; i > 0; ) {
      uint256 j = i - 1;
      newStack[j] = stack[j];
      if (block.timestamp >= newStack[j].point.end) {
        revert InvalidState(InvalidStates.EXPIRED_LIEN);
      }

      unchecked {
        potentialDebt += _getOwed(newStack[j], newStack[j].point.end);
      }

      if (potentialDebt > newStack[j].lien.details.liquidationInitialAsk) {
        revert InvalidState(InvalidStates.INITIAL_ASK_EXCEEDED);
      }

      unchecked {
        --i;
      }
    }
    if (
      //****@audit  need stack.length>0, so first LienToken will Ignore ****//
      stack.length > 0 && potentialDebt > newSlot.lien.details.maxPotentialDebt
    ) {
      revert InvalidState(InvalidStates.DEBT_LIMIT);
    }
  }
```

## Tools Used

## Recommended Mitigation Steps
need check when first LienToken
```solidity
  function _appendStack(
    LienStorage storage s,
    Stack[] memory stack,
    Stack memory newSlot
  ) internal returns (Stack[] memory newStack) {
...
    uint256 potentialDebt = _getOwed(newSlot, newSlot.point.end);

+    if (potentialDebt > newSlot.lien.details.liquidationInitialAsk) {
+      revert InvalidState(InvalidStates.INITIAL_ASK_EXCEEDED);
+    }

...
    if (
-     stack.length > 0 && potentialDebt > newSlot.lien.details.maxPotentialDebt
+    potentialDebt > newSlot.lien.details.maxPotentialDebt
    ) {
      revert InvalidState(InvalidStates.DEBT_LIMIT);
    }

```
WithdrawProxy will break if there is a fee-on-transfer underlying
Audit: 2023-01-astaria-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L384-L387


# Vulnerability details

`PublicVault.transferWithdrawReserve()` will increase `WithdrawProxy.withdrawReserveReceived` by `withdrawBalance`.
The issue is that if the token has a fee-on-transfer, `withdrawBalance` will be greater than the amount received by `withdrawProxy`


```
384: ERC20(asset()).safeTransfer(currentWithdrawProxy, withdrawBalance);
385:       WithdrawProxy(currentWithdrawProxy).increaseWithdrawReserveReceived(
386:         withdrawBalance
387:       );
```

```solidity
235: function increaseWithdrawReserveReceived(uint256 amount) external onlyVault {
236:     WPStorage storage s = _loadSlot();
237:     s.withdrawReserveReceived += amount;
238:   }
```


This can make `WithdrawProxy.claim()` revert because of underflow:

```solidity
255: uint256 balance = ERC20(asset()).balanceOf(address(this)) -
256:       s.withdrawReserveReceived; // will never underflow because withdrawReserveReceived is always increased by the transfer amount from the PublicVault 
//@audit - except for fee-on-transfer tokens
``` 

meaning `processEpoch()` reverting, which eventually means `commitToLien()` reverts, ie users cannot borrow.


`USDT` is an example token that can have fees activated.

## Impact

Medium

## Tools Used

Manual Analysis

## Mitigation


Consider checking balances to ensure `withdrawReserveReceived` never exceeds the token balance.
```diff
+    balanceBefore = asset().balanceOf(currentWithdrawProxy);
384: ERC20(asset()).safeTransfer(currentWithdrawProxy, withdrawBalance);
+    balanceAfter = asset().balanceOf(currentWithdrawProxy);
385:       WithdrawProxy(currentWithdrawProxy).increaseWithdrawReserveReceived(
-386:         withdrawBalance
+386:         balanceAfter - balanceBefore
387:       );
```
Potential issue with `Vault.depost` function
Audit: 2023-01-astaria-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/Vault.sol#L59-L68
https://github.com/code-423n4/2023-01-astaria/blob/main/src/AstariaRouter.sol#L522-L542


# Vulnerability details


## Impact

Contract Vault is a private vault which only allows the owner (also the strategist) to deposit. However, `Vault.deposit` uses an unnecessary complicated logic `require(s.allowList[msg.sender] && receiver == owner());` to allow only owner to deposit (actually the require statement can be simplified by `require(msg.sender == owner);` which will do the trick). This may have potential issue in the future. Because the `allowList` for a private vault is actually meaningless since all `allowList`-related functions are disabled on private vaults. Currently, the owner address is set in the `allowlist` when a private vault is created via `AstariaRouter.newVault` (i.e. `allowList[0] = msg.sender;`). However, this `allowlist` setting might be removed in the future as it's meaningless for a private vault. When it's removed, `Vault.deposit` won't work any more due to `require(s.allowList[msg.sender])`.

## Proof of Concept

In the orginal `Vault.deposit` function,  `require(s.allowList[msg.sender] && receiver == owner());`  is equivalent to `require(msg.sender == owner);`. This is because:
1.  `s.allowList[msg.sender] == true` is valid only when `msg.sender == owner()` since when the private vault is created, only the `msg.sender` (i.e. the owner of the vault) is set in the `allowList`. Please refer to [this code line](https://github.com/code-423n4/2023-01-astaria/blob/main/src/AstariaRouter.sol#L528) for details. The `allowList` of a private vault has only one element which is the owner.
2. `receiver == owner()` just requires that the input argument `receiver` must be set to the owner. Since `receiver` is not actually used elsewhere in the function body, `receiver == owner()` can be omitted. This is because `s.allowList[msg.sender] == true` has already guaranteed the `msg.sender` must be the owner.

The `allowList` for private vaults is only used at two places which are the above mentioned two functions: `Vault.depost` and `AstariaRouter.newVault`. So the proposed optimizations in the below are safe to apply.

## Tools Used
Manual review

## Recommended Mitigation Steps

**Step A**: To optimize the `Vault.deposit` function as in the below

```solidity
File: main/src/Vault.sol

59    function deposit(uint256 amount, address /* receiver */)  //@audit: Comment `receiver` as it is not used in the function
60      public
61      virtual
62      returns (uint256)
63    {
64      //@audit: This line is removed
65      require (msg.sender == owner(), "Only Owner Can Deposit");  //@audit: can use costom error to further save gas
66      ERC20(asset()).safeTransferFrom(msg.sender, address(this), amount);
67      return amount;
68:   }
```

The benefits of the above optimization:
1. Improved readability;
2. Simplified logic makes it easier for maintena