xanoutas/solidity-security-findings huggingface dataset:
Rewards are not accounted for properly in NTokenApeStaking contracts, limiting user's collateral.
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/tokenization/libraries/ApeStakingLogic.sol#L253


# Vulnerability details

## Description

ApeStakingLogic.sol implements the logic for staking ape coins through the NTokenApeStaking NFT.

`getTokenIdStakingAmount()` is an important function which returns the entire stake amount mapping for a specific BAYC / MAYC NFT.

```
function getTokenIdStakingAmount(
    uint256 poolId,
    ApeCoinStaking _apeCoinStaking,
    uint256 tokenId
) public view returns (uint256) {
    (uint256 apeStakedAmount, ) = _apeCoinStaking.nftPosition(
        poolId,
        tokenId
    );
    uint256 apeReward = _apeCoinStaking.pendingRewards(
        poolId,
        address(this),
        tokenId
    );
    (uint256 bakcTokenId, bool isPaired) = _apeCoinStaking.mainToBakc(
        poolId,
        tokenId
    );
    if (isPaired) {
        (uint256 bakcStakedAmount, ) = _apeCoinStaking.nftPosition(
            BAKC_POOL_ID,
            bakcTokenId
        );
        apeStakedAmount += bakcStakedAmount;
    }
    return apeStakedAmount + apeReward;
}
```

We can see that the total returned amount is the staked amount through the direct NFT, plus rewards for the direct NFT, plus the staked amount of the BAKC token paired to the direct NFT. However, the calculation does not include the pendingRewards for the BAKC staked amount, which accrues over time as well.

As a result, getTokenIdStakingAmount() returns a value lower than the correct user balance. This function is used in PTokenSApe.sol's balanceOf function, as this type of PToken is supposed to reflect the user's current balance in ape staking. 

When user unstakes their ape tokens through executeUnstakePositionAndRepay, they will receive their fair share of rewards.It will call ApeCoinStaking's \_withdrawPairNft which will claim rewards also for BAKC tokens. However, because balanceOf() shows a lower value, the rewards not count as collateral for user's debt, which is a major issue for lending platforms.

## Impact

Rewards are not accounted for properly in NTokenApeStaking contracts, limiting user's collateral.

## Tools Used

Manual audit

## Recommended Mitigation Steps

Balance calculation should include pendingRewards from BAKC tokens if they exist.
Bad debt will likely incur when multiple NFTs are liquidated.
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/libraries/logic/GenericLogic.sol#L394


# Vulnerability details

## Description

\_getUserBalanceForERC721() in GenericLogic gets the value of a user's specific ERC721 xToken. It is later used for determining the account's health factor. In case `isAtomicPrice` is false such as in ape NTokens, price is calculated using:

```
    uint256 assetPrice = _getAssetPrice(
        params.oracle,
        vars.currentReserveAddress
    );
    totalValue =
        ICollateralizableERC721(vars.xTokenAddress)
            .collateralizedBalanceOf(params.user) *
        assetPrice;
```

It is the number of apes multiplied by the floor price returns from \_getAssetPrice. The issue is that this calculation does not account for slippage, and is unrealistic. If user's account is liquidated, it is very unlikely that releasing several multiples of precious NFTs will not bring the price down in some significant way. 

By performing simple multiplication of NFT count and NFT price, protocol is introducing major bad debt risks and is not as conservative as it aims to be. Collateral value must take slippage risks into account.

## Impact

Bad debt will likely incur when multiple NFTs are liquidated.

## Tools Used

Manual audit

## Recommended Mitigation Steps

Change the calculation to account for slippage when NFT balance is above some threshold.
Owner has complete control of NTokens using unsafe marketplace delegatecall
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/libraries/logic/MarketplaceLogic.sol#L132


# Vulnerability details

## Description

Owner can set new marketplace adapters using setMarketplace:
```
function setMarketplace(
    bytes32 id,
    address marketplace,
    address adapter,
    address operator,
    bool paused
) external override onlyOwner {
    _marketplaces[id] = DataTypes.Marketplace(
        marketplace,
        adapter,
        operator,
        paused
    );
    emit MarketplaceUpdated(id, marketplace, adapter, operator, paused);
}
```

Later, marketplace adapters are called via delegatecall in MarketPlaceLogic's \_buyWithCredit:
```
// delegateCall to avoid extra token transfer
Address.functionDelegateCall(
    params.marketplace.adapter,
    abi.encodeWithSelector(
        IMarketplace.matchAskWithTakerBid.selector,
        params.marketplace.marketplace,
        params.payload,
        priceEth
    )
);
```

The combination of these two functions allow owner to immediate execute any code in the context of the pool. They will set a new marketplace, with malicious contract as adapter, and execute their malicious code in `matchAskWithTakerBid`.

Conceretely, they may rug all NTokens using these functions:
```
function mint(
    address onBehalfOf,
    DataTypes.ERC721SupplyParams[] calldata tokenData
) external virtual override onlyPool nonReentrant returns (uint64, uint64) {
    return _mintMultiple(onBehalfOf, tokenData);
}
/// @inheritdoc INToken
function burn(
    address from,
    address receiverOfUnderlying,
    uint256[] calldata tokenIds
) external virtual override onlyPool nonReentrant returns (uint64, uint64) {
    return _burn(from, receiverOfUnderlying, tokenIds);
}
function _burn(
    address from,
    address receiverOfUnderlying,
    uint256[] calldata tokenIds
) internal returns (uint64, uint64) {
    (
        uint64 oldCollateralizedBalance,
        uint64 newCollateralizedBalance
    ) = _burnMultiple(from, tokenIds);
    if (receiverOfUnderlying != address(this)) {
        for (uint256 index = 0; index < tokenIds.length; index++) {
            IERC721(_underlyingAsset).safeTransferFrom(
                address(this),
                receiverOfUnderlying,
                tokenIds[index]
            );
        }
    }
    return (oldCollateralizedBalance, newCollateralizedBalance);
}
/// @inheritdoc INToken
function transferOnLiquidation(
    address from,
    address to,
    uint256 value
) external onlyPool nonReentrant {
    _transfer(from, to, value, false);
}
```

These functions, guarded by onlyPool, will allow compromised owner to transfer underlying NFTs or mint NTokens for their own gain, making massive profits.

## Impact

Owner has complete control of NTokens using unsafe marketplace delegatecall

## Proof of Concept

## Tools Used

Manual audit

## Recommended Mitigation Steps

Consider adding timelocks
Victim cannot make use of UniswapV3 NTokens if victim keeps DOSing their balance
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/tokenization/libraries/MintableERC721Logic.sol#L402


# Vulnerability details

## Description

NTokens with balance limits, such as UniswapV3 NTokens, check that this balance limit is not reached when minting new tokens.
```
function _checkBalanceLimit(
    MintableERC721Data storage erc721Data,
    bool ATOMIC_PRICING,
    uint64 balance
) private view {
    if (ATOMIC_PRICING) {
        uint64 balanceLimit = erc721Data.balanceLimit;
        require(
            balanceLimit == 0 || balance <= balanceLimit,
            Errors.NTOKEN_BALANCE_EXCEEDED
        );
    }
}
```

The issue is that NTokens can be freely transferred, so attacker can easily fill the balance (30 by default) of victim's allocated NToken tokenIDs. UniswapV3 NTokens can be of any desired value, so user can mint them with negligible value. Therefore, attacker can continually fill up the balance of victim with useless tokens, which will cost a lot of gas for attack to keep getting rid of, in order to make use of these slots.

## Impact

Victim cannot make use of UniswapV3 NTokens if victim keeps DOSing their balance

## Tools Used

Manual audit

## Recommended Mitigation Steps

Allow user to opt-out of receing NTokens when they have balance limits.
Attacker can abuse victim's signature for marketplace bid to buy worthless item
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/libraries/types/DataTypes.sol#L296


# Vulnerability details


## Description

In ParaSpace marketplace, taker may pass maker's signature and fulfil their bid with taker's NFT. The maker can use credit loan to purchase the NFT provided the health factor is positive in the end.

In validateAcceptBidWithCredit, verifyCreditSignature  is called to verify maker signed the credit structure.

```
function verifyCreditSignature(
    DataTypes.Credit memory credit,
    address signer,
    uint8 v,
    bytes32 r,
    bytes32 s
) private view returns (bool) {
    return
        SignatureChecker.verify(
            hashCredit(credit),
            signer,
            v,
            r,
            s,
            getDomainSeparator()
        );
}
```

The issue is that the credit structure does not have a marketplace identifier:
```
struct Credit {
    address token;
    uint256 amount;
    bytes orderId;
    uint8 v;
    bytes32 r;
    bytes32 s;
}
```

As a result, attacker can use the victim's signature for some orderId in a particular marketplace for another one, where this orderId leads to a much lower valued item.
User would borrow money to buy victim's valueless item. This would be HIGH impact, but incidentally right now only the SeaportAdapter marketplace supports credit loans to maker (implements matchBidWithTakerAsk). However, it is very likely the supporting code will be added to LooksRareAdapter and X2Y2Adapter as well. 
LooksRareExchange supports the function out of the box:

```
function matchBidWithTakerAsk(OrderTypes.TakerOrder calldata takerAsk, OrderTypes.MakerOrder calldata makerBid)
    external
    override
    nonReentrant
{
    require((!makerBid.isOrderAsk) && (takerAsk.isOrderAsk), "Order: Wrong sides");
    require(msg.sender == takerAsk.taker, "Order: Taker must be the sender");
    // Check the maker bid order
    bytes32 bidHash = makerBid.hash();
    _validateOrder(makerBid, bidHash);
    (bool isExecutionValid, uint256 tokenId, uint256 amount) = IExecutionStrategy(makerBid.strategy)
        .canExecuteTakerAsk(takerAsk, makerBid);
    require(isExecutionValid, "Strategy: Execution invalid");
    // Update maker bid order status to true (prevents replay)
    _isUserOrderNonceExecutedOrCancelled[makerBid.signer][makerBid.nonce] = true;
    // Execution part 1/2
    ...
}
```

So, this impact would be HIGH but since it is currently not implemented, would downgrade to MED. I understand it can be closed as OOS due to speculation of future code, however I would ask to consider that the likelihood of other Exchanges supporting the required API is particularly high, and take into account the value of this contribution.

## Impact

Attacker can abuse victim's signature for marketplace bid to buy worthless item


## Tools Used

Manual audit

## Recommended Mitigation Steps

Credit structure should
When users sign a credit loan for bidding on an item, they are forever committed to the loan even if the NFT value drops massively.
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/libraries/types/DataTypes.sol#L296


# Vulnerability details

## Description

In ParaSpace marketplace, taker may pass maker's signature and fulfil their bid with taker's NFT. The maker can use credit loan to purchase the NFT provided the health factor is positive in the end.

In validateAcceptBidWithCredit, verifyCreditSignature  is called to verify maker signed the credit structure.

```
function verifyCreditSignature(
    DataTypes.Credit memory credit,
    address signer,
    uint8 v,
    bytes32 r,
    bytes32 s
) private view returns (bool) {
    return
        SignatureChecker.verify(
            hashCredit(credit),
            signer,
            v,
            r,
            s,
            getDomainSeparator()
        );
}
```

The issue is that the credit structure does not have a deadline:
```
struct Credit {
    address token;
    uint256 amount;
    bytes orderId;
    uint8 v;
    bytes32 r;
    bytes32 s;
}
```

As a result, attacker may simply wait and if the price of the NFT goes down abuse their previous signature to take a larger amount than they would like to pay for the NFT. Additionaly, there is no revocation mechanism, so user has completely committed to loan to get the NFT until the end of time.

## Impact

When users sign a credit loan for bidding on an item, they are forever committed to the loan even if the NFT value drops massively.


## Tools Used

Manual audit

## Recommended Mitigation Steps

Add a deadline timestamp to the signed credit structure.
Compromised or malicious owner can fully control NFT prices, making them able to take uncollateralized loans or freely liquidate users
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/misc/NFTFloorOracle.sol#L405


# Vulnerability details

## Description

NFTFloorOracle.sol is used to query prices of NFTs. Admin has excessive privileges in this contract, which allows them to inflate the value of NFTs and take massive undercollateralized loans, or, deflate their value which would trigger liquidation of user's holdings.

The addFeeder function immediately adds a new feeder which will update the price
```
function addFeeders(address[] calldata _feeders)
    external
    onlyRole(DEFAULT_ADMIN_ROLE)
{
    _addFeeders(_feeders);
}
```

If there are above or equal to MIN_ORACLES_NUM, the price is considered valid.
```
if (validNum < MIN_ORACLES_NUM) {
    return (false, assetPriceMap[_asset].twap);
}
_quickSort(validPriceList, 0, int256(validNum - 1));
return (true, validPriceList[validNum / 2]);
```

So, compromised owner can simple add three feeders which will call setPrice() with rogue data.

Another large centralization risk is when setting the first price on a given asset:
```
//first time just use the feeding value
if (assetPriceMap[_asset].twap == 0) {
    return (true, _twap);
}
```

Owner can abuse it easily by deleting the asset and adding it again, which will enter this "initialization" flow and accepting any given twap without combining it with other oracles.

```
/// @notice Allows owner to add assets.
/// @param _assets assets to add
function addAssets(address[] calldata _assets)
    external
    onlyRole(DEFAULT_ADMIN_ROLE)
{
    _addAssets(_assets);
}
/// @notice Allows owner to remove asset.
/// @param _asset asset to remove
function removeAsset(address _asset)
    external
    onlyRole(DEFAULT_ADMIN_ROLE)
    onlyWhenAssetExisted(_asset)
{
    _removeAsset(_asset);
}
```

## Impact

Compromised or malicious owner can fully control NFT prices, making them able to take uncollateralized loans or freely liquidate users

## Tools Used

Manual audit

## Recommended Mitigation Steps

Add a time delay when adding and deleting assets. Wait a certain time before new feeder's prices are accepted, to give time for users to react and flee with their assets.
Invalid ERC-165 implementation
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/tokenization/base/MintableIncentivizedERC721.sol#L572-L582


# Vulnerability details

## Impact
The MintableIncentivizedERC721 base contract implements IERC165 interface, but the supportsInterface implementation does not comply to the EIP-165.

Raising as medium priority because the incorrect implementation defeats its own purpose.

## Proof of Concept

The EIP-165 defines support for ERC-165 interface/implementation [here](https://eips.ethereum.org/EIPS/eip-165) and states the following:

How to Detect if a Contract Implements ERC-165
1. The source contract makes a STATICCALL to the destination address with input data: 0x01ffc9a701ffc9a700000000000000000000000000000000000000000000000000000000 and gas 30,000. This corresponds to contract.supportsInterface(0x01ffc9a7).
2. If the call fails or return false, the destination contract does not implement ERC-165.
3. If the call returns true, a second call is made with input data 0x01ffc9a7ffffffff00000000000000000000000000000000000000000000000000000000.
4. If the second call fails or returns true, the destination contract does not implement ERC-165.
5. Otherwise it implements ERC-165.

How to Detect if a Contract Implements any Given Interface
1. If you are not sure if the contract implements ERC-165, use the above procedure to confirm.
2. If it does not implement ERC-165, then you will have to see what methods it uses the old-fashioned way.
3. If it implements ERC-165 then just call supportsInterface(interfaceID) to determine if it implements an interface you can use.

## Tools Used
Manual review.

## Recommended Mitigation Steps
Follow the EIP-165 or inherit from a correct ERC-165 implementation as OpenZeppelin's one and ensure the supportsInterface call follows the inheritance chain.
executeBuyWithCredit() in MarketPlaceLogic contract don't refund extra received ETH that has been converted to wETH.
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/libraries/logic/MarketplaceLogic.sol#L63-L103
https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/libraries/logic/MarketplaceLogic.sol#L575-L591
https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/libraries/logic/MarketplaceLogic.sol#L569-L573


# Vulnerability details

## Impact
When user send extra ETH to `executeBuyWithCredit()` or `executeBatchBuyWithCredit()` and tries to buy WETH token, contract would convert user ETH to WETH but it won't transfer back the extra amount user has been sent to contract. (when it doesn't convert the ETH contract sent back the extra amount). so users would lose funds in some conditions, if buying tokens has no exact price then users needs to send extra ETH and those extra amount would be lost.

## Proof of Concept
This is `executeBuyWithCredit()` and `_depositETH()` code in Marketplace Logic contract:
```
   function executeBuyWithCredit(
        bytes32 marketplaceId,
        bytes calldata payload,
        DataTypes.Credit calldata credit,
        DataTypes.PoolStorage storage ps,
        IPoolAddressesProvider poolAddressProvider,
        uint16 referralCode
    ) external {
        MarketplaceLocalVars memory vars;

        vars.weth = poolAddressProvider.getWETH();
        DataTypes.Marketplace memory marketplace = poolAddressProvider
            .getMarketplace(marketplaceId);
        DataTypes.OrderInfo memory orderInfo = IMarketplace(marketplace.adapter)
            .getAskOrderInfo(payload, vars.weth);
        orderInfo.taker = msg.sender;
        vars.ethLeft = msg.value;

        _depositETH(vars, orderInfo);

        vars.ethLeft -= _buyWithCredit(
            ps._reserves,
            ps._reservesList,
            ps._usersConfig[orderInfo.taker],
            DataTypes.ExecuteMarketplaceParams({
                marketplaceId: marketplaceId,
                payload: payload,
                credit: credit,
                ethLeft: vars.ethLeft,
                marketplace: marketplace,
                orderInfo: orderInfo,
                weth: vars.weth,
                referralCode: referralCode,
                reservesCount: ps._reservesCount,
                oracle: poolAddressProvider.getPriceOracle(),
                priceOracleSentinel: poolAddressProvider.getPriceOracleSentinel()
            })
        );

        _refundETH(vars.ethLeft);
    }

    function _depositETH(
        MarketplaceLocalVars memory vars,
        DataTypes.OrderInfo memory orderInfo
    ) internal {
        if (
            vars.ethLeft > 0 &&
            orderInfo.consideration[0].itemType != ItemType.NATIVE
        ) {
            IWETH(vars.weth).deposit{value: vars.ethLeft}();
            IERC20(vars.weth).safeTransferFro
External functions supplyPunk, acceptBidWithCredit, and batchAcceptBidWithCredit should provide the possibility to buy punk directly 
Audit: 2022-11-paraspace-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/ui/WPunkGateway.sol#L77
https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/ui/WPunkGateway.sol#L129
https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/ui/WPunkGateway.sol#L167


# Vulnerability details

## Impact
External functions ```supplyPunk```, ```acceptBidWithCredit```, and ```batchAcceptBidWithCredit``` in ```WPunkGateway``` contract do not provide the possibility for buying punks directly. Indeed, since these functions are not payable, users cannot send ether to them and buy punks directly.

## Proof of Concept
https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/ui/WPunkGateway.sol#L77 

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/ui/WPunkGateway.sol#L129

https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/ui/WPunkGateway.sol#L167

## Recommended Mitigation Steps
External functions ```supplyPunk```, ```acceptBidWithCredit```, and ```batchAcceptBidWithCredit``` in ```WPunkGateway``` contract  should be payable and also ```msg.value``` should be added to ```buyPunk``` call.