Primex Finance security record

Arbitrum, Base, BNB Chain, Ethereum, Polygon (POS)primex.financeXGitHub

As of 30 Oct 2026, Primex Finance has 5 audit reports by 2 security firms on Trustblock; the latest is by Resonance Security, dated 14 Oct 2024. Those reports list no open critical findings.

Critical findings
No open critical findings
Across the 5 reports, 2 critical findings were reported. Each is marked fixed by the firm that reported it. See the findings
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.

Audits5

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Primex FinanceSecurity firm: Resonance SecurityDate: Scope: 401 addresses on Ethereum, Polygon (POS) and ArbitrumNo open critical findingsOpen · IPFS
Primex FinanceSecurity firm: Resonance SecurityDate: Scope: 401 addresses on Ethereum, Polygon (POS) and Arbitrum1 critical finding, fixedOpen · IPFS
Primex FinanceSecurity firm: Resonance SecurityDate: Scope: 401 addresses on Ethereum, Polygon (POS) and ArbitrumNo open critical findingsOpen · IPFS
Primex FinanceSecurity firm: Resonance SecurityDate: Scope: 401 addresses on Ethereum, Polygon (POS) and Arbitrum1 critical finding, fixedOpen · IPFS
Primex FinanceSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com

Findings92

Statuses are the security firm’s own, from each report.

SeverityOpenAcknowledgedFixed
Critical001
High007
Medium3411
Low91146
CriticalPossible To Use Outdated Variables During Flash LoansPrimex Finance · Resonance Security · 14 Oct 2024Fixed

The function flashLoan() does not update important variables right after the transfer of the assets. Essentially, there are three steps to the function flashLoan():Calculate fees, available liquidities and transfer the assets to the borrower.Give control to the borrower to execute the intended operation.Handle the repayment of the flash loan.During the first step, the transfer of the assets to the receiver is performed but the calls to the functions _updateRates() and _updateIndexes() are not performed. These are only performed later after the executeOperation() function call on the third step during _handleFlashLoanRepayment(). This effectively means that malicious borrowers may execute operations within the flash loan transaction, such as deposit() and withdraw(), that will operate under outdated rates and indexes variables. Taking into additional consideration that flash loans can amount to big numbers and different buckets, the execution of such functions may yield unfavorable results to the protocol.The same attack vector is true for the variable availableLiquidity.

Open the report
HighInvalid Asset Price Due To Incomplete Price MappingsPrimex Finance · Resonance Security · 14 Oct 2024Fixed

The PriceOracle contract is responsible for dictating the prices for given assets. The prices could be fetched using multiple of sources - Uniswap, Pyth and Chainlink to be precise. However, the Pyth and Chainlink sources support only prices denominated in USD. The PriceOracle contract keeps the prices in a mapping that is indexed with the asset price and returns that asset's price in USD. Hence, if the requested price is for a pair that does not include USD (for instance BTC/ETH) and Pyth/Chainlink is used as a price source, then the _getExchangeRate() function would actually return the price denominated in USD which will lead to invalid calculations.

Open the report
HighMissing Return Value On _swapExactTokensForTokens() Leads To Incorrect CalculationsPrimex Finance · Resonance Security · 14 Oct 2024Fixed

The functions performPathsSwap() and swapExactTokensForTokens() make use of the internal function _swapExactTokensForTokens() and expect a uint256[3]value to be returned. Further calculations are made with this returned value. However, for the DexType.Paraswap, no value is returned, both leading to incorrect calculations of values presented to the caller of the functions.

Open the report
HighPossible Drain Of Funds On updatePullOracle()Primex Finance · Resonance Security · 14 Oct 2024Fixed

The function updatePullOracle() does not properly validate the amount of Ether sent to the smart contract and allows for funds to be drained to an external contract. This can occur when the validation on the variable msg.value is being done after funds have been transferred. While it seems counterintuitive, the variable msg.value does not change throughout the transaction, even after successful outbound transfers of native funds.The following describes an example of an attack scenario for this specific case:User calls updatePullOracle() while sending 10 Wei. The variable msg.value will contain the value 10.For the Pyth if branch, the variable updateFee is calculated via pyth.getUpdateFee().Supposing a value of 9 for the variable updateFee, the require statement will pass successfully.9 Wei is sent to the external contract pyth via updatePriceFeeds(). 1 Wei is left from the funds deposited by the user.Supposing input parameters that will result in the execution of multiple iterations of the for loop, and supposing a calculation result of 9 for the second updateFee, the next iteration of the require statement will still pass successfully (9 <= 10) since the value of msg.value does not change, even though funds have been transferred away on the first iteration. This means that if the contract PriceOracle contains funds, these will be used along with the 1 Wei left from the user.Next iterations will drain the funds of the PriceOracle smart contract completely.

Open the report
HighPossible Unrecoverable Funds On updatePullOracle()Primex Finance · Resonance Security · 14 Oct 2024Fixed

The function updatePullOracle() is payable and therefore, it can receive native Ether from callers of this function. When using UpdatePullOracle.Pyth as an oracle type, the calculated updateFee is required to be less than or equal to the amount of native Ether received via msg.value. When the caller of the function sends a higher amount of Ether than the one required by updateFee, the smart contract PriceOracle will retain the excess funds and it will be impossible to retrieve them, making the contract act as a sink for unrecoverable funds.

Open the report
HighSlippage Vulnerability in PrimeX Protocol for Swap and Spot Trade PositionsPrimex Finance · Quantstamp · 19 Oct 2023Fixed

In the PrimeX protocol, the keeper can attack orders using spot trades or swaps. The protocol includes slippage protection by comparing the DEX execution price with the oracle price data within a certain gap. However, this protection is not applied to swap and spot trade positions. As a result, if a limit order is created for a swap or spot trade, there can be high slippage without the oracle price gap protection. The limit orders do not have the slippage protection by `amountOutMin` as well.

Open the report
HighTraders May Lose Entire Position if Asset Was Removed From BucketPrimex Finance · Quantstamp · 19 Oct 2023Fixed

When an asset was removed from a bucket through `removeAsset()`, the assets of all open positions may be transferred to the treasury. The affected traders will lose their entire position. The issue arises from the fact that `health()` in `PositionLibrary` returns 0 when `position.positionAsset` is not an allowed asset in the bucket. This can only occur if the asset was removed, as this position could not exist otherwise. Because `health()` returns 0, those positions can be closed through `closePosition()` with `CloseReason.RISKY_POSITION`. Such closures will lead to the traders not receiving any profits (`topUpAvailableBalance()` will not be called) AND not receiving their deposit back, as `decreaseTraderDebt()` will be called with `params.primexDNS.treasury()` as a receiver. Furthermore, when a position is closed due to liquidation, the trader will not receive any funds back. The deposit and potential profit will be sent to the treasury in the `PositionLibrary.closePosition()`.

Open the report
HighVolatility May Be Greater than OnePrimex Finance · Quantstamp · 19 Oct 2023Fixed

The Chainlink Volatility Feed measures the [realized volatility](https://docs.chain.link/data-feeds/rates-feeds#realized-volatility) of one asset against another. Note that realized volatility can be greater than or equal to 100% (see: [formula here](https://www.wallstreetmojo.com/realized-volatility/#h-realized-volatility-formula)), and such an instance would create one of two problems: * In the case where the volatility is exactly 100% any user holding this asset would have a health of 0 and hence be able to liquidate. * In the case where the volatility is over 100% the calculation of a user's health will fail due to overflow and hence no one will be able to liquidate.

Open the report
MediumMissing Validation Of Input Parameters On updatePullOracle()Primex Finance · Resonance Security · 14 Oct 2024Fixed

The function updatePullOracle() does not validate the input arrays _data and _oracleTypes. It is possible for this function to be called with mismatching input array lengths and allowing transactions to occur on only a subset of the input elements.

Open the report
Medium`ECDSA` Library Vulnerable to Signature MalleabilityPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The protocol currently utilizes OpenZeppelin's `ECDSAUpgradeable` version `4.3.1` in contracts `PMXBonusNFT`, `ReferralProgram`, and `WhiteBlackListReferral` for validating registration using `ECDSAUpgradeable.recover(bytes, bytes)`. However, it is important to note that version `4.7.3` introduced a high-severity patch to address a [vulnerability related to signature malleability](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h) in the `ECDSA.recover()` and `ECDSA.tryRecover()` functions. These functions were found to be vulnerable due to accepting EIP-2098 compact signatures in addition to the traditional 65-byte signature format. This vulnerability affected the functions that accept a single bytes argument, not the ones that take `r, v, s` or `r, vs` as separate arguments. As a result, the `PMXBonusNFT`, `ReferralProgram`, and `WhiteBlackListReferral` contracts are impacted since they utilize the single bytes argument version of `ECDSA`, and version `4.3.1` is affected by this vulnerability.

Open the report
Show 10 more
MediumAssumption of Singular Bucket Updates in `_searchApproxIndex()` FunctionPrimex Finance · Quantstamp · 19 Oct 2023Fixed

In the `FeeExecutor`, lists `updatedTimestamps` and `indexes` are used to track all index and timestamp updates for a bucket. The function `FeeExecutor._searchApproxIndex()` is designed to return an approximate index corresponding to a given bonus deadline and the current index. However, its implementation, which employs a binary search approach, assumes that only one bucket updates are recorded in the `updatedTimestamps` and `indexes` lists. This assumption is incorrect because multiple buckets can update the lists using the function `FeeExecutor._updateIndex()`. Based on `FeeDecreaser` and `InterestIncreaser` functions, the `_updateIndex()` function pushes different bucket indexes which can be different based on the bucket's specific `bar` rate. This incorrect assumption can lead to inaccurate results returned by the `_searchApproxIndex()` function.

Open the report
MediumBuggy `BestDexLens` ImplementationPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The `BestDexLens.getBestMultipleDexes()` function filters out DEX results and attempts to optimize share splits across DEX results to return the best DEX routing path for the amount requested. However, several concerns arise from the current implementation: 1. **Overwriting the Negative Value**: Within the loop, a condition checks if `amount` equals 0 and assigns `VERY_NEGATIVE_VALUE` to `amountByDexByShare`. However, in the subsequent lines, this value is immediately overwritten without any related checks. 1. **Unsafe Gas Estimation**: The gas, represented in ETH units (`vars.gas`), is directly added or subtracted to/from the `amount`. Mixing gas estimations in ETH with an amount that might represent another token or asset unit could lead to inaccurate calculations or misrepresentations of value. 1. **Unsafe Casting to `int256`**: The `amount`, an unsigned integer, is directly cast to `int256`. Without ensuring the `amount` is within safe bounds, this could introduce potential overflows or unexpected negative values. 1. **Arbitrarily Large Negative Value Concern**: A value `VERY_NEGATIVE_VALUE` defined as `-1e72` is used to indicate an undesirable amount obtained from the DEX. The problem arises when `currentValue` is assigned this large negative value and subsequently compared to other values using the conditional `_params.isAmountToBuy ? (currentValue < bestValue || bestValue == 0) : currentValue > bestValue`. If `_params.isAmountToBuy` is `true`, then a `currentValue` of `VERY_NEGATIVE_VALUE` will almost always be considered smaller than `bestValue`, even if `bestValue` represents a more desirable outcome. This bug can lead to incomplete or suboptimal solutions.

Open the report
MediumClose Conditions May Be Incorrectly Set in `BatchManager`Primex Finance · Quantstamp · 19 Oct 2023Fixed

When batch closing positions through `BatchManager.closeBatchPositions()`, each position listed in the array `_ids` is validated. If the position does not exist through `PositionManager.getPosition()`, the function will catch the error and continue to the next position id in the `_ids` array. Therefore the `i` variable may not track to `vars.length` and `vars.length` can be less than `i`. ```solidity if ( _closeReason == PositionLibrary.CloseReason.BATCH_STOP_LOSS || _closeReason == PositionLibrary.CloseReason.BATCH_TAKE_PROFIT ) vars.closeConditions[vars.length] = positionManager.getCloseCondition(vars.ids[i], _conditionIndexes[i]); ``` Therefore, the variable `i` used to obtain the position close condition can be incorrect. Since `i` can be ahead of `vars` the position id can be zero. This will return the close condition from position id `0` for the current position `_ids[i]` and can incorrectly close the current position being evaluated.

Open the report
MediumDeployers Can Upgrade Factory Deployed ContractsPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The architecture graph suggests that exclusive roles should possess substantial privileges, which should be meticulously time-locked for enhanced security. The factories inherit the `UpgradeableBeacon` contract for beacon upgrades. However, the `UpgradeableBeacon` contract inherits the `Ownable` contract, making the deployer the owner and granting them the ability to upgrade implementations through the `UpgradeableBeacon.upgradeTo()` function (see: [code](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4d4a509b1f8e521583d82c042ef4bce919fe8e12/contracts/proxy/beacon/UpgradeableBeacon.sol#L52C14-L52C23)). As a result, the deployer holds a significant privilege to upgrade all contracts, highlighting the need to secure this role and its associated responsibilities.

Open the report
MediumInsufficient Reward upon PMX WithdrawalPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The `ActivityRewardDistributor.withdrawPmx()` function enables the admin to withdraw unused PMX tokens from the contract. During the execution of this function, the `bucketInfo.totalReward` is reduced by the withdrawal amount. However, the `bucketInfo.rewardPerDay` and `bucketInfo.endTimestamp` remain unchanged. As a result, there may not be enough PMX tokens available to cover the reward until the end timestamp. Additionally, the `lastUpdatedRewardTimestamp` is not updated as expected. As a consequence, the time span since this timestamp was last refreshed is inaccurately accounted for during subsequent reward accumulation. Specifically, when rewards are withdrawn, the `bucketInfo.fixedReward` value increases based on the duration since the `lastUpdatedRewardTimestamp`. Failure to update the `lastUpdatedRewardTimestamp` can result in the period being double-counted if it is not properly updated.

Open the report
MediumInterest Accumulation Prior to Bucket LaunchPrimex Finance · Quantstamp · 19 Oct 2023Fixed

According to the [documentation](https://docs.primex.finance/guides/credit-buckets/liquidity-mining), it states that "During the stabilization period, Traders can now borrow funds from the Credit Bucket, and Lenders start earning interest on the liquidity they provide for margin trading." Based on this information, we assume that lenders only start earning interest after moving to the stabilization period, which occurs when the bucket launches. Additionally, the implementation of `_depositLM()` does not update indexes and rates. However, the `withdraw()` function allows lenders to withdraw funds before the bucket launches. Within this function, both `_updateIndexes()` and `_updateRates()` are called, causing the index to be updated and start accumulating before the bucket launches.

Open the report
MediumOverflow Blocking `ActivityRewardDistributor` From FunctioningPrimex Finance · Quantstamp · 19 Oct 2023Fixed

In both the `setupBucket()` and `decreaseRewardPerDay()` functions of the `ActivityRewardDistributor` contract, if `rewardPerDay` is equal to zero, the `bucketInfo.endTimestamp` is overridden to `type(uint256).max`. Additionally, the `getBucketAccumulatedReward()` and `_updateBucketInfo()` functions have the logic of `endTimestamp += unusedTime` when `rewardPerDay == 0`. The line `endTimestamp += unusedTime` will overflow if the `endTimestamp` is set to `type(uint256).max`. Consequently, almost all functions relying on `getBucketAccumulatedReward()` and `_updateBucketInfo()` will fail. From our discussion with the team, the `rewardPerDay` can be set to zero as emergency mitigation in case there is a bug to stop the accrual of incorrect rewards. Despite the likelihood of this occurring being low, it would cause extra chaos and worsen the emergency situation, which is why it is a medium-severity issue.

Open the report
MediumReserve May Fall Below the Minimum Percentage of Total SupplyPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The `Reserve` currently uses `pToken.scaledTotalSupply()` instead of actual token supply `pToken.totalSupply()`, when validating the minimum percentage of token supply in the `Reserve` during the function `transferToTreasury()`. This methodology could result in inaccuracies in the calculated minimum percentage, which can lead to a lower than expected minimum percentage in the reserve. ``` _require( reserveBalance >= (restristions.minAmountToBeLeft + amount) && reserveBalance >= (pToken.scaledTotalSupply().wmul(restristions.minPercentOfTotalSupplyToBeLeft) + amount), Errors.NOT_SUFFICIENT_RESERVE_BALANCE.selector ); ```

Open the report
MediumStrict Oracle Tolerance in Spot Trade Can Prevent Traders From Closing PositionsPrimex Finance · Quantstamp · 19 Oct 2023Fixed

When closing a spot trade position (or more specifically, on `vars.borrowedAmountIsNotZero` in `PositionManager._closePosition()#L682-690`) through `PositionManager._closePosition()` the `oracleTolerableLimit` is set to zero between `depositAsset` and `positionAsset`. This means when closing the position through `PositionLibrary.closePosition()`, the swapped amount returned by the DEX in the `PrimexPricingLibrary.multiSwap()` must be equivalent to or better than the price provided by the price oracle. This check is validated in the `multiSwap()` where the `getOracleAmountsOut()` must be greater or equal to the amount obtained from the DEX because `_needOracleTolerableLimitCheck` is set to `true` in the `PositionLibrary.closePosition()` function. This strict requirement can prevent spot traders from closing their positions.

Open the report
LowFunction Does Not Account For Gas Calculations On All ChainsPrimex Finance · Resonance Security · 14 Oct 2024Fixed

The function getEstimatedMinProtocolFee() does not account for gas calculations for the newly introduced Optimistic chain integration. The variable l1CostWei will always yield a value of 0. While this may be intended, it does not conform with code implemented across other smart contracts on the protocol.

Open the report
Show 10 more
LowGas Price Not Set For ArbitrumPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:Gas price oracle was not set for Arbitrum, and defaultMaxGasPrice was used instead of it that caused incorrect min protocol fee and min position size calculations. We’ve added a wrapper contract on top of Arb gas price precompiles that returns gas price in the required format.

Open the report
LowImpossible To Create Orders For Assets With Pull OraclesPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:In createLimitOrder, there is a check that the expected position size is higher than minPositionSize. However this method dont include pullOracleData so it was impossible to create an order for assets with pull oracles.

Open the report
LowImpossible To Execute Limit Orders Through PrimexUpkeepPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:Executing a limit order through primexUpkeep is not possible as the method is not payable, and it cannot pay the Pyth pull oracle fee in the native token.

Open the report
LowIncorrect Calculations For minFeeRestrictionsPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:Method getL1BaseLengthForTradingOrderType returned the sum of lengths for position opening and closing for limit orders that caused incorrect calculations of minProtocolFee for these actions separately.

Open the report
LowIncorrect Fee In Health Calculation After UpgradePrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:The positions opened before the upgrade paid the protocol fee at the moment of opening, and the fee from them is not taken again upon closing, but this fee was taken into account in the health calculation. A check was added to avoid it.

Open the report
LowIncorrect Token Amount Used In Protocol Fee Calculation For Batch ClosingPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:An incorrect token amount was used in the protocol fee calculation for batch closing, tokenOut and amountIn were used instead of tokenOut and amoutOut.

Open the report
LowLack Of Event Emission In TraderBalanceVaultPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:The following functions do not emit relevant events after executing sensitive actions:withdrawFromincreaseLockedBalancetopUpAvailableBalance

Open the report
LowLimit Orders Work Incorrectly Due To Fee StructurePrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:After the changes in fee structure, limit orders created before the upgrade worked incorrectly - the fee associated with them was locked after the order execution or editing, also the order became unexecutable and unclosable after editing.

Open the report
LowminPositionSizeMultiplier MisinterpretationPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:We renamed minPositionSizeMultiplier to minPositionSizeAddend because the old name didn’t correspond to its meaning, and irrelevant restrictions were removed.

Open the report
LowMissing Estimation Of minProtocolFee For LiquidationPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:Added a new method to Lens to calculate min protocol fee for liquidation.

Open the report
Show 10 more
LowMissing extraParams In OpenPositionDataPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:The OpenPositionData struct had no extraParams field in src/contracts/interfaces/IPrimexLens.sol

Open the report
LowMissing protocolFeeCoefficient In minPositionSize CalculationPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:The protocolFeeCoefficient was missed in minPositionSize calculation, but this coefficient is a part of min protocol fee, which defines the min position size.

Open the report
LowMissing Reinitialization On SwapManager And BatchManager Due To UpgradePrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:The initialize functions of SwapManager and BatchManager check the interfaces of the contracts they receive as parameters, including IPositionManagerV2 and IPriceOracleV2, which will be added with this upgrade. However, the initialize method was called before the upgrade of the PositionManager and PriceOracle contracts, causing the check to fail. To resolve this, the initialization was split into two steps, with the second step executed after the upgrade of these contracts.

Open the report
LowMissing Revert Case For Uniswap v3 TWAP OraclePrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:Add revert to Uni v3 TWAP oracle for the case if the pool is unavailable.

Open the report
LowOverly Restrictive Requirement Leads To Failed Token SwapsPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:It was impossible to swap tokens through an arbitrary contract using DexAdapter.swapExactTokensForTokens as it required that the router had to be whitelisted. This restriction was removed.

Open the report
LowParameter Name Mismatch In setPoolUpdateIntervalPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:The setPoolUpdateInterval function in src/contracts/UniswapPriceFeed/UniswapPriceFeed.sol is designed to set poolUpdateInterval. However it will not work due to parameter name mismatch.

Open the report
LowPossible Duplicate Assets In FlashloanPrimex Finance · Resonance Security · 14 Oct 2024Fixed

The FlashLoanManager contract contains logic related to flashloans. Most notably - the flashLoan function used to initiated the loan. Among other arguments, this function takes two arrays - buckets and amounts which specify assets to be used in the flashloan. It was observed that the flashLoan function does not verify the uniqueness of entries in the buckets array. Hence, it is possible to use the same asset multiple times during the same flashloan. As a consequence, in this scenario the contract will need to perform additional cross-contract calls and use more memory for the execution which would be inefficient.

Open the report
LowRedundant Code On _withdrawBucketLiquidityFromAave()Primex Finance · Resonance Security · 14 Oct 2024Fixed

The function _withdrawBucketLiquidityFromAave() is duplicated on both Bucket and BucketExtension contracts. This fact makes the code more complex and less readable, while also wasting unnecessarily more bytecode on the blockchain.

Open the report
LowTransaction Fails Due To Price DifferencePrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:The borrowed amount for margin limit orders was calculated during the order execution based on the oracle prices. At the same time, keepers calculate the swap route before the transaction execution, and if the amountIn used in the route and the amount calculated in tx differs, the transaction fails. To fix it, we allowed keepers to set the borrowed amount, but we also check that the leverage of the opened position can’t differ from the leverage of the order for more than leverageTolerance percentage.

Open the report
LowUniform Health Check During LiquidationPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:There is a difference in minProtocolFee calculation for single and batch position closing which leads to different health values and the liquidation price for the same position depending on the closing method.

Open the report
Show 10 more
LowUnnecessary Usage Of int256 On minPositionSizeMultiplierPrimex Finance · Resonance Security · 14 Oct 2024Fixed

The contract KeeperRewardDistributorStorageV2 implements the state variable minPositionSizeMultiplier as an int256. The usage of this state variable throughout the code assumes that it will always contain an unsigned integer. Therefore, various checks may be removed to optimize gas.

Open the report
LowUpdated Admin RolesPrimex Finance · Resonance Security · 14 Oct 2024Fixed

Issue identified by Primex:Change admin roles for some methods.

Open the report
Low`depositAndLock()` Not Directly Tied to a DepositPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The `TraderBalanceVault.depositAndLock()` function allows the `VAULT_ACCESS_ROLE` to add any amount of any asset to any trader's locked balance. However, this function does not actually require that a deposit takes place, contrary to what the function name suggests.

Open the report
Low`increaseDeposit()` May Revert if No Swap Is PerformedPrimex Finance · Quantstamp · 19 Oct 2023Fixed

When increasing the deposit of a position through `PositionLibrary.increaseDeposit()`, the following check is performed: ``` _require(depositedAmountInBorrowed >= params.amountOutMin, ...) ``` However, this check will also be performed in case `params.asset == borrowedAsset`, meaning that no swap is executed. Therefore, this swap may revert if the user has provided `_amountOutMin` in `increaseDeposit(..)` of `PositionManager.sol` anyway.

Open the report
Low`orderExist` Modifier May Incorrectly Return TruePrimex Finance · Quantstamp · 19 Oct 2023Fixed

The `limitOrderManager.orderExists` modifier may run into a problem when `orders.length == 0`. In this case, if it is called with input `0` then it will return true since the check `orders[index].id == _orderId` essentially amounts to a check that `0 == 0`.

Open the report
Low`PositionManager` and `BatchManager` do not need `NO_FEE_ROLE`Primex Finance · Quantstamp · 19 Oct 2023Fixed

The deployment process grants `NO_FEE_ROLE` to `PositionManager` and `BatchManager` in addition to `LimitOrderManager` and `Bucket`. The `NO_FEE_ROLE` is given to contracts to avoid protocol fees when swapping with `SwapManager`. The `PositionManager` and `BatchManager` do not need `NO_FEE_ROLE` because the contracts do not use `SwapManager` to conduct swaps.

Open the report
LowApplication Monitoring Can Be Improved by Emitting More EventsPrimex Finance · Quantstamp · 19 Oct 2023Fixed

In order to validate the proper deployment and initialization of the contracts, it is a good practice to emit events. Also, any important state transitions can be logged, which is beneficial for monitoring the contract, and also tracking eventual bugs or hacks. Below we present a non-exhaustive list of events that could be emitted to improve application management: 1. `Bucket.setReserveRate()` 1. `Bucket.setWithdrawalFee()` 1. `Bucket.setInterestRateStrategy()` 1. `PositionManager.setKeeperRewardDistributor()` 1. `PositionManager.setMinPositionSize()` 1. `PositionManager.setOracleTolerableLimitMultiplier()` 1. `Reserve.setTransferRestrictions()` 1. `PrimexDNS.setConditionalManager()` 1. `PrimexDNS.setPMX()` 1. `PrimexDNS.setProtocolRate` 1. `PrimexDNS.setProtocolRateInPMX` 1. `PrimexDNS.setAavePool()` 1. `PrimexDNS.activateBucket()` 1. `PrimexDNS.freezeBucket()` 1. `PrimexDNS.setDexAdapter()` 1. `PrimexDNS.activateDEX()` 1. `PrimexDNS.freezeDEX()` 1. `PriceOracle.updatePriceFeed()` 1. `PriceOracle.updateVolatilityFeed()` 1. `PriceOracle.setGasPriceFeed()` 1. `KeeperRewardDistributor.setDefaultMaxGasPrice()` 1. `KeeperRewardDistributor.setOracleGasPriceTolerance()` 1. `KeeperRewardDistributor.setMaxGasAmount` 1. `KeeperRewardDistributor.setPmxPartInReward()` 1. `KeeperRewardDistributor.setNativePartInReward()` 1. `KeeperRewardDistributor.setPositionSizeCoefficients()` 1. `KeeperRewardDistributor.setAdditionalGas()` 1. `SpotTradingRewardDistributor.decreaseRewardPerPeriod()` 1. `SpotTradingRewardDistributor.setRewardPerPeriod()` 1. `SpotTradingRewardDistributor.topUpAvailablePmxBalance()` 1. `SpotTradingRewardDistributor.withdrawPmx()` 1. `Treasury.setMaxSpendingLimit()` 1. `Treasury.decreaseLimits()` 1. `ReferralProgram.setReferrals()` 1. `DexAdapter.setQuoter()` 1. `DexAdapter.setDexType()` 1. `Redeemer.changeRate()` 1. `Redeemer.adminClaimEarlyTokens()` 1. `Redeemer.adminClaimRegularTokens()` 1. `SwapManager.setSwapRate()` 1. `SwapManager.setSwapRateInPmx()` 1. `PMXBonusNFT.setExecutor()` 1. `PMXBonusNFT.blockNFT()` 1. `PMXBonusNFT.unblockNFT()`

Open the report
LowDuplications and Inconsistencies in Referrers List Due to Absence of Validations in `setReferrers()` and `setReferrals()` FunctionsPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The `setReferrers()` function permits the configuration of multiple referrers. However, it currently does not verify the existence of a referrer in the `referrers` list prior to the addition of a new referrer. This can result in the same referrer address being duplicated in the `referrers` list. Furthermore, the `setReferrals()` function neglects to validate the existence of referrals or referrers before updating the `referralsOf` and `referrerOf` mappings. It also fails to add new referrers to the `referrers` list. This can lead to inconsistencies in the tracking of referrers and referrals.

Open the report
LowInconsistency and Validation Gaps in Treasury Spending Limit ManagementPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The current structure of the `Treasury.setMaxSpendingLimit()` and `Treasury.decreaseLimits()` functions, crucial for managing the treasury spending, exhibit inconsistencies and lack the necessary validation checks. The `setMaxSpendingLimit()` function allows the `Treasury` to add a new spender address with spending limits or update existing limits. This function does not validate the `_newSpendingLimits` used and but the function is locked behind a `MEDIUM_TIMELOCK_ADMIN`. Although the function name implies modifying the maximum spending limits for a spender, the implementation allows any data in `SpendingInfo.limits` to be updated for new and existing spenders. The `Treasury.decreaseLimits()` function allows `Treasury` to update the spending limits of existing spenders. This function validates that the new limits are decreased and time durations are increased. However, the function does not validate the existence of the spender address. This lack of validation could allow for unintentional increases in the time duration for non-existent spenders in the `spenders` mapping. The following input validations are recommended, but not limited to: 1. When adding or updating spending limits for a spender address, 1. `maxTotalAmount` should exceed zero, 2. `maxAmountPerTransfer` should exceed zero, 3. `maxPercentPerTransfer` should be less than `WAD` or reasonably bounded, 4. `minTimeBetweenTransfers` should exceed zero or reasonably bounded, 5. `maxAmountDuringTimeFrame` should exceed zero or reasonably bounded. 2. When decreasing spending limits for a spender address, 1. `isSpenderExist` should be validated,

Open the report
LowInconsistency in Pause Management when Opening PositionPrimex Finance · Quantstamp · 19 Oct 2023Fixed

If `PositionManager` contract is paused, it is still possible to open new positions via the `LimitOrderManager` contract through the `LimitOrderManager.openPositionByOrder()` function. However, this can be mitigated once the `LimitOrderManager` contract is paused as well.

Open the report
Show 10 more
LowIneffective Conditions Can Be Attached to OrdersPrimex Finance · Quantstamp · 19 Oct 2023Fixed

An order for a swap does not require, and should not have, a close condition attached to it. This is because a swap order does not open a position, so there is no need for a way to close it. The `LimitOrderLibrary.setCloseConditions()` function includes a check on `_order.shouldOpenPosition` to prevent this situation. However, it is important to note that this check can be bypassed if a user changes a spot trade order to a swap order using the `LimitOrder.updateOrder()` function. In such cases, the originally attached closing condition will remain attached, potentially leading to unexpected behavior.

Open the report
LowInfinite Token ApprovalPrimex Finance · Quantstamp · 19 Oct 2023Fixed

Several contracts approves token infinitely for another contract. While we do not find any exploit from this, and the risk is mitigated as it is only approved to another contract within the protocol, it increase the risk surface as a vulnerability can cause the token on the approved contracts to be all taken away. We found the pattern in the following places: 1. `ActivityRewardDistributor.initialize()` 2. `Bucket.initialize()` 3. `LiquidityMiningRewardDistributor.initialize()` 4. `SpotTradingRewardDistributor.initialize()`

Open the report
LowLoss of Points Due to Insufficient PrecisionPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The `getLenderInfo()` function calculates the percentage of funds a lender holds with the formula: ``` (lenderInfo.points * 100) / buckets[_bucketName].totalPoints; ``` This calculation can lead to a loss of precision. For example, a lender with 1 point in a 1000-point bucket would be represented as holding 0% rather than the correct 0.1%. As the total points accumulate in `totalPoints`, the inaccuracy magnifies.

Open the report
LowMissing `GUARDIAN_ADMIN` rolePrimex Finance · Quantstamp · 19 Oct 2023Fixed

During `Registry` deployment, if `guardianAddress` is undefined from the `addresses.json` configuration, the role `GUARDIAN_ADMIN` will not be added to the `Registry`. The `guardianAddress` is not specified in the configuration. The guardian role is needed in PrimexTimelock to pause and unpause functionalities.

Open the report
LowMissing Access Control in `PToken.setBucket()`Primex Finance · Quantstamp · 19 Oct 2023Fixed

Any user can call the `PToken.setBucket()` function and change the bucket corresponding to the `PToken` as long as they chose an address conforming to a valid PrimeX bucket interface. However, once this bucket is set it cannot be changed. Thus, this attack has a very small window of opportunity but can be disruptive if successfully executed. Additionally, this issue is mitigated in the `BucketsFactory.createBucket()` function. Essentially, the pToken is deployed/created, and `setBucket()` is immediately called, ensuring that this scenario would not occur in practice due to their deployment mechanism. Nonetheless, if the `PToken` contract is ever used independently, this issue should be a concern.

Open the report
LowMissing Authorization Check for `PTokensFactory.createPToken()`Primex Finance · Quantstamp · 19 Oct 2023Fixed

The `PTokensFactory.createPToken()` function seems only needed for the `BucketFactory.createBucket()` function. However, there is no authorization check for the `PTokensFactory.createPToken()` function. In other words, anyone can call the function and deploy a new pToken. We do not find any exploit due to this, but if any of the off-chain components are to listen to the `PTokenCreated` event, they might be wrongly notified and have unexpected behavior.

Open the report
LowProposers Incorrectly Set to ExecutorsPrimex Finance · Quantstamp · 19 Oct 2023Fixed

During the deployment process of `PrimexTimelock`, the proposers are incorrectly parsed from executors. Therefore the proposers are set as the executors regardless of the proposers provided in the task parameters.

Open the report
LowPTokens Can Be Transfered to Blacklisted AddressPrimex Finance · Quantstamp · 19 Oct 2023Fixed

In the `transfer()` function of `PToken`, there is no check to ensure that the recipient is not blacklisted. In accordance with these checks in other places, blacklisted addresses should not be able to receive any pTokens. **Note:** We discussed this with the team during the audit, and the team has clarified that this is the intended behavior.

Open the report
LowSpot Trade or Swap Order with the `depositedAsset` Being the Same as `positionAsset`Primex Finance · Quantstamp · 19 Oct 2023Fixed

An order for a swap or spot trade should not have the `depositedAsset` being the same as the `positionAsset`, as there is no need for them to be identical. The `LimitOrderLibrary.createLimitOrder()` function includes validation on the assets when `vars.isSpot` to prevent this scenario. However, it is important to note that when using the `LimitOrderManager.updateOrder()` function, one can change the `depositedAsset` without the same validation. As a result, it is possible to create a spot trade or swap order with the `depositedAsset` being the same as the `positionAsset`, which may lead to unexpected behavior or unnecessary operations.

Open the report
LowUnable to Clean Up Legacy OrdersPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The `LimitOrderManager` contract currently only allows the trader to cancel an order with the `cancelLimitOrder()` function, unless the bucket has been delisted. However, if the `deadline` of the order has passed, it may be kept in the contract indefinitely unless the trader actively cancels it. These legacy orders will be stored in the contract, including arrays such as `traderOrderIds` and `bucketOrderIds`. When there are too many legacy orders, it can potentially block certain features, such as the `getBucketOrders()` function, from executing due to running out of gas. Additionally, directly accessing the public array may also raise gas concerns, although this can be configurable through the node (refer to the gas limit on `eth_call` discussion [here](https://community.infura.io/t/gas-limit-on-eth-call/1115)).

Open the report
Show 5 more
LowUnclear Whether Native Currency Should Be Supported for SwappingPrimex Finance · Quantstamp · 19 Oct 2023Fixed

When swapping from the wallet through the `swap()` function, the input token `params.tokenA` can be `NATIVE_CURRENCY`. The current implementation does not accept `NATIVE_CURRENCY` when swapping directly from the wallet through the `TokenTransfersLibrary.doTransferFromTo()` function. However, the implementation accepts `NATIVE_CURRENCY` when using funds from the `traderBalanceVault.lockAsset()`. Nonetheless, the call to `PrimexPricingLibrary.multiSwap()` will eventually fail. However, it might be great to clarify whether native token should be supported or not and add the corresponding validation.

Open the report
LowUninitialized Implementation ContractPrimex Finance · Quantstamp · 19 Oct 2023Fixed

Leaving an implementation contract uninitialized poses a security risk. An uninitialized implementation contract can be exploited by attackers, potentially compromising the associated proxy. To mitigate this risk, it is recommended to invoke the `_disableInitializers()` function in the constructor during deployment (see: [OpenZeppelin doc](https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#initializing_the_implementation_contract)). This action will automatically lock the implementation contract, preventing any unauthorized usage. The following is the list of impacted contracts found with the `grep` command: ```sh ▶ grep -rl --include="*.sol" --exclude="I*.sol" --exclude-dir="mocks" "initializer" . ./SpotTradingRewardDistributor/SpotTradingRewardDistributor.sol ./TraderBalanceVault/TraderBalanceVault.sol ./PMXBonusNFT/PMXBonusNFT.sol ./ActivityRewardDistributor/ActivityRewardDistributor.sol ./PToken/PToken.sol ./PriceOracle/PriceOracle.sol ./WhiteBlackList/WhiteBlackListReferral/WhiteBlackListReferral.sol ./WhiteBlackList/WhiteBlackList/WhiteBlackList.sol ./LimitOrderManager/LimitOrderManager.sol ./KeeperRewardDistributor/KeeperRewardDistributor.sol ./Bucket/Bucket.sol ./LiquidityMiningRewardDistributor/LiquidityMiningRewardDistributor.sol ./DebtToken/DebtToken.sol ./Reserve/Reserve.sol ./ReferralProgram/ReferralProgram.sol ./PrimexDNS/PrimexDNS.sol ./BonusExecutor/FeeDecreaser.sol ./Treasury/Treasury.sol ./PositionManager/PositionManager.sol ```

Open the report
LowUnlocked Pragma and Risk of Unsupported Opcode in the Latest Solidity VersionPrimex Finance · Quantstamp · 19 Oct 2023Fixed

Every Solidity file specifies in the header a version number of the format `pragma solidity (^)0.8.*`. The caret (`^`) before the version number implies an unlocked pragma, meaning that the compiler will use the specified version _and above_, hence the term "unlocked". Note that Solidity `0.8.20` might only work on Ethereum Mainnet at this moment as it introduced a new OP Code that other EVM-compatible chains might not support yet (see: [this article](https://medium.com/coinmonks/push0-opcode-a-significant-update-in-the-latest-solidity-version-0-8-20-ea028668028a) for more information).

Open the report
LowUnresolved `TODO`Primex Finance · Quantstamp · 19 Oct 2023Fixed

The `PrimexPricingLibrary.getLiquidiationPriceByOrder()` function has an unresolved `TODO` stating: "This function is only used in tests. Maybe it can be removed."

Open the report
LowUsing Deprecated FunctionPrimex Finance · Quantstamp · 19 Oct 2023Fixed

The function `AccessControl._setupRole()` has been [deprecated](https://docs.openzeppelin.com/contracts/4.x/api/access#AccessControl-_setupRole-bytes32-address-) in favor of `AccessControl._grantRole()`, which performs the same operations.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="primex-finance"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us