Synthetix engaged Guardian to review the security of its BFP market, which aims to allow stablecoin issuers and other DeFi protocols to create delta neutral perpetuals, utilizing ETH and ETH LSTs as collateral. From the 25th of March to the 18th of April, a team of 7 auditors reviewed the source code in scope.
- Published
- Review window
- March 25 to April 18, 2024
- Language
- Solidity
- Chains
- Ethereum
- Sector
- Perpetuals
- 9 Critical
- 5 High
- 21 Medium
- 24 Low
- 0 Informational
Scope
Overview
Synthetix engaged Guardian to review the security of its BFP market, which aims to allow stablecoin issuers and other DeFi protocols to create delta neutral perpetuals, utilizing ETH and ETH LSTs as collateral. From the 25th of March to the 18th of April, a team of 7 auditors reviewed the source code in scope.
Findings 59
-
C-01 Critical User Debt Overwritten When Cancelling Orders Logical Error Resolved
Description
Proof of concept: PoC
When canceling an order with the
cancelOrderfunction the keeper fee is directly accounted withupdateAccountDebtAndCollateral, however if the user has no sUSD collateralupdateAccountDebtAndCollateralreassigns the account’s debt to the keeper fee, therefore overwriting any existing debt for the account.Recommendation
Consider Including the accounts existing debt when charging the fee with the
updateAccountDebtAndCollateralfunction, otherwise create a dedicated function to charge the keeper fee from the user’s margin.Resolution
Synthetix Team: The issue was resolved in PR#2079.
-
C-02 Critical Splitting Positions Allows fromAccount To Go Below IM Logical Error Resolved
Description
Proof of concept: PoC
In the
splitAccountfunction thetoAccountwhich is created from a portion of thefromAccountis validated to meet the minimum initial margin requirement, however thefromAccountis not validated to still uphold the initial margin requirement after the split.As a result it is possible for the
fromAccountto circumvent the minimuminitialMarginand create positions that are prone to insolvent liquidations and create bad debt. Additionally it is possible for a malicious actor to liquidate their small position that is left behind this way and wind up with a net profit from the flag and liquidation fee.Recommendation
Validate that the
fromAccountis still above the initial margin requirement after the split occurs.Resolution
Synthetix Team: The issue was resolved in PR#2096.
-
C-03 Critical reportedDebt Incorrectly Calculates Funding Logical Error Resolved
Description
The
reportedDebtfunction aims to report the net funding fees which have yet to be paid to or from traders, among other things.Following from the documentation in
PerpMarket.sol:/// debtCorrection = positions.sum(p.collateralUsd - p.size * (p.entryPrice + p.entryFunding)) /// marketDebt = market.skew * (price + nextFundingEntry) + debtCorrection
reportedDebt aims to compute the outstanding funding amount via
market.skew * nextFundingEntry- positions.sum(p.size * p.entryFunding)
However in the implementation of the
reportedDebtfunction, theunrecordedFundingis used as thenextFundingEntryin the equation above. Instead thecurrentFundingAccruedComputed +unrecordedFundingought to be used as thenextFundingEntry. This clearly invalidates the computation of the outstanding funding amount as often the individualp.entryFundingvalues will be larger than theunrecordedFundingportion.Recommendation
Use
currentFundingAccruedComputed + unrecordedFundinginstead of justunrecordedFundingwhen computing the outstanding funding fees of the market.Resolution
Synthetix Team: The issue was resolved in PR#2091.
-
C-04 Critical Market Size Increased Indefinitely With Merge Accounts Logical Error Resolved
Description
Proof of concept: PoC
Function
mergeAccountscan merge any 2 accounts, adding their collateral and combining their positions. If the positions are opposite to each other the accounts will be merged with a reduced position size, however the market size will remain the same. This enables attacker to increase the size of the market as much as they want, while paying only order fees.The impact from this is complex as size is taken into quite a few calculations and checks:
- Increasing size increases utilization lowering PnL for other users.
- Increasing size will reach max OI, which will prevent users from opening trades.
- Utilizing 100% of the market will cause the LPs to be locked, as
delegateCollateralwill revert,
which leads to
minimumCreditchecking if we are over the limit.delegateCollateral->_verifyNotCapacityLocked->findMarketWithCapacityLocked->isCapacityLocked->getLockedCreditCapacity->minimumCreditNote that this doesn't need to be "exploited", as it will occur naturally with use of the protocol.
Recommendation
Check if the two positions are different and if true update the market size.
Resolution
Synthetix Team: The issue was resolved in PR#2095.
-
C-05 Critical Negative Price Impact Bypassed For Consistent Profits Logical Error Resolved
Description
Proof of concept: PoC
Users can manipulate the skew to gain profit by making large orders and then merging them to use the fill price penalty as a way to gain a profit. A position is opened with the fill price, where depending on the skew the fill price can deviate from the actual price. That deviation is not realized when opening the position, but left as unrealized PnL.
When merging 2 positions
mergeAccountscalculates the margin only for thetoaddress, and assumes thefromhas no outstanding PnL. Then it adds its collateral and debt and sets the price to the current oracle price.The above enables us to: 1. Have a small position - 10 USD. 2. Make a new bigger position - 100k USD, using 1% of the skew. 3. Use the hooks and merge this new position (deleting the unrealized loss from the fill price discount). 4. Our new position is at the current oracle price, but the skew is still there. 5. Close the position (lowering the skew) to claim the fill price incentive. With the above example any user with enough capital can gain constant profits from the market, while only paying order and keeper fees. Furthermore, the disincentive to imbalance longs and shorts is bypassed.
Recommendation
Calculate any outstanding losses for the
fromPositionbased on the newly assignedfromPosition.entryPriceand account for these in the newly mergedtoposition.Resolution
Synthetix Team: The issue was resolved in PR#2112.
-
C-06 Critical Users Can Withdraw Their Collateral Without Paying Debt Logical Error Resolved
Description
Proof of concept: PoC
Users without sUSD deposited as collateral will accumulate losses in
debtUsd. This happens inupdateAccountDebtAndCollateral. In the scenario where a trader closes a position, and realizes a loss, there will be some collateral left and a pendingdebtUsdto pay.The issue arises when a user tries to withdraw the deposited collateral without any open position. The
validatePositionPostWithdrawwill fail to do its job, as theposition.sizeis 0, leading toisLiquidateableto return false andimto be 0. Therefore, the protocol will allow users to withdraw all their collateral, even with a pending debt to pay.Recommendation
Validate the case where there is no open position, checking if the
discountedCollateralUsd <debtUsd.Resolution
Synthetix Team: The issue was resolved in PR#2100.
-
C-07 Critical LPs Can Claim Rewards While Avoiding Debt Logical Error Resolved
Description
Proof of concept: PoC
LP’s which delegated their collateral can exit the pools between BFP flag and liquidate. On flag all of the collateral is distributed instantly, while keeping
totalDebtthe same (non-sUSD collateral) since the position still exists. However when liquidatingtotalDebtwill change effectively assigning debt to the LP providers.This allows LPs who have already staked for some time (above
requiredMinDelegationTime) to flag a large position, claim the rewards in thepayoutTokenand then to decrease their exposure withdelegateCollateralto 0, skipping the debt exposure when the position gets liquidated.Consider the following scenario: 1) Bob and Alice both delegated equal amounts of collateral. 2) 10 ETH is distributed upon liquidatable position being flagged. 3) Alice claims her 5 ETH and removes her delegation. 4) The position is liquidated. 5) The debt is solely distributed to Bob’s LP position, so the account’s debt is increased. 6) Alice can re-delegate her collateral and all of the distributed debt is still on Bob’s position.
Ultimately, Alice was able to avoid the socialization of debt while still gaining the same amount of rewards from the
RewardDistributor.Recommendation
This issue ultimately arises from awarding LPs with liquidated collateral before the liquidated position has been cleared from the
reportedDebt. Consider avoiding the distribution of all collateral upon flagging. Instead, distribute collateral uponliquidatePosition, proportional with the amount of size being liquidated or only once the position has been entirely liquidated.Resolution
Synthetix Team: The introduction of asynchronous delegation will resolve this.
-
C-08 Critical Collateral Modification Abused To Levy LP Fees Griefing Resolved
Description
When depositing and withdrawing sUSD collateral, a fee is accrued in the
depositMarketUsdandwithdrawMarketUsdfunctions in theMarketManagerModule. For example, in a deposit, the fee is subtracted from the amount and added tocreditCapacityD18:market.creditCapacityD18 += (amount - feeAmount)However, these fees are handled only inside the Synthetix V3 system, whereas the BFP market adds the entire deposited amount to the trader balance, neglecting the fees:
accountMargin.collaterals[synthMarketId] += absAmountDeltaThis way the trader does not experience the fees levied from their collateral deposit and withdrawal actions, rather the liquidity providers and potentially traders with unrealized profits are affected. This can be exploited to manipulate
creditCapacityD18andnetIssuanceD18by continuously callingmodifyCollateralin order to increasenetIssuanceD18and decreasecreditCapacityD18.Anyone can batch deposit-withdraw calls in one TX using Morpho flashloans (0% fees) in order to maximize the impact with minimal capital requirements.
Increasing
netIssuanceD18will report more debt for the LPs than actually exists and lower their profits. DecreasingcreditCapacityD18could lead to traders getting stuck inside the BFP aswithdrawMarketUsdreverts insidegetWithdrawableMarketUsdandwithdrawMarketCollateralcan revert withnewWithdrawableMarketUsd < 0.Recommendation
Account for the fees being charged in the BFP market, reducing the amount of collateral traders are credited with upon deposits by the fee amount and reducing the amount of collateral traders ultimately redeem from the Synthetix V3 system by the fees.
Resolution
Synthetix Team: Fees will be removed with SIP-365.
-
C-09 Critical debtCorrection Not Updated Upon Realizing To Account Margin Logical Error Resolved
Description
Proof of concept: PoC
In the
mergeAccountsfunction the outstanding PnL for the to account is realized, however thedebtCorrectionis not updated to account for this realized PnL.As a result every merge where the to account has outstanding PnL will result in a double counting of that PnL in the
debtCorrection, as the skew still includes the old position and the account has now materialized it’s gain or loss into it’s collateral.Recommendation
Update the
debtCorrectionfor the settlement of the to account’s PnL.Resolution
Synthetix Team: The issue was resolved in PR#2133.
-
H-01 High minimumCredit Inaccurately Restricts Backing For Shorts Logical Error Acknowledged
Description
The
minimumCreditfunction defines an amount which the available credit capacity cannot go below depending on the size of the market and the current index price. However this calculation perturbs the amount that ought to be reserved for shorts.For example:
- A market has 10 index tokens as short open interest.
- The market size is 10.
- The price of the index token doubles.
- The minimum credit is now a ratio based on the 10 tokens of short open interest, now valued at
twice the price.
This inaccurately represents the amount of backing liquidity that ought to be reserved for the market as shorts can only ever gain up to their cost-basis and when the price of the index token rises, shorts are in a loss.
Recommendation
Account for the long and short open interest separately when computing how much backing liquidity ought to be reserved.
For example, the GMX V2 system reserves liquidity based upon
openInterestInTokens * pricefor longs andopenInterest(position cost) for shorts.Resolution
Synthetix Team: Acknowledged.
-
H-02 High Liquidation Computes Utilization Before Updating Market Size Logical Error Resolved
Description
During
liquidatePosition,updateMarketPreLiquidationis called to perform pre-steps and validation, including the recomputation of utilization.market.recomputeUtilizationis incorrectly called beforemarket.sizeis reduced by the liquidation size. The new utilization rate should be calculated with the new market size, similar tosettleOrderinOrderModule.sol.By calling
recomputeUtilizationbefore updating size, the liquidation leaves utilization rate unchanged when it should have reduced it, affecting all remaining traders.Assume the utilization rate was very high, and a large position was just liquidated. This should in effect bring down utilization rate and improve the margins of all other traders. However, due to this error, the margins of all other traders remain unchanged, which could then lead to unfair liquidations.
Recommendation
Call
recomputeUtilizationafter market size and skew are updated in theupdateMarketPreLiquidationfunction.Resolution
Synthetix Team: The issue was resolved in PR#2101.
-
H-03 High sUSD Drained From Vault When Liquidating Margin Only Gaming Resolved
Description
Proof of concept: PoC
In the
isMarginLiquidatablefunction, accounts are determined to be liquidatable when they have adiscountedMarginUsdof 0. However this puts the protocol at risk of taking on bad debt as there is no requirement that the margin is able to cover liquidator fees as well as potential instantaneous collateral price decreases.Furthermore, an issue arises with low price collateral assets. An attacker can deposit a very small amount of collateral (1 wei), and the validation for
isMarginLiquidatablewill return true, as thediscountedCollateralUsdwill be 0 when collateral price is below 1e18:discountedCollateralUsd += available.mulDecimal(discountedCollateralPrice);The attacker will then liquidate the account and earn keeper fees, withdrawing sUSD from the V3 pool.
Recommendation
Change the definition of the
isMarginLiquidatablefunction such that positions will be considered liquidatable by margin only if theirdiscountedMarginUsdcannot cover liquidation keeper rewards, optionally as well as a safety bound for potential downward collateral price gaps.Additionally, validate that positions hold enough collateral so that they are not liquidatable by margin only upon any action that would modify their position’s collateral.
Resolution
Synthetix Team: The issue was resolved in PR#2116.
-
H-04 High minimumCredit Backed By Trader sUSD Collateral Validation Resolved
Description
In the BFP market, sUSD collateral is deposited by traders and counted towards the
creditCapacityof the market. ThiscreditCapacityis ultimately compared against theminimumCreditto validate that there is sufficient backing liquidity to safely operate the market.However trader collateral should not be included in this validation as it cannot be locked in the event that the market's
isCapacityLockedvalidation fails, failing to safely back the market with a minimum amount of liquidity and adequately back trader’s positions. Additionally trader’s profits which are settled to sUSD ought to always be able to be covered by backing liquidity, however this amount is not accounted for in theminimumCredit.Recommendation
Consider accounting for the trader’s deposited sUSD collateral when reporting the
minimumCreditfor the BFP market such that thecreditCapacitymust include the desired minimum amount in addition to thecreditCapacitygenerated by the trader’s sUSD collateral.Since the additional sUSD
depositedCollateralwill include all settled profits and only some of the realized losses which can be covered directly by sUSD collateral, it may also be pertinent to reduce theminimumCreditby the net debt losses for all accounts. However the most conservative validation would be to count only thedepositedColalteralvalue for sUSD.Otherwise consider a larger refactor of the way trader sUSD collateral is handled, perhaps restricting it’s withdrawal when the
minimumCreditis breached or removing it from having an effect on thecreditCapacityentirely.Resolution
Synthetix Team: The issue was resolved in PR#2134.
-
H-05 High minimumCredit Reserves Not Validated Upon Position Increase Validation Resolved
Description
Traders are allowed to open and settle orders even when the existing market positions cannot be adequately supported by the liquidity backing the BFP market. Even if the existing
minimumCreditis too large for the backingcreditCapacity, traders can continue to increase the market size and therefore increase the uncovered gap between theminimumCreditand the lackingcreditCapacity.As a result the BFP market can easily become insolvent in the event that traders continue to open positions without consideration for the backing liquidity. This leads to a market state where sUSD collateral withdrawals are DoS'd as well as any settlement for positions in a profit.
Recommendation
Validate that orders that would create new positions or increase existing positions do not invalidate the
minimumCreditvalidation for the market.Resolution
Synthetix Team: The issue was resolved in PR#2128.
-
M-01 Medium Fill Price Causes Funding And Utilization Discrepancy Logical Error Resolved
Description
In the
Position.validateTradefunction theparams.fillPriceis used to compute themarginValues, which include the funding and utilization fees based upon that price. However the funding and utilization fees should not be based upon thefillPrice, as this price includes a premium/discount according to how the trade affects the market skew.This will lead to shorts paying less fees when they push the skew increasingly short, or longs paying more fees when they push the skew increasingly long.
Additionally, when the
currentFundingAccruedComputedandcurrentUtilizationAccruedComputedis accounted for the market with therecomputeUtilizationandrecomputeFundingfunctions these values are based upon thepythPrice. As a result traders will experience a discrepancy in the amount of funding and utilization fees paid to the market’s recorded funding and utilization accrued values.Recommendation
Consider using the
params.oraclePricespecifically for the funding and utilization fee calculations when computing themarginValuesin thePosition.validateTradefunction.Resolution
Synthetix Team: The issue was resolved in commit 7c5d2fa.
-
M-02 Medium Full Utilization DoS DoS Resolved
Description
When computing the current utilization in the
PerpMarket.getUtilizationfunction if the backing liquidity is over-utilized, e.g.delegatedCollateralValueUsd < 0, then a utilization of 100% is returned.However when the backing liquidity is exactly 100% utilized, e.g.
delegatedCollateralValueUsd == 0then the function will attempt to divide thelockedCollateralUsdby thedelegatedCollateralValueUsd, resulting in a divide by 0 panic revert.However, the risk of DoS is unlikely as the utilization is unlikely to be able to get to exactly 100%.
Recommendation
Modify the
ifcondition on line 191 such that thePerpMarket.getUtilizationfunction early returns ifdelegatedCollateralValueUsd <= 0.Resolution
Synthetix Team: The issue was resolved in PR#2085.
-
M-03 Medium Wrong Feature Flag Used For Account Split Validation Resolved
Description
In the
splitAccountfunction the feature flag validation is performed with theFlags.MERGE_ACCOUNTfeature, meanwhile theFlags.SPLIT_ACCOUNTfeature ought to be used. This can allow an account which does not have permission to split their account to do so anyway.Recommendation
Validate the feature flag based upon the
Flags.SPLIT_ACCOUNTfeature in thesplitAccountfunction.Resolution
Synthetix Team: The issue was resolved in PR#2084.
-
M-04 Medium flagReward Incorrectly Based On marginUsd Logical Error Resolved
Description
In the
validateNextPositionEnoughMarginfunction the Maintenance Margin is calculated through thegetLiquidationMarginUsdfunction. However the invocation wrongly passes in thenextMarginUsdto compute theflagRewardwhen it should be passing incollateralUsd.The
flagPositionfunction computes theflagRewardbased upon thecollateralUsdof the position, therefore usingnextMarginUsdto compute theflagRewardinaccurately accounts for the amount in the liquidation check.Recommendation
Provide the
collateralUsdas the second to last parameter when invoking thegetLiquidationMarginUsdfunction within thevalidateNextPositionEnoughMarginfunction.Resolution
Synthetix Team: The issue was resolved in PR#2097.
-
M-05 Medium entryPrice Used To Validate Initial Margin Logical Error Resolved
Description
In the
validateNextPositionImfunction thegetLiquidationMarginUsdfunction is used to compute the initial margin value that the position must uphold. However the initial margin value is computed based upon thenewPosition.entryPricerather than theoraclePrice.This is in direct contradiction to the price used to calculate and validate the maintenance margin for the position in the
validateNextPositionEnoughMarginfunction, which uses theoraclePrice.This leads to a discrepancy in the validation performed on a position when validating a trade. The initial margin is validated based upon the
entryPricewhile the maintenance margin is validated based upon theoraclePrice.Recommendation
In the
validateNextPositionImfunction, callgetLiquidationMarginUsdwith theoraclePriceinstead ofentryPrice.Resolution
Synthetix Team: The issue was resolved in PR#2097.
-
M-06 Medium Merging Accounts May Fail For Multicollateral Positions Logical Error Resolved
Description
Proof of concept: PoC
When merging accounts, the function executes
getMatchingMarketCollateralwhich returns the matching margin collateral equal to market. This function will return a matchingsynthMarketIdandfromAccountCollateral.If the
fromIdaccount has multiple collaterals, thegetMatchingMarketCollateralfunction will only return the last collateral that matched. This means that the merge will transfer one collateral to thetoIdaccount, and leave the other 2 in thefromIdaccount.The issue is that the merge will then transfer a portion of the collateral but the whole position size. If the last collateral that matched is the smallest one in terms of USD, then the
toPositionmight invalidate the Initial Margin check and revert.Recommendation
Transfer all collaterals with available balance to the
toIdaccount.Resolution
Synthetix Team: The issue was resolved in PR#2095.
-
M-07 Medium Small Positions Accrue Bad Debt In The System Logical Error Resolved
Description
Users can set their own
keeperFeeBufferUsdandlimitPrice, potentially forcing bad debt into the system. This is because IM and MM have minimum values as follows: IM = 2% *position.size+ fixed = 2% * p.size + 50 MM = 1% *position.size+ fixed +liqFlagReward+keeper reward= 1% * p.size + 50 +liqFlagReward+keeper rewardWhile the maximum value forkeeperFeeBufferUsdis 100 USD.Currently, it's possible to place an order with
keeperFeeBufferUsd > collateral > IM && MM, choosing the maximumkeeperFeeBufferUsdand an unrealisticlimitPrice, using it to cancel your order later and accrue bad debt ofkeeperFeeBufferUsd - collateral.Similarly users can submit orders that would decrease their position size by a trivial amount and avoid the liquidatable checks upon settlement, allowing the keeper fee to place their position in a liquidatable or even insolvent state.
Recommendation
Consider raising the
minMarginUsdsuch that it would not be possible for a keeper fee to exceed an account’s margin and cause bad debt to occur. Otherwise consider preventing orders from being created where the keeper fee would cause the account to ultimately become liquidatable.Resolution
Synthetix Team: The issue was resolved in PR#2117.
-
M-08 Medium getFillPrice And validateLiquidation Revert Due To Division By 0 Arithmetic Error Resolved
Description
If
skewScaleis set to 0, arithmetic operations which divide byskewScalewill revert. This occurs in theOrder.getFillPriceandPosition.validateLiquidationfunctions. While it is unlikely thatskewScalewill ever be set to 0, this is a possibility and is specifically handled in many areas of the codebase.Recommendation
In
getFillPriceandvalidateLiquidationhandle the scenario forskewScale == 0and avoid division by 0.Resolution
Synthetix Team: The issue was resolved in PR#2108.
-
M-09 Medium Risk Free Trade With Merge Callbacks Gaming Resolved
Description
Order execution with the
settleOrderfunction requires that thepriceUpdateDataprovided to parse thepythPriceis for the price update that satisfies the minimum and maximum times(commitmentTime + 12 seconds, commitmentTime + 60 seconds)as well as that the publish time of the price update that is sequentially previous to the provided price data took place before the minimumcommitmentTime. Therefore only prices that satisfy these constraints may be used to execute an order while it is ready and not stale.A malicious user may prevent an order from being executable in the block where the valid price data is accurate and only allow the order to go through once a significant period of time has passed and the user observes that the true current price of the index asset has moved in their favor. The order will only be executable with the outdated price, and therefore the user will realize a risk-free profit based upon how much price has diverged in the user’s favor since then.
The malicious user may prevent their order from being executable by registering a
mergeAccountshook as a callback where the user’s position as thefromAccounthas sUSD collateral in addition to the market’s index as collateral and therefore reverts. When the malicious user wishes their order to be executable, e.g. they have determined that price has moved in a direction that is favorable to them, they may remove the sUSD collateral with the payDebt function, assuming they have a pre-existing position with debt, and execute their order with the outdated price.Recommendation
Consider increasing the
orderFeepercentage that is taken to dissuade from any risk-free short term trades. Otherwise consider removing the possibility for users to control whether or not their orders are executable by way of callbacks through a try/catch wrapper.Resolution
Synthetix Team: The issue was resolved in PR#2095.
-
M-10 Medium Keeper Gas Fee Is Fixed While Execution Gas Is Not Incentives Partially resolved
Description
Every keeper operation is rewarded with a specific keeper fee, where the gas units are fixed and the fee is calculated on the spot with:
gas * gasPrice + keeperProfit. However, some operations can use much more gas than others.Example:
- Settling a normal order versus one with 3 hooks.
- Flagging a position with 1 collateral versus one with 10 collaterals.
- Liquidating a position where you don't need to loop through the window for previous liquidations
versus one where you need to loop through every block (using the
while).As a result some orders will be significantly more profitable than others, and some orders may end up being unprofitable entirely, even with a fee buffer, and as a result won't be executed.
Recommendation
Consider tracking the gas used during an execution with
gasLeftand use this amount to compute the keeper’s fee with an added profit margin.Resolution
Synthetix Team: Partially Resolved.
-
M-11 Medium Non-Discounted Collateral Used To Validate IM Logical Error Resolved
Description
In the
mergeAccountsandsplitAccountsfunctions the IM is validated against the non-discounted margin value. However to be as conservative as possible the IM ought to be validated against the discounted margin value of these accountsRecommendation
Validate the accounts in the
mergeAccountsandsplitAccountsfunctions against the IM based upon the discounted value of the margin.Resolution
Synthetix Team: The issue was resolved in PR#2112.
-
M-12 Medium Actions May Be Completed When Accounts Are Liquidatable By Margin Only Validation Resolved
Description
Throughout the BFP market actions are allowed to take place when an account involved is liquidatable by margin only, e.g. the account has a zero discounted margin value and a nonzero collateral value.
Orders can be settled and positions can be merged and split to accounts that are liquidatable by margin only. This can lead to users errantly creating orders for accounts that are about to be liquidated, and thus having the orders cancelled.
This behavior also introduces additional attack surface by allowing these accounts to be involved in such actions, which could potentially lead to unexpected scenarios.
Recommendation
Consider validating that accounts are not liquidatable by margin only in the
validateTrade,mergeAccounts, andsplitAccountfunctions.Resolution
Synthetix Team: The issue was resolved in PR#2115,.
-
M-13 Medium Lack of Pyth Confidence Interval Check Logical Error Acknowledged
Description
Currently the system uses
parsePriceFeedUpdatesUniqueto get the first unique price for the given time period.Pyth provides instant prices, but because market price discovery takes time and happens gradually over all of the markets Pyth has implemented confidence in their system. For example, the returned price for ETH can be $2000 with confidence of +-20 USD. This means the real price of ETH can range from $1980 to $2020.
Currently there are no checks for confidence, which can lead to users not being liquidated in time, lowering the profits for LP providers, or putting them in debt.
Recommendation
Consider using the confidence intervals as described in Pyth’s best practices. If someone wants to open a derivative contract, their collateral may be valued at the lower price. However, if deciding whether someone's margin limits were violated, value their outstanding leveraged position at the higher price.
Resolution
Synthetix Team: Acknowledged.
-
M-14 Medium Endorsed Keeper May Receive Excessive Fees Unexpected Behavior Acknowledged
Description
In
validateLiquidation,liqKeeperFeeis calculated based onliqSizewhich is expected not to exceedmaxLiquidatableCapacity. Therefore,getLiquidationKeeperFeeis expected to calculateiterations= 1 and returnliquidationFeeInUsd * 1.However, when an endorsed keeper performs a liquidation,
liqSizemay exceedmaxLiquidatableCapacity. In this case,iterationscould exceed 1, and the keeper will receive multiples of the keeperFee despite only performing one liquidation.For example, if
liqSize = 10butmaxLiquidatableCapacity = 2, then the keeper will receive five times thekeeperFee.Recommendation
Consider whether this is desired behavior. If it is not desired, then consider adding to
getLiquidationKeeperFee:if (ERC2771Context._msgSender() == globalConfig.keeperLiquidationEndorsed) { iterations = 1; }Resolution
Synthetix Team: Acknowledged.
-
M-15 Medium Utilization Rate Not Bounded Below 1 Logical Error Resolved
Description
The documentation for the
getUtilizationfunction states that thecollateralUtilizationis between zero and one, however this is not true as thelockedCollateralUsd / delegatedCollateralValueUsdratio is not guaranteed to be below one.While delegated collateral is locked when it’s value drops below the
minimumCredit(e.g.lockedCollateralUsd), this does not guarantee that thedelegatedCollateralValueUsdwill always be greater than theminimumCredit. ThedelegatedCollateralValueUsdmay fall below theminimumCreditbased on price action as well as increases in theminimumCreditby the introduction of new positions.As a result the utilization can be above 1e18, which can lead to unexpected utilization fees as well as a DoS when computing the utilization rate with the
getCurrentUtilizationRatefunction. If the utilization rate is allowed to hit > 3e18 then thehighUtilizationRateInterestcalculation is at risk of overflowing theuint128and halting all order execution and liquidations in the BFP market.Recommendation
Consider explicitly bounding the result from
getUtilizationbelow 1e18.Resolution
Synthetix Team: The issue was resolved in PR#2123.
-
M-16 Medium Lacking Execution Incentive During Periods Of High Gas Fees Incentives Resolved
Description
In the test environment the
maxKeeperFeeUsdis between $50 and $100, however this amount will be insufficient to incentivize the execution of orders and flagging of liquidatable positions during periods of high network usage and gas fees.The
maxKeeperFeeUsdought to be raised to sufficiently incentivize timely order execution and liquidation.Subsequently, some users may be unwilling to pay for extremely high execution costs during these times of high network usage. For these users it may be useful to have an order specific maximum keeper fee to limit the potential cost to their account’s margin.
Recommendation
Consider raising the
maxKeeperFeeUsdto a value that does not constrict the incentive for keepers to execute orders and flag positions for liquidation during periods of high gas fees. Based on thekeeperSettlementGasUnitsof 1.2 million and assuming an aggressive base fee of 40 gwei at a current price of $3,500 per ETH, themaxKeeperFeeUsdought to be assigned to roughly $200+ to allow for appropriate incentives for order execution during periods of high network usage.Additionally consider implementing a maximum keeper fee value that is configurable on a per-order basis to allow users to set their tolerance for network fees.
Resolution
Synthetix Team: Resolved.
-
M-17 Medium Gas Griefing With Settlement Hooks Gas Griefing Resolved
Description
Users can opt to use settle order hooks, called at the end of the
settleOrderfunction. These hooks will be mainly used for splitting and merging accounts when settling orders. These hooks require explicit permissions from the account holders:_PERPS_MODIFY_COLLATERAL_PERMISSION.If a user commits an order with one of this hooks, they can front run the keeper order and remove the account permissions, reverting the transaction.
Recommendation
Be aware and clearly document that this can be an issue for the keepers.
Resolution
Synthetix Team: The issue was resolved in PR#2126.
-
M-18 Medium Order Cancellation Overcompensates Keepers Incentives Resolved
Description
Upon cancelling an order, the keeper is compensated with the same fee they would receive for executing the order. However the gas cost necessary to execute an order is far more than the gas cost to cancel an order.
Additionally, keepers will receive the
keeperFeeBufferUsdas profit when cancelling an order, when this amount is meant instead to incentivize the execution of an order. As a result keepers receive far more profit for cancelling orders rather than executing them. Therefore, keepers will not only be overcompensated for cancellation, but highly incentivized to front-run users who are cancelling their own orders to cancel them on the user’s behalf and collect a fee from the user’s margin.Recommendation
Consider implementing a fee calculation that is specific to cancellation remuneration rather than overcompensating keepers for the cancellation with the same fee they would receive from execution.
Resolution
Synthetix Team: The issue was resolved in PR#2117.
-
M-19 Medium Sudden Block Fee Increases May Cause Insolvent Liquidations Warning Resolved
Description
New positions are validated when the order is settled by checking if the margin minus the fees will satisfy the initial and maintenance margin checks. This fees include order, keeper, flag and liquidation fees.
The issue is that the calculations of these fees rely heavily on the
block.basefeeand eth price, the only parameters that the protocol can't control. This base fee can range from 10-15 Gwei in a normal market scenario, up to >600 Gwei when volatility is high.Therefore, users can open LONG positions when the block base fee is low, and get liquidated a few blocks later if the base fee increases, even if the market price moves in their favor. Potentially, this can cause an insolvent liquidation for small accounts since the base fee jump might be an unpredictable stepwise change.
Recommendation
Consider increasing the market
minMarginUsdto the point that it can cover the volatility of the base fee and reduce the risk of an insolvent liquidation.Resolution
Synthetix Team: Resolved.
-
M-20 Medium Risk Free Trade With Account Permissions Gaming Resolved
Description
Similarly to M-09, it is possible to make a short term risk free trade by preventing keepers from executing an account’s order by including a splitAccount callback where no keeper is granted the necessary
_PERPS_MODIFY_COLLATERAL_PERMISSIONfor thefromIdaccount.As a result, a malicious user may prevent an order from being executable in the block where the valid price data is accurate and only allow the order to go through once a significant period of time has passed and the user observes that the true current price of the index asset has moved in their favor.
The order will only be executable with the outdated price, and therefore the user will realize a risk-free profit based upon how much price has diverged in the user’s favor since then.
Recommendation
Consider increasing the
orderFeepercentage that is taken to dissuade from any risk-free short term trades. Otherwise consider removing the possibility for users to control whether or not their orders are executable by way of callbacks through atry/catchwrapper around the callbacks.Resolution
Synthetix Team: The issue was resolved in PR#2126.
-
M-21 Medium Lacking Incentive To Repay Debt Incentives Resolved
Description
In the BFP market users can leave accounts with realized
debtUsdand enough collateral to support thatdebtUsdwithout ever repaying the debt. The debt inside these accounts will be reported inreportedDebtas profits for the LPs, however the sUSD will never be returned and never increase thecreditCapacityfor the market since the debt is not repaid.Over time with many positions holding unpaid debt there is an increased risk of reducing the
getWithdrawableMarketUsdto a point where traders are unable to withdraw their sUSD collateral or claim their sUSD profits.Recommendation
Consider implementing an interest rate on unpaid debt, where traders pay a configurable rate on debt that has not yet been repaid in sUSD.
Resolution
Synthetix Team: The issue was resolved in PR#2170.
-
L-01 Low supportedSynthMarketIds DoS DoS Resolved
Description
Throughout the codebase there are many instances where the
supportedSynthMarketIdslist is iterated over and often expensive operations are performed. When configuring thesupportedSynthMarketIdslist with thesetMarginCollateralConfigurationfunction there is no validation on the maximum length of the list.As a result it may be possible for the length of the
supportedSynthMarketIdsto be assigned such that many operations are extremely gas intensive or entirely DoS’d as they would exceed the block gas limit.This could cause significant harm if e.g. an account liquidation would require too much gas to be executed. However it is unlikely that the
supportedSynthMarketIdslist would grow extremely long as currently only three synthetic assets are planned to be supported.Recommendation
Consider implementing validation in the
setMarginCollateralConfigurationfunction such that thesupportedSynthMarketIdscannot exceed an acceptable length.Resolution
Synthetix Team: The issue was resolved in PR#2084.
-
L-02 Low Misleading Comment Documentation Resolved
Description
In the
liquidateMarginOnlyfunction the comment on line 370 indicates that the keeperReward will go to pay the flagger, however this amount is not paid to the flagger instead it is paid to themsg.sender.Recommendation
Update the comment to be clear that this fee is intended to be sent to the msg.sender, not the flagger.
Resolution
Synthetix Team: The issue was resolved in PR#2084.
-
L-03 Low Typo Typo Resolved
Description
On line 218 in the
PerpAccountModule,toPositionis misspelled astoPostion.Recommendation
Correct it to
toPosition.Resolution
Synthetix Team: The issue was resolved in PR#2084.
-
L-04 Low reportedDebt Even Skew Optimization Optimization Resolved
Description
In the
reportedDebtfunction there is a short-circuit case which saves gas whenmarket.skew == 0 &&market.debtCorrection == 0 && market.totalTraderDebtUsd == 0.The expensive operation being avoided is the
market.getOraclePricecall, however this expensive operation can be avoided in the more general case wheremarket.skew == 0.Recommendation
In order to avoid the expensive
market.getOraclePricecall in as many scenarios as possible, consider changing the short-circuit case to the following:if (market.skew == 0) return totalCollateralValueUsd - market.debtCorrection.toUint() - market.totalTraderDebtUsd;Resolution
Synthetix Team: The issue was resolved in PR#2084.
-
L-05 Low Modifying Fees Puts Users At Risk Of Liquidation Warning Acknowledged
Description
Changing any market parameters can instantly put users at risk of liquidation. This is because most parameters are closely tied to liquidation calculations, and altering just one can change the liquidation threshold for users. Examples include flag fees, maker and taker fees, and skew scale which affect the liquidation keeper fees, etc.
Recommendation
Consider introducing a timelock for modifying parameters that could cause positions to be at risk of liquidation.
Resolution
Synthetix Team: Acknowledged.
-
L-06 Low Gas Optimizations For UpdateMarketPreLiquidation Optimization Resolved
Description
In
updateMarketPreLiquidationthe following optimization can be made:market.updateDebtCorrection(market.positions[accountId], newPosition);can be changed tomarket.updateDebtCorrection(oldPosition, newPosition);Recommendation
Consider implementing the suggested optimization.
Resolution
Synthetix Team: The issue was resolved in PR#2136.
-
L-07 Low Gas Optimization For getCurrentUtilizationRate Optimization Resolved
Description
In the
getCurrentUtilizationRatefunction theutilization < utilizationBreakpointPercentcase can be optimized to account for the case whereutilization == utilizationBreakpointPercent.This is because when the
utilizationis the same as theutilizationBreakpointPercentthe resulting value is entirely based upon thelowUtilizationSlopePercent.Recommendation
Consider updating the low utilization case to:
utilization <= utilizationBreakpointPercent.Resolution
Synthetix Team: The issue was resolved in PR#2136.
-
L-08 Low payDebt Always Deducts From Account Margin Unexpected Behavior Resolved
Description
Permission can be granted for arbitrary addresses to
payDebton behalf of other users. However, when another user pays back the account's debt, the system will still deduct from the account's sUSD collateral.The
accountIdis checked for any sUSD, and if found, the system reduces the paid amount by this sUSD while also reducing the account collateral in the sUSD market. This behavior may be unexpected for the user who is making the debt payment and can unintentionally place positions at a greater risk of liquidation than intended.Recommendation
Be sure to document this behavior to users as it may be unexpected. Otherwise consider adding a boolean parameter and use it to determine if sUSD from the account's margin should be used.
Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-09 Low Unused updatePythPrice Function Optimization Resolved
Description
The
updatePythPriceinternal function in thePerpMarketlibrary is not used. It seems this was meant to be used to manually update pyth prices without the need to create or cancel an order.Additionally, this functions creates extra deployment costs, besides causing confusion to the reader of the contract.
Recommendation
Remove the unused internal function or add the external function with a proper access control so that pyth prices can be updated manually.
Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-10 Low getProportionalFundingElapsed Unnecessarily Performs Integer Division Arithmetic error Resolved
Description
The
getProportionalFundingElapsedfunction performsdivDecimalbetween theblock.timestamp -self.lastFundingTimeand1 days. Both of these values can be divided asuintvalues, howevertoIntis invoked on the time since the last funding. As a result thedivDecimaloverload accepting twoint256variables is used.This produces no unexpected behavior with the values being used, however to maximize the allowed domain space for these values,
uintvalues ought to be used instead.Recommendation
Consider modifying the
getProportionalFundingElapseddefinition such that thedivDecimaloverload acceptinguintvalues is used:return (block.timestamp - self.lastFundingTime).divDecimal(1 days).toInt();Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-11 Low Endorsed Keeper Unable To Fully Liquidate Positions Validation Acknowledged
Description
keeperLiquidationEndorsedmay not always be able to liquidate a user on the first attempt. This limitation arises because the condition allowing them to liquidate 100% of a user's position requires two criteria to be met:ERC2771Context._msgSender() == globalConfig.keeperLiquidationEndorsedandruntime.remainingCapacity == 0. This finding concerns the second criterion.For the endorsed keeper to liquidate 100% of a user's position,
remainingCapacitymust be 0. However, this is not always the case asremainingCapacityrestores (increases) with each block, due to the expiration of old liquidations.In a busy market, it's common for there to be liquidations in every block. If our keeper is the first to attempt liquidation in the current block,
remainingCapacitywill **not be 0**. This results in the endorsed keeper liquidating only a tiny fraction of the user's position.Consider the following example:
maxLiquidatableCapacity = 80 ETHwith a refresh rate of 30 seconds on Base (15 blocks). 1. The market is volatile and busy, with significant MEV and front-running activity. 2. Small liquidations occur every block, depleting the capacity. 3. A large position needs immediate liquidation as prices move quickly. 4. The keeper, being first to call liquidate, butremainingCapacityhas replenished with a few ETH. 5. The keeper liquidates only a small fraction of the order. Under these circumstances, the endorsed keeper needs to call liquidate again in the same block, beforeremainingCapacityis replenished in the next.Recommendation
Consider removing the
runtime.remainingCapacity == 0requirement for the endorsed keeper. If the endorsed keeper calls to liquidate a user, that user often must be liquidated in entirety in a timely manner.Resolution
Synthetix Team: Acknowledged. 59
-
L-12 Low Keepers Doubly Incentivized To Flag Liquidatable Positions Unexpected Behavior Acknowledged
Description
When computing the liquidation flag reward in the
getLiquidationFlagRewardfunction the keeper receives a profit margin from two sources: the maximum of thekeeperProfitMarginPercentor thekeeperProfitMarginUsdas well as theliquidationRewardPercent.This doubly incentivizes liquidators to flag positions, which may be intentional to ensure liquidations always occur in a timely manner, but raises an inconsistency with the way other keeper actions such as executing liquidations or settling orders are remunerated.
Recommendation
Consider if it is expected for liquidation flaggers to be compensated with profit margin twice, if it is not then adjust the
getLiquidationFlagRewardfunction accordingly.Resolution
Synthetix Team: Acknowledged.
-
L-13 Low Withdrawals DoS’d By Merge Hook DoS Partially resolved
Description
The
withdrawAllCollateralfunction prevents users from withdrawing their collateral ifdebtUsdis non-zero. If this user has previously given permissions to the merge settlement hook, a malicious user can front run a withdrawal, and settling an order with this hook, transferring somedebtUsd(even 1 wei) to the target account, forcing thewithdrawAllCollateralfunction call to revert.Recommendation
Document this issue to users so they can revoke any permissions previously given to other contracts before they attempt to withdraw their collateral or otherwise accept the risk of this occurring.
Resolution
Synthetix Team: The issue was resolved in PR#2126.
-
L-14 Low Unnecessary Approvals Optimization Resolved
Description
The owner address can configure the collaterals supported by the market using the
setMarginCollateralConfiguration. This function will internally make an infinite approval to several addresses. Firstly an approval is made to the core Synthetix address, which is necessary to transfer market deposited collateral from traders.Secondly, the spot market is approved however this approval amount is never utilized and unnecessarily introduces risk to the BFP market.
Thirdly, the BFP market address itself is approved to transfer all sUSD synths, however nowhere in the modules which will act on this address is this approval amount used.
Recommendation
If there is a reason for these approvals then clearly document them. Otherwise, remove the unnecessary approvals to the spot market and to the BFP market contract itself.
Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-15 Low Position Mapping Not Cleared Upon Full Split Unexpected Behavior Resolved
Description
Splitting an account with 100% proportion does not delete the
fromIdposition from thepositionsmapping. Although this yields a position with size 0, the logic should coincide with thesettleOrderlogic, where the position is deleted from thepositionsmapping when size is zero.Recommendation
Remove the from position from the positions mapping if it is found to have zero size after splitting.
Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-16 Low Modify Collateral Permission Too Lenient Access Control Resolved
Description
Users can grant permissions to other addresses so that they can interact with their accounts. The issue is that
_PERPS_MODIFY_COLLATERAL_PERMISSIONmay be too lenient for the address, as this role can now deposit/withdraw collateral, pay debt, split and merge accounts.This prevents users to give specific permissions, for example, if they only want to allow a user to deposit or pay debt, but not withdrawing collateral. Furthermore, if an address has this permission it can open a new position for the user with
mergeAccount, which can be unexpected for users.Recommendation
Consider creating more granular permissions for account access. Otherwise, clearly document this access control behavior to users.
Resolution
Synthetix Team: The issue was resolved in PR#2140.
-
L-17 Low Insolvent Positions DoS getWithdrawableMargin DoS Resolved
Description
In the
getWithdrawableMarginfunction when the size of the position is 0 thecollateralUsd - debtUsdof the account is the uint value returned. However there is no guarantee that this resulting value will be a positive integer.Ideally accounts will always remain solvent and be liquidated in a timely fashion before their debt is able to eclipse their collateral, but in the scenario where this does occur the
getWithdrawableMarginfunction ought to not revert due to underflow and return a result of 0.This way integrating systems relying on
getWithdrawableMarginwill not experience a DoS when positions enter an insolvent state.Recommendation
Return the minimum of
collateralUsd - debtUsdand 0.Resolution
Synthetix Team: The issue was resolved in PR#2135.
-
L-18 Low Liquidator Fee Can Extract More Rewards Than Expected Gaming Acknowledged
Description
The liquidator keeper fee is calculated based on a block base fee, eth price and some market and global configs. When a position is flagged, this fee is accounted for in the maintenance margin. Depending on the position size and the
remainingCapacityof the market for liquidations, a position can be either liquidated in a single transaction or multiple partial liquidation transactions. The iterations are calculated based on an ideal scenario where there is full capacity when liquidating the entire position.Therefore, after a position is flagged, the keeper can actually earn multiple
liqRewardamounts: Let's take an example of a 10 ETH position that needs to be liquidated 1. remainingCapacity in window = 1. 2. Position flagged and partially liquidated (10-1 = 9). 3. Next block, callliquidatePositionagain, depending on prev market liquidations in window, keeper either liquidates fully or partially again.This means that a keeper may earn 2 or more liquidation fee rewards, when only 1 was accounted for in the margin requirement. In the worst case, a small account happens to be liquidated on the precipice of the liquidation capacity for a single block, and must be liquidated over two blocks. However the maintenance margin for this account did not factor this in, and therefore the additional liquidation fees cannot be covered by the margin, resulting in bad debt.
Recommendation
Consider raising the minimum required collateral for a position such that small positions cannot inadvertently cause bad debt through experiencing more liquidation fee iterations than expected. Additionally, the margin requirement threshold could pessimistically assume that some liquidation capacity will have been taken up in the block when the account is liquidated and account for an additional liquidation iteration when the position is above a certain size.
Alternatively, consider solutions which would account for the current used liquidation capacity, factoring in if a position would require more than one liquidation given the amount of capacity that is currently used up. Though such a solution may be dissatisfactory as it introduces a potential liquidation manipulation vector.
Finally, consider the use of a monitoring system that checks the iterations and liquidation sizes for flagged positions. This way endorsed keepers could be used in outlier scenarios to prevent overpaying liquidation fees by liquidating smaller accounts in a single transaction when they would otherwise incur bad debt.
Resolution
Synthetix Team: Acknowledged.
-
L-19 Low Incorrect NatSpec Documentation Resolved
Description
The following functions have incorrect NatSpec:
recomputeUtilizationis using the documentation from therecomputeFundingfunction.getSettlementKeeperFeestates that the fee is used for liquidations, which is incorrect.
Recommendation
Correct the NatSpec for these functions.
Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-20 Low Typo Typo Resolved
Description
In the comment describing the early return case in the
getUtilizationfunction,positionsis misspelled aspostions.Recommendation
Correct
postionstopositions.Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-21 Low Typo Typo Resolved
Description
In the
Marginlibrary the docstring for thegetOracleCollateralPricemisspellsoracleManagerasoraclerManager.Recommendation
Correct it to
oracleManager.Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-22 Low Typo Typo Resolved
Description
In the comment on line 283 in the
settleOrderfunctiongetHealthDatais misspelled asgetHeathData.Recommendation
Correct it to
getHealthData.Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-23 Low Typo Typo Resolved
Description
In the comment on line 269 in the
validateTradefunction,asis repeated twice.Recommendation
Remove the second instance of the word
as.Resolution
Synthetix Team: The issue was resolved in PR#2119.
-
L-24 Low Positions Can Be Liquidated When Adding Collateral Prevented Logical Error Resolved
Description
The protocol is able to revoke access to the
DEPOSITfeature, which prevents users from depositing more collateral. It is possible to be in a state such that adding collateral is prevented, yet liquidations can still occur. In such a scenario, users can be unfairly liquidated as they are unable to make their position healthy.Recommendation
Consider also pausing liquidations for positions that become liquidatable or only allowing liquidations to be made by trusted addresses during this period. Otherwise, clearly document this behavior to users.
Resolution
Synthetix Team: Resolved.
No findings match.
Invariants 15
The review's fuzzing suite asserted 15 invariants. 15 held.
Every invariant tested
| ID | Invariant | Result |
|---|---|---|
MGN-01 | Position is never liquidatable after a successful margin withdraw | Held |
MGN-02 | A modify collateral call will always revert for an account with a flagged position | Held |
MGN-03 | A modify collateral call will always revert for an account that has a pending order | Held |
MGN-04 | If an account's collateral is 0, then the account's debt must also be 0 | Held |
LIQ-01 | isPositionLiquidatable never reverts | Held |
LIQ-02 | If a position is flagged for liquidation before any function call, the position after is always either flagged for liquidation, or no longer exists | Held |
LIQ-03 | remainingLiquidatableSizeCapacity is strictly decreasing immediately after a successful liquidation | Held |
LIQ-04 | If a user gets successfully flagged, their collateral will always be 0 | Held |
LIQ-05 | The sUSD balance of a user that successfully flags a position is strictly increasing | Held |
LIQ-06 | The sUSD balance of a user that successfully flags a position increases less or equal to maxKeeperFee | Held |
ORD-01 | If an account has an order commited, a subsequent commit order call will always revert | Held |
ORD-02 | The sizeDelta of an order is always 0 after a successful settle order call | Held |
ORD-03 | An order immediately after a successful settle order call, is never liquidatable | Held |
ORD-04 | If a user successfully settles an order, their sUSD balance is strictly increasing | Held |
ORD-05 | The sUSD balance of a user that successfully cancels an order for another user is strictly increasing | Held |
More from Synthetix
All 14 reports-
Update Reviews
34 findings2 critical · 4 high 34 findings: 2 critical, 4 high, 13 medium, 10 low, 5 informational -
Deposit Contract
38 findings1 high 38 findings: 1 high, 6 medium, 20 low, 11 informational -
Fixed Staking Rewards
6 findings1 high 6 findings: 1 high, 2 medium, 3 low -
Auto-Compounding LP Vault
80 findings1 critical · 4 high 80 findings: 1 critical, 4 high, 14 medium, 61 low
Put your code through the same review.
This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.
