Farseen0/scar-pairs huggingface dataset:
MEDIUM severity: [UFAR3] Ques Callback Iterates Over Deposit and Withdraw Queues Backwards. **Severity:** Medium

**Description:** In `UFarmPool:quexCallback`, the queues for deposits and withdrawals are processed, however they are handled in reverse order, from the most recent to the oldest. This means the original order in which users made their requests is not respected.

If the...

Vulnerable code:
requestsLength = depositQueue.length;
while (requestsLength > 0) {
    // Validate each deposit request
    depositItem = depositQueue[requestsLength - 1];
MEDIUM severity: [UFAR6] Protocol fees and management fees have not been deducted from the profit in the calculation of the performance fee. **Severity:** Medium

**Path:** contracts/main/contracts/pool/UFarmPool.sol#L748-L772

**Description:** In the UFarmPool contract, `protocolFee` and `managementFee` are always charged whenever `_accrueFee` is called, regardless of whether the pool's totalCost is in profit or loss. These fees...

Vulnerable code:
{
    uint256 protocolCommission = IUFarmCore(_ufarmCore).protocolCommission();
    uint256 costInTime = (totalCost * accrualTime) / YEAR;

    (protocolFee, managementFee) = (
        (costInTime * protocolCommission) / ONE,
        (costInTime * managementCommission) / ONE
    );
}

if (totalCost > highWaterMark) {
    uint256 profit = totalCost - highWaterMark;

    performanceFee = (profit * PerformanceFeeLib.ONE_HUNDRED_PERCENT) / highWaterMark; // APY ratio
    uint16 performanceCommission = performanceFee > PerformanceFeeLib.MAX_COMMISSION_STEP
        ? PerformanceFeeLib.MAX_COMMISSION_STEP
        : uint16(performanceFee); // Compare with max commission step, normalizing to MAX_COMMISSION_STEP

    performanceCommission = PerformanceFeeLib._getPerformanceCommission(
        packedPerformanceCommission,
        performanceCommission
    ); // Unpack commission percent for the step, where step is APY multiplier

    performanceFee = (profit * performanceCommission) / PerformanceFeeLib.ONE_HUNDRED_PERCENT; // Profit * commission rate
}

if (totalCost - protocolFee - managementFee > highWaterMark) {
    uint256 profit = totalCost - protocolFee - managementFee - highWaterMark;
    ...
MEDIUM severity: [UFAR7] Lack of Slippage Protection in UFarmPool Withdrawals and Deposits. **Severity:** Medium

**Path:** contracts/main/contracts/pool/UFarmPool.sol::quexCallback() 

**Description:** When depositing to or withdrawing from the `UFarmPool` contract, users must submit a request and wait for the `quexCallback()` function - called by `quexCore` - to process it.

The...

Vulnerable code:
sharesToMint = _mintSharesByQuote(investor, amountToInvest, _totalCost);

// Adjust the total cost and total deposit
_totalCost += amountToInvest;
totalDeposit += amountToInvest;

// Process the withdrawal
amountToWithdraw = _processWithdrawal(
    investor,
    sharesToBurn,
    _totalCost,
    withdrawalRequestHash,
    withdrawItem.bearerToken
);

if (investor != ufarmFund && amountToWithdraw != 0) {
    // Mark the request as used
    __usedWithdrawalsRequests[withdrawalRequestHash] = true;

    // Delete the request from the pending withdrawals
    delete pendingWithdrawalsRequests[withdrawalRequestHash];
}
MEDIUM severity: [UFAR8] USDC Blacklist Can Trigger DoS in quexCallback() Function. **Severity:** Medium

**Path:** contracts/main/contracts/pool/UFarmPool.sol#L554 

**Description:** The `UFarmPool.quexCallback()` function is responsible for processing all pending deposit and withdrawal requests from users. It iterates through the `depositQueue[]` and `withdrawQueue[]` arrays,...

Vulnerable code:
IERC20(bearerToken).safeTransfer(investor, burnedAssetsCost);

function _processWithdrawal(
    address investor,
    uint256 sharesToBurn,
    uint256 _totalcost,
    bytes32 withdrawalRequestHash,
    address bearerToken
) private keepWithdrawalHash(withdrawalRequestHash) returns (uint256 burnedAssetsCost) {
    uint256 _totalSupply = totalSupply();
    burnedAssetsCost = (_totalcost * sharesToBurn) / _totalSupply;

    if (IERC20(bearerToken).balanceOf(address(this)) >= burnedAssetsCost) {
        _burn(investor, sharesToBurn);
        
        /// @audit the following line will revert if the bearerToken = USDC and investor is a blacklisted address 
        IERC20(bearerToken).safeTransfer(investor, burnedAssetsCost); 
        emit Withdraw(investor, bearerToken, burnedAssetsCost, withdrawalRequestHash);

        highWaterMark -= highWaterMark > burnedAssetsCost ? burnedAssetsCost : highWaterMark;

        emit WithdrawRequestExecuted(investor, sharesToBurn, withdrawalRequestHash);
    } else {
        burnedAssetsCost = 0;
    }

    return burnedAssetsCost;
}
MEDIUM severity: [UFAR10] Fund creation DoS by front-running factory call. **Severity:** Medium

**Path:** FundFactory.sol:createFund#L47-L49

**Description:** The FundFactory exposes the `createFund` function, which uses a beacon proxy and `CREATE2` to deploy a new UFarmFund contract. This function is called from UFarmCore in the corresponding `createFund`...

Vulnerable code:
function createFund(
    address _fundManager,
    bytes32 _applicationId
)
    external override
    ownerOrHaveTwoPermissions(uint8(Permissions.UFarm.Member), uint8(Permissions.UFarm.ApproveFundCreation))
    nonReentrant returns (address fund)
{
    uint256 nextFundId = _funds.length();
    fund = fundFactory.createFund(_fundManager, _applicationId);
    _funds.add(fund);
    emit FundCreated(_applicationId, nextFundId, fund);
}

function createFund(address _manager, bytes32 _salt) external onlyLinked returns (address fund) {
    return SafeOPS._safeBeaconCreate2Deploy(fundImplBeacon, _salt, _getInitFundCall(_manager));
}

function _safeBeaconCreate2Deploy(
	address _beacon,
	bytes32 _salt,
	bytes memory _initCall
) internal returns (address addr) {
	try new BeaconProxy{salt: _salt}(_beacon, _initCall) returns (BeaconProxy beaconProxy) {
		return address(beaconProxy);
	} catch {
		revert BeaconProxyDeployFailed();
	}
}
MEDIUM severity: [UFAR5] Incorrect order of amounts emitted in the event of UnoswapV2Controller::delegatedAddLiquidity. **Severity:** Low

**Path:** contracts/main/contracts/controllers/UnoswapV2Controller.sol#L320

**Description:** In the `UnoswapV2Controller::delegatedAddLiquidity()` function, `tokenA` and `tokenB` are never sorted. However, `amountA` and `amountB`, obtained from `quoteExactLiquidityAmounts()`,...

Vulnerable code:
(uint256 amountA, uint256 amountB, address pair) = thisController.quoteExactLiquidityAmounts(
    tokenA,
    tokenB,
    alArgs.amountADesired,
    alArgs.amountBDesired,
    alArgs.amountAMin,
    alArgs.amountBMin,
    alArgs.deadline
);

bool reversed = tokenA > tokenB;

IERC20(tokenA).safeTransfer(pair, reversed ? amountB : amountA);
IERC20(tokenB).safeTransfer(pair, reversed ? amountA : amountB);

emit LiquidityAddedUnoV2(tokenA, tokenB, amountA, amountB, liquidity, pair, PROTOCOL());
HIGH severity: Cross-chain Replay in borrowAsset() & swapToBorrow(). **Description**

Cross-chain Replay: If an User borrows assets on Chain A, they could reuse the same signature (generated from the same data) on Chain B, assuming the signature is valid for the same borrow hash structure on both chains.

**Recommendations**

Vulnerable code:
bytes32 _borrowHash = keccak256(
    abi.encode(
        collaterals,
        borrows,
        collateralAmounts,
        borrowsAmounts,
        msg.sender,
        nonceOf[msg.sender],
        block.chainid // Include the chainId in the hash to make it unique per chain
    )
);
MEDIUM severity: Missing time limit for signature. **Description**

Some actions in financial contracts are time-sensitive, and allowing a signature to be valid indefinitely could break expected business rules. For instance, if the contract terms change or the collateral value fluctuates, an old signature might lead to unfair borrowing conditions...

Vulnerable code:
bytes32 _borrowHash = keccak256(
    abi.encode(
        collaterals,
        borrows,
        collateralAmounts,
        borrowsAmounts,
        msg.sender,
        nonceOf[msg.sender],
        deadline // Add expiry
    )
);

// Check if the signature is expired
if (block.timestamp > deadline) {
    revert SignatureExpired();
}
HIGH severity: Missing access control in `updateFairLaunchProperties()` function. **Description:**

The `updateFairLaunchProperties()` function allows external callers to update the `fairLaunchProperties` variable, which is used to determine whether the token is available for buying or selling. This function lacks proper access control, enabling any unauthorized user to modify...

Vulnerable code:
- function updateFairLaunchProperties(FairLaunchProperties memory _fairLaunchProperties) external returns (bool) {....}
+ function updateFairLaunchProperties(FairLaunchProperties memory _fairLaunchProperties) external onlyOwner returns (bool) {....}
HIGH severity: `getPrice()` will always revert due to absence of `fallback()` and `receive()` functions. **Description:**

The `getPrice()` function is designed to calculate the price of `saleToken` by dividing the contract's ETH balance by the balance of `saleToken` held by the contract. However, the function will always revert due to the absence `fallback()` or `receive()` function, and the...

Vulnerable code:
function getPrice() public view returns (uint256) {
        ...

        if (saleTokenBalance == 0) revert saleTokenBalanceZeroError();
@>      if (ethBalance == 0) revert EthBalanceZeroError();

        ...
    }
MEDIUM severity: User won't be able to buy token if he has less ETH in his wallet after paying for Token. **Severity:** Medium

**Context:** hyacinth_test.sol#L199

**Description:**

In the `buy()` function, there is a check to ensure that the sender's ETH balance is not less than the ETH amount sent:

This check is redundant and inaccurate because it checks the balance of `msg.sender` after the ETH...

Vulnerable code:
if (address(msg.sender).balance < ethAmount)
    revert InsufficientETHBalanceError();

// Remove this check
// if (address(msg.sender).balance < ethAmount) revert InsufficientETHBalanceError();
HIGH severity: [FIXED] Redundant asserts in `AllowedRecipientsBuilder`. ##### Location
File | Location | Line
--- | --- | ---
[AllowedRecipientsBuilder.sol](https://github.com/lidofinance/easy-track/tree/425f4a254ceb2be389f669580b9dc76618e92756/contracts/AllowedRecipientsBuilder.sol#L219-L220 "/contracts/AllowedRecipientsBuilder.sol") | contract...

Vulnerable code:
assert(!registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, address(this)));
assert(!registry.hasRole(DEFAULT_ADMIN_ROLE, address(this)));
HIGH severity: [ACKNOWLEDGED] Use of outdated libraries. ##### Location
File | Location | Line
--- | --- | ---
[FixedSpreadLiquidationStrategy.sol](https://github.com/Into-the-Fathom/fathom-stablecoin-smart-contracts/tree/3768c87367d286ae0e82f444b2f9d760417b507e/contracts/main/stablecoin-core/liquidation-strategies/FixedSpreadLiquidationStrategy.sol#L202....

Vulnerable code:
"@openzeppelin/contracts": "4.4.1",
"@openzeppelin/contracts-upgradeable": "4.4.1",
HIGH severity: [ACKNOWLEDGED] Check is not performed prior to sending funds in `FathomProxyWalletOwner`. ##### Location
File | Location | Line
--- | --- | ---
[FathomProxyWalletOwner.sol](https://github.com/Into-the-Fathom/fathom-stablecoin-smart-contracts/tree/3768c87367d286ae0e82f444b2f9d760417b507e/contracts/main/fathom-SDK/FathomProxyWalletOwner.sol#L114...

Vulnerable code:
(bool sent, ) = payable(msg.sender).call{ value: address(this).balance }("");
HIGH severity: [FIXED] No access control for `deposit` function call in `VaultStrat`. ##### Location
File | Location | Line
--- | --- | ---
[VaultStrat.sol](https://github.com/ZunamiProtocol/ZunamiProtocolV2/tree/8bc108201bef8c4d341ecd3a29a3b1d975019cec/contracts/strategies/VaultStrat.sol#L30 "/contracts/strategies/VaultStrat.sol") | contract `VaultStrat` > function `deposit` |...

Vulnerable code:
it('open deposit method in VaultStrat', async () => {
    const {
        alice,
        bob,
        zunamiPool,
        zunamiPoolController,
        strategies,
        usdt,
    } = await loadFixture(deployFixture);

    // add VaultStrat to zunamiPoolController
    const strategy = strategies[0];
    await zunamiPool.addStrategy(strategy.address);

    await zunamiPoolController.setDefaultDepositSid(0);
    await zunamiPoolController.setDefaultWithdrawSid(0);

    // Alice deposits 100 to VaultStrat
    await expect(
        zunamiPoolController
            .connect(alice)
            .deposit(getMinAmountZunUSD('100'), alice.getAddress())
    ).to.emit(zunamiPool, 'Deposited');

    // Bob deposits 100 to VaultStrat
    await expect(
        zunamiPoolController
            .connect(bob)
            .deposit(getMinAmountZunUSD('100'), bob.getAddress())
    ).to.emit(zunamiPool, 'Deposited');

    // Bob makes fake deposit to VaultStrat
    await strategy.connect(bob).deposit(getMinAmountZunUSD('200'))

    // Bob withdraws 200 from VaultStrat
    let balanceBefore = BigNumber.from(await usdt.balanceOf(bob.getAddress()));
    let sharesAmount = BigNumber.from(
        await zunamiPool.balanceOf(bob.getAddress())
    );
    await zunamiPool.connect(bob).approve(zunamiPoolController.address, sharesAmount);

    await expect(
        zunamiPoolController.connect(bob).withdraw(sharesAmount, [0, 0, 0, 0, 0], bob.getAddress())
    ).to.emit(zunamiPool, 'Withdrawn');

    expect(
        BigNumber.from(await usdt.balanceOf(bob.getAddress())).sub(balanceBefore)
    ).to.eq(ethers.utils.parseUnits('200', 'mwei'));
  });
HIGH severity: [FIXED] Blocking execution of `inflate` and `deflate` functions in `ConvexCurveStratBase`. ##### Location
File | Location | Line
--- | --- | ---
[ConvexCurveStratBase.sol](https://github.com/ZunamiProtocol/ZunamiProtocolV2/tree/8bc108201bef8c4d341ecd3a29a3b1d975019cec/contracts/strategies/curve/convex/ConvexCurveStratBase.sol#L32...

Vulnerable code:
uint256 balance = IERC20(lptoken).balanceOf(msg.sender);
deposit(_pid, balance, _stake);
HIGH severity: [FIXED] Elevated price in USD in the `getLiquidityTokenPrice` function leads to money theft from the pool in `ZunamiStratBase`. ##### Location
File | Location | Line
--- | --- | ---
[ZunamiStratBase.sol](https://github.com/ZunamiProtocol/ZunamiProtocolV2/tree/8bc108201bef8c4d341ecd3a29a3b1d975019cec/contracts/strategies/ZunamiStratBase.sol#L71 "/contracts/strategies/ZunamiStratBase.sol") | contract `ZunamiStratBase` >...

Vulnerable code:
function deposit(uint256[POOL_ASSETS] memory amounts) external returns (uint256) {
	// ...
	uint256 liquidity = depositLiquidity(amounts);
	depositedLiquidity += liquidity;
	return calcLiquidityValue(liquidity);
}

// ...
	minted =
		((totalSupply() + 10 ** _decimalsOffset()) * depositedValue) /
		(totalDeposited + 1);
}
_mint(receiver, minted - locked);
_strategyInfo[sid].minted += minted;

totalDeposited += depositedValue;

getLiquidityTokenPrice = 1 (USD)
	strategy.depositedLiquidity = 10000 (LP)
	zunamiPool.minted = 10000 (shares)
	zunamiPool.totalDeposited = 10000 (USD)
HIGH severity: [FIXED] Underflow in case of `depositedValue` is lower than `MINIMUM_LIQUIDITY` on the first deposit to the strategy in `ZunamiPool`. ##### Location
File | Location | Line
--- | --- | ---
[ZunamiPool.sol](https://github.com/ZunamiProtocol/ZunamiProtocolV2/tree/8bc108201bef8c4d341ecd3a29a3b1d975019cec/contracts/ZunamiPool.sol#L199 "/contracts/ZunamiPool.sol") | contract `ZunamiPool` > function `processSuccessfulDeposit` |...

Vulnerable code:
if (totalSupply() == 0) {
	minted = depositedValue;
	locked = MINIMUM_LIQUIDITY;
	_mint(MINIMUM_LIQUIDITY_LOCKER, MINIMUM_LIQUIDITY);
} else {
	// ...
}
_mint(receiver, minted - locked);
HIGH severity: [FIXED] Inflation attack in `ZunamiPool`. ##### Location
File | Location | Line
--- | --- | ---
[ZunamiPool.sol](https://github.com/ZunamiProtocol/ZunamiProtocolV2/tree/8bc108201bef8c4d341ecd3a29a3b1d975019cec/contracts/ZunamiPool.sol#L196 "/contracts/ZunamiPool.sol") | contract `ZunamiPool` > function `processSuccessfulDeposit` |...

Vulnerable code:
minted =
    ((totalSupply() + 10 ** _decimalsOffset()) * depositedValue) /
    (totalDeposited + 1);
HIGH severity: [FIXED] Using constant in `CurveStratBase`. ##### Location
File | Location | Line
--- | --- | ---
[CurveStratBase.sol](https://github.com/ZunamiProtocol/ZunamiProtocolV2/tree/8bc108201bef8c4d341ecd3a29a3b1d975019cec/contracts/strategies/curve/CurveStratBase.sol#L36 "/contracts/strategies/curve/CurveStratBase.sol") | contract...

Vulnerable code:
for (uint256 i = 0; i < 5; i++) {
HIGH severity: Incorrect user accounting in `withdraw` method. **Proof of Concept**

The `withdraw` method in `NYProfitTakingVaultBaseV1` does incorrect user accounting in the following line:

In the `deposit` method we use the `user.amount` to store the amount of `underlying` tokens deposited, but in `withdraw` instead of subtracting the `underlying` tokens...

Vulnerable code:
- user.amount = user.amount - _shares;
+ user.amount = user.amount - r;
MEDIUM severity: MEV can sandwich every harvest due to missing slippage tolerance value. **Proof of Concept**

In `NyPtvFantomWftmBooSpookyV2StrategyToUsdc` each time the `_harvestCore` method is called (on each harvest) it will call the `_swapFarmEmissionTokens` method which itself has the following code:

The “0” here is the value of the `amountOutMin` argument which is used for...

Vulnerable code:
IUniswapV2Router02(SPOOKY_ROUTER).swapExactTokensForTokensSupportingFeeOnTransferTokens(
      booBalance,
      0,
      booToUsdcPath,
      address(this),
      block.timestamp
    );
LOW severity: If `underlying` or `rewardToken` is a two-address token then `inCaseTokensGetStuck` method can be used to rug users. **Proof of Concept**

Some ERC20 tokens on the blockchain are deployed behind a proxy, so they have at least 2 entrypoints (the proxy and the implementation) for their functionality. Example is Synthetix’s `ProxyERC20` contract from where you can interact with `sUSD, sBTC etc). If such a token was.....

Vulnerable code:
if (_token == address(underlying)) {
      revert NYProfitTakingVault__CannotWithdrawUnderlying();
}
if (_token == address(rewardToken)) {
      revert NYProfitTakingVault__CannotWithdrawRewardToken();
}
LOW severity: The `getPricePerFullShare` method returns a wrong value when `totalSupply` is 0. **Proof of Concept**

The `getPricePerFullShare` method currently computes the result by the following formula:

The problem is that when the underlying token used is with less or more than 18 decimals and the `totalSupply` is still 0, then the price returned won’t be correct, as it will be 1e18....

Vulnerable code:
return totalSupply() == 0 ? 1e18 : (balance() * 1e18) / totalSupply();

if (totalSupply() == 0) {
      shares = _amount;
}

- return totalSupply() == 0 ? 1e18 : (balance() * 1e18) / totalSupply();

+ return totalSupply() == 0 ? 10**underlying.decimals() : (balance() * 1e18) / totalSupply();
HIGH severity: The `unlockExponent` does not work as intended when it is ≠ 1. **Proof of Concept**

The documentation and the chart in `README.md` shows that it is expected that when `unlockExponent == 0` then immediately after funds `unlockDelaySec` the user can claim his whole locked amount. This is actually not working as intended, let’s look at the...

Vulnerable code:
uint256 factor = deltaTimeNormalized ** unlockExponent;

if (factor > precision) {
         factor = precision;
}

uint256 deltaTimeNormalized = (deltaTimeDelayed * precision) / unlockPeriodSec;

uint256 factor = deltaTimeNormalized ** unlockExponent;

if (factor > precision) {
      factor = precision;
}
uint256 totalUnlockedAmount = (record.totalAmount * factor) / precision;
HIGH severity: Unsafe call to `ER:transfer` can result in stuck funds. **Proof of Concept**

In the `_sendFunds` method we have the following code for transferring ERC20 tokens

The problem is that the `transfer` function from ERC20 returns a bool to indicate if the transfer was a success or not. As there are some tokens that do not revert on failure but instead...

Vulnerable code:
IERC20(underlyingToken).transfer(receiver, amount);
MEDIUM severity: Gas stipend for external call might be insufficient and lead to stuck ETH. **Proof of Concept**

The way the Zerem protocol transfers out ETH looks like this

As you see, there is a gas stipend of 3000, but this might not be enough in some cases as some smart contract recipients need more than 3000 gas to receive ETH.

Examples of problematic recipients:

1. Recipient is.....

Vulnerable code:
payable(receiver).call{gas: 3000, value: amount}(hex"")
MEDIUM severity: Gas griefing/theft is possible on unsafe external call. **Proof of Concept**

This comment `// TODO: send relayer fees here` in the `unlockFor` method and its design show that it is possible that `unlockFor` is usually called by relayers. This opens up a new attack-vector in the contract and it is gas griefing on the ETH transfer

Now `(bool success,...

Vulnerable code:
(bool success,) = payable(receiver).call{gas: 3000, value: amount}(hex"");

bool success;
assembly {
    success := call(3000, receiver, amount, 0, 0, 0, 0)
}
HIGH severity: There is no way to withdraw the ETH paid by minters. **Proof of Concept**

There is currently no possible way for the contract deployer/owner to withdraw the ETH that was paid by miners. This means that value will be stuck & lost forever.
This is also the case for the `ERC721A` standard, which this project actually extends as well, but it was...

Vulnerable code:
function withdrawBalance() external onlyOwner {
    (bool success, ) = msg.sender.call{value: address(this).balance}("");
    require(success);
  }
HIGH severity: If address is a smart contract that can't handle ERtokens they will be stuck after a whitelisted mint. **Proof of Concept**

The `mintPublic` method has a check that allows only EOAs to call it

but it is missing in the whitelisted mint methods (`mintArcanaList`, `mintAspirantList`, `mintAllianceList`). This means that if the address that is whitelisted is a contract and it calls those functions...

Vulnerable code:
if (tx.origin != msg.sender) revert ContractsNotAllowed();
MEDIUM severity: `claimTimeout` is not checked for first claim by an account. **Likelihood:**
High, because it will happen for each account's first claim

**Impact:**
Low, because there is no loss of funds, but code is not working as intended

**Description**

In `claimRewards` in `LP.sol` there is the following check

which basically forces an account that claims his...

Vulnerable code:
if ((block.timestamp - reward.claimedAt) < claimTimeout)
    revert ClaimTimeout(reward.claimedAt + claimTimeout);
HIGH severity: `transferERToTreasury` won't work as intended if `assetToken` is a multiple-address token. **Likelihood:**
Low, because it requires using a multiple-address token and a malicious/compromised admin

**Impact:**
High, because users can use 100% of their deposits

**Description**

Some ERC20 tokens on the blockchain are deployed behind a proxy, so they have at least 2 entry points (the...

Vulnerable code:
require(tokenAddress != _assetTokenAddress, "IP: Asset transfer");
MEDIUM severity: Inverted slippage protection approach can lead to problems. **Likelihood:**
Low, because it needs more than one special condition simultaneously

**Impact:**
Medium, because it can lead to limited amount of funds lost from the protocol

**Description**

Both the `leaveETH` and `leave` methods use the `slippage` storage variable to implement slippage...

Vulnerable code:
uint256 percentage = 100000 - slippage;
uint256 glpPrice = priceFeed.getGLPprice().mul(percentage).div(100000);
uint256 glpOut = amountOut.mul(10**12).mul(tokenPrice).div(glpPrice).div(10**30);
LOW severity: Inconsistent `tokenData.owner` validation. The `mintRecord` functionality in `Collection` allows the caller to mint tokens to any address since the `to` argument is not validated in any way. The problem is that the `getTokenData` inherited function has the following check:

which is not actually true, because a token could be minted to the.....

Vulnerable code:
require(data.owner != address(0), "NOT_MINTED");