Primex Finance

Resonance Security401 addresses on Ethereum, Polygon (POS) and Arbitrum

Resonance Security reviewed Primex Finance on 7 Dec 2023: 17 findings, 1 critical; 13 marked fixed, 4 open.

1 critical finding, fixed
Open the reportOpen Primex Finance’s security record
Report stored on IPFS. Content hash Qmat2FzynN5HZLT79ECUTPvSxUCfeynuMtjcoY69eEfXfy

Trustblock does not review code.

Findings17

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

SeverityOpenAcknowledgedFixed
Critical001
High100
Medium204
Low108
CriticalPossible To Drain Treasury On closePositionByCondition()Fixed

The function closePositionByCondition() is typically used by keepers to perform the upkeep of open positions that should be closed for a variety of reasons. This function was not designed to be used by traders that simply want to close a position without any condition. For that, the function closePosition() should be used.However, the function closePositionByCondition() does not validate who is the caller, or the provided close reason. Therefore, it is possible for a trader to also use this function to close an active position without any condition. Despite the logic of the code being very similar between the two functions, since the function closePositionByCondition() was meant to be used by keepers, the keepers obtain rewards for performing the necessary upkeep.Since a trader can also use the function closePositionByCondition() at will, there is a greater incentive for them to use it over closePosition(), since they will earn rewards for simply closing their active positions.The rewards are claimable through the treasury, and with the possibility of this fact occurring over and over again by every trader, it is possible to drain the treasury of all its PMX and native tokens, therefore gaining an unfair advantage over other users not aware of this issue.

MediumMissing Check For Initial Parameters In Bucket.solFixed

The Buckets contract is responsible for storing the liquidity provided by Lenders. Traders have the option to borrow this liquidity when they open margin positions. The deployment of the Bucket contract can only be done through the BucketFactory by MEDIUM_TIMELOCK_ADMIN.During the initialization of the contract, most parameters are properly validated. However, there is a missing validation for the withdrawalFeeRate , feeBuffer and reserveRate As a result, there is a possibility that the bucket could be initialized with unfavourable fees for users either by mistake or by a malicious administrator.

MediumPossible To Activate Bucket Without Adding ItFixed

The function activateBucket() allows the activation of a bucket without having been added with addBucket() in the first place. The validation on the activateBucket() function is based solely on the currentStatus of the bucket, which by default is Inactive for buckets that have not been added yet. This effectively means that a less privileged admin SMALL_TIMELOCK_ADMIN may effectively obtain the same result of adding and activating a bucket by simply calling the function activateBucket().Having a bucket activated with a corresponding name but not with a corresponding address can result in multiple behaviors across the various function calls throughout the protocol.The intended workflow should be having the function addBucket() be executed first by the BIG_TIMELOCK_ADMIN, and then activate and freeze the bucket at will with the respective functions.

MediumPossible To Frontrun setBucket()Fixed

The function setBucket() is meant to be called right after the creation of a bucket. While the creation of buckets is handled by the contract BucketsFactory.sol, it is possible to create a bucket without using the factory. In these cases, the call to the setBucket() function is not guaranteed to happen on the same transaction. As such, it is possible for malicious actors to call such function right after the creation of a bucket and render the respective PToken and DebtToken useless by assigning them a malicious bucket.

MediumRewards Can Be Claimed When LiquidityMiningRewardDistributor Is PausedFixed

The function claimReward() does not allow rewards to be claimed when the contract is paused, due to the usage of the whenNotPaused modifier. However, this is not the only function that is able to claim liquidity mining rewards. The function reinvest(), which is callable by buckets and can be triggered by the average user, can be used to claim liquidity mining rewards under certain conditions. When the LiquidityMiningRewardDistributor contract is paused, no rewards should be claimed one way or another, assuming that an emergency is in place.

LowConditions On supportsInterface() Can Be Switched To Save GasFixed

Most supportsInterface() functions across the Primex protocol validate the base-most interfaceId. Due to both the inheritance nature of the Solidity language, and the short-circuiting capability of its logical operators, testing the base-most interface first is not optimal to save gas.

LowDifferent Versions Of canBeFilled() Lead To Undefined BehaviourFixed

The function canBeFilled() implements several versions used throughout different contracts of the Primex protocol. Using different versions of code for the same intended behaviour may lead to unexpected and/or inconsistent results.

LowMissing Restrictions Validation On setFeeRestrictions()Fixed

The function setFeeRestrictions() on PrimexDNS does not validate whether the given input parameters, minProtocolFee and maxProtocolFee, are correct in regards to each other, i.e., minProtocolFee should always be less than maxProtocolFee. These values are used in the protocol fees calculations in the function calculateProtocolFee(), and if set incorrectly, either maliciously or unknowingly, may cause permanent loss of funds to the users or the protocol itself.It should be noted that the severity of this finding is decreased due to the fact that only users with the BIG_TIMELOCK_ADMIN role may execute the setFeeRestrictions() function.

LowMissing supportsInterface() Validation Of _bucketImplementationFixed

The constructor does not validate whether the argument _bucketImplementation is a valid contract that supports the interface IBucket.

LowMissing supportsInterface() Validation Of liquidityMiningRewardDistributorFixed

The initialize() function does not validate whether the argument LMparams.liquidityMiningRewardDistributor is a valid contract that supports the interface ILiquidityMiningRewardDistributor.

Show 3 more
LowPossible To Use Deposit Owned By Other Users On depositPrologantion()Fixed

The function depositPrologantion() does not validate whether the _depositId belongs to the msg.sender. As such, a user can call this function erroneously and trigger a prolongation of his own deposit by an incorrect and/or unexpected amount.

LowUnnecessary Validation Of _params On createBucket()Fixed

The function createBucket() correctly validates _params.positionManager and _params.reserve. However, this validation is unnecessary since the same validation is being made inside the contract Bucket, therefore leading to a duplication of code and the increase of gas costs.

LowUsage Of Unlimited ApproveFixed

The inclusion of unlimited approval in contracts increase potential attack surface.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Part of Primex Finance’s security record

Primex Finance
Audits5 audits by 2 firmsLast audit Oct 2024, by Resonance Security.
Critical findingsNo open critical findingsAcross the 5 reports, 2 critical findings were reported. Each is marked fixed by the firm that reported it.
Open Primex Finance’s security record

Security firm

Resonance Security

18 projects reviewed · 25 reports · latest Aug 2025

See Resonance Security’s audits

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