Resonance Security reviewed Primex Finance on 7 Dec 2023: 17 findings, 1 critical; 13 marked fixed, 4 open.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 1 |
| High | 1 | 0 | 0 |
| Medium | 2 | 0 | 4 |
| Low | 1 | 0 | 8 |
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.
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.
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.
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.
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.
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.
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.
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.
The constructor does not validate whether the argument _bucketImplementation is a valid contract that supports the interface IBucket.
The initialize() function does not validate whether the argument LMparams.liquidityMiningRewardDistributor is a valid contract that supports the interface ILiquidityMiningRewardDistributor.
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.
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.
The inclusion of unlimited approval in contracts increase potential attack surface.
The report names a repository or files. Open the report to see its scope.
18 projects reviewed · 25 reports · latest Aug 2025
See Resonance Security’s auditsSomething 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