Ethereal engaged Guardian to review the security of their Orderbook Perps settlement contracts. From the 12th of February to the 24th of February, a team of 7 auditors reviewed the source code in scope.
- Published
- Review window
- February 12 to 24, 2025
- Language
- Solidity
- Chains
- Converge
- Sector
- Perpetuals
- 1 Critical
- 1 High
- 3 Medium
- 16 Low
- 15 Informational
Scope
Overview
Ethereal engaged Guardian to review the security of their Orderbook Perps settlement contracts. From the 12th of February to the 24th of February, a team of 7 auditors reviewed the source code in scope.
Findings 36
-
C-01 Critical Insolvency Due To Trading Fees Logical Error Resolved
Description
When matching orders, taker and maker fees are not deducted from traders' balances, yet they are still added to the fee collector’s balance.
However, when the fee collector claims these fees, both the global balance and the fee collector’s personal balance are reduced. This results in insolvency, preventing depositors from withdrawing their balances.
Recommendation
Deduct maker and taker fees from traders' balances.
Resolution
Ethereal Team: The issue was resolved in PR#94.
-
H-01 High Traders Credited With Infinite Liquidity Logical Error Resolved
Description
In the protocol, PNL is calculated based on the whole position size regardless of the actual filled amount. This means that even if there aren’t enough counterparties to fill the full position at a given price, the system still accounts for the profit as if the whole size was successfully exited, which creates a mismatch between realized profits and what is actually achievable in the market.
This creates an issue especially when the liquidity depth is not enough to close a large position. For example:
- Trader opens a 100-size long at $1000
- The price rises to $1500, but it’s a resistance level with strong sell pressure and limited buy liquidity.
- Trader closes only size of 1.
- The protocol realizes profit on the full 100-size position at $1500, even though only 1 unit was actually sold.
- Realized profit: $50,000
Normally, equilibrium would be reached as the price declines, with the trader closing the remaining 99-size position at a lower price and realizing a loss. However, knowing they cannot exit the full size at reasonable prices, the trader can withdraw these realized but unbacked profits and leave the remaining position for liquidation.
For this position above (at 10x leverage):
- Initial position value: $100,000
- Deposit: $10,000
- Realized profit: $50,000
- New balance: $60,000
- New position value: 99 * 1500 = $148,500
- New required margin: $14,850
- Trader can withdraw up to $45,150, and leave the rest of the position for liquidation.
Recommendation
Consider realizing PNL only when decreasing or closing positions and calculating it based on the filled amount rather than the entire position size. This ensures that realized profits accurately reflect actual market execution.
When increasing positions, calculate and adjust the average entry price instead of realizing PNL and setting the latest match price as the new entry. This ensures that unrealized gains or losses remain properly accounted for until an actual position reduction occurs.
Resolution
Ethereal Team: The issue was resolved in PR#114.
-
M-01 Medium excludedAccounts Can Open Trades Validation Resolved
Description
Inside the the
_verifyOrderfunction the order of operations is incorrect. It checks if theorder.senderis an excluded account.However, at this point the
order.sendercould be the linked signer of the account. In these situations the validation would not be sufficient and an excluded account could open a trade.Recommendation
Perform the validation with
account.senderinstead oforder.sender.Resolution
Ethereal Team: The issue was resolved in PR#90.
-
M-02 Medium Liquidator Can Open Trades For Any Account Centralization Resolved
Description
The liquidator account has the power to open trade positions for any account. The liquidator can increase or decrease another account's position size without their approval or signature.
Recommendation
Similar to how when a market is in a closed status require that
_isIncreasingPositionreturns false. This will limit the liquidator to only decreasing the position's size.Resolution
Ethereal Team: The issue was resolved in PR#files.
-
M-03 Medium DoS Of processActions() DoS Resolved
Description
A user can temporarily cause a DoS of the
processActions()function by submitting a link signer request and depositing. Doing so will prevent other transactions that are meant to be submitted from being posted on-chain.In turn, this can delay liquidations and users from closing trades at crucial times. To carry this attack out a malicious user needs to create a link signer action. Then,
deposit()can be called by the user directly. This will add them to theexcludedSignersmapping.Inside of
_handleLinkSigner(), a revert will occur when it validates that the user is not in theexcludedSignersmapping.Recommendation
Wrap internal calls inside of
processAction()intry-catchblocks to prevent a revert from causing a DoS of the entire transaction.Resolution
Ethereal Team: The issue was resolved in PR#116.
-
L-01 Low Impossible To Remove Some Tokens Unexpected Behavior Acknowledged
Description
The
ExchangeConfigcontract allows tokens to be removed and specifically contains logic for removing the USD token used in the contract.However, it is realistically impossible to remove the USD token as the USD token must be used as the quote token in the
PerpEngine.solcontract, thus marking it asremoveProtected.// Only allow usdToken (i.e. USDe) as the perp settlement currency. if (quoteToken.tokenAddress = accountGlobal.usdToken) {revert InvalidParameter("quoteTokenName", P_ERR_BAD_ADDR);} if (quoteToken.removeProtected) {quoteToken.removeProtected = true;}Furthermore, protected tokens in general can never be removed as they are required to be
removeProtected = false, but there is not way to assignremoveProtectedback to false for tokens which are only used in deprecated markets.Recommendation
Be aware of this behavior and if you wish to be able to remove tokens that are only used in deprecated markets then consider refactoring the
removeProtectedlogic.Resolution
Ethereal Team: This is expected behaviour and documented in the code. removeToken is largely in-place to undo fat finger configuration when an asset is initially added and needs to be updated before enabling deposits.
-
L-02 Low tokensByAddress Written For Virtual Tokens Logical Error Resolved
Description
In the
addTokenfunction thetokensByAddressmapping is updated even in the case where thetokenAddressisaddress(0). Therefore the entry foraddress(0)is a valid token and is the last token that was added with theaddTokenfunction.Recommendation
Only write to the
tokensByAddressmapping inside of thetokenAddress = address(0) elsecase.Resolution
Ethereal Team: The issue was resolved in PR#105.
-
L-03 Low Lacking Maker Taker Fee Validation Validation Resolved
Description
In both the
registerandupdateFeesfunctions there are no validations performed on the maker and taker fees to ensure that the maker fee is lower than the taker fee and also within a reasonable range.Recommendation
Consider adding validations in both the
registerandupdateFeesfunctions so that the maker fee cannot be configured higher than the taker fee and that both fees are within a reasonable range.Resolution
Ethereal Team: The issue was resolved in PR#106.
-
L-04 Low UpdateFunding Risks Centralization Acknowledged
Description
There is no signature validation necessary for the
UpdateFundingaction from the sequencer. Therefore a compromised or errant sequencer may submit invalid funding updates.This affords the sequencer the power to apply arbitrarily large funding amounts and subsequently liquidate users or a malicious actor who has compromised the sequencer may assign a high positive funding amount and immediately close their account to withdraw ill gotten gains.
Recommendation
There are already TODO comments which suggest adding caps on the magnitude of the
fundingDeltaUsdand limiting how often update funding can be called, which appropriately addresses the risk. Consider implementing these TODO comments.Additionally, consider adding a specific
FundingUpdatersigner which must attest to the validity of the funding updates. This way even if the sequencer were compromised they cannot submit any inaccurate funding updates.Resolution
Ethereal Team: These TODO comments will be implemented at a later time before the initial launch.
-
L-05 Low Lacking Exclusion Validation Validation Resolved
Description
In the
addSequencer,updateFeeCollector, andupdateLiquidatorfunctions there is no validation to ensure the added account is not anexcludedSignersorexcludedAccountsexclusion before adding it.Recommendation
Consider validating that the newly assigned account is not already set as true in either the
excludedSignersorexcludedAccountsmappings.For the
updateFeeCollectorandupdateLiquidatorjust be sure that the account is not the same as the existing fee collector and liquidator accounts before performing this validation.Resolution
Ethereal Team: The issue was resolved in PR#files.
-
L-06 Low updateMaxLeverage Can Change Liquidation Status Validation Acknowledged
Description
In the offchain Matching Engine,
initialMarginRateis the reciprocal ofmaxLeverage.maintenanceMarginRateis half ofinitialMarginRate. If an account fails to satisfy the maintenance margin they will be liquidated. Therefore, if themaxLeveragefor a product is decreased themaintenanceMarginwill increase. Accounts with open positions may be moved under themaintenanceMarginand into liquidation zone. Consider the following example:STATE 1
initialMaxLeverage = 10initialMarginRate = 1/( initialMaxLeverage) = 1/10maintenanceMarginRate = (1/2)*initialMarginRate = 1/20STATE 2
newMaxLeverage = 5newInitialMarginRate = 1/(newMaxLeverage) = 1/5maintenanceMarginRate = (1/2)*newInitialMarginRate = 1/10Let's say an account has apositionSize= $10,000 and collateral = $750In STATE 1
minMaintenanceCollateral = (1/20)*positionSizeminMaintenanceCollateral = (1/20)*$10,000minMaintenanceCollateral = $500$750 > $500, SAFE FROM LIQUIDATIONIn STATE 2
minMaintenanceCollateral = (1/10)*positionSizeminMaintenanceCollateral = (1/10)*$10,000minMaintenanceCollateral = $1000$750 < $1000, LIQUIDATABLETherefore, the collateral requirements increased after the
maxLeveragewas decreased.Recommendation
First put the product in a closed status. Once all trades are closed, update the max leverage and then change the status of the product to open.
Resolution
Ethereal Team: Acknowledged.
-
L-07 Low Healthy Positions Can Be Liquidated Logical Error Resolved
Description
Even with sequencer checks if the user makes a deposit right before a batch of orders goes through the sequencer could check and see that the account is underwater.
But by the time liquidations go through the user could have deposited funds and had a healthy account, but still get liquidated since there are no on chain margin checks.
Recommendation
Document to users that if the account is at any point in time liquidatable they are eligible to be liquidated and pay the liquidation fee. Regardless of the accounts health when the actual liquidation occurs.
Resolution
Ethereal Team: The issue was resolved in PR#110.
-
L-08 Low Missing On Chain Cancellation Logic Validation Resolved
Description
When a cancellation occurs it is intended to be handled off-chain. But the signatures will still be valid on chain. This means that even after a user cancels an order that signature can still be used on chain.
Even if this information is maintained off chain all it would take is the off chain data to be lost, overlooked, or changed, at which point all cancelled orders could be used despite the original sender's request to cancel the order.
The sequencer is trusted to not re-use these signatures/nonces and the off-chain component is trusted to not allow re-submissions of these signatures/nonces.
Recommendation
Ensure that the off-chain systems cannot allow nonces to be re-submitted when they haven’t been used on-chain. Optionally, consider adding a deadline parameter to the signature so that naturally after a set amount of time the order cannot be used.
Resolution
Ethereal Team: The issue was resolved in PR#118.
-
L-09 Low Unclaimed Fees Are Locked After Update Logical Error Acknowledged
Description
Fee collectors are excluded accounts and claim fees using the
claimFeesfunction. The owner can change the fee collector address, but this change does not perform a balance check.Setting a new fee collector without claiming the previous balance will lock the previously earned fees. This happens because the previous fee collector can no longer call the
claimFeesfunction.Additionally, they cannot use the withdraw function due to their excluded status. The new fee collector also cannot withdraw those fees, as they remain in the previous collector’s balance.
Recommendation
Perform a balance check and claim earned fees before updating the fee collector address. Otherwise be aware of this behavior and ensure that fees are always claimed before changing the fee collector or that the fee collector address should be reset to the original address to claim any fees that went unclaimed.
Resolution
Ethereal Team: Acknowledged.
-
L-10 Low Changing Lot Size Can Impact Order Fulfillment Warning Resolved
Description
Whenever the a trade is opened it checks to make sure the quantity
product.lotSize = 0. Thus, if the owner makes updates theproduct.lotSize, there is a good chance that open positions will not be able to be 100% liquidate-able. For example, the originallotSize = 2.A trade is made with quantity of 4 and passes all checks. Then the
lostSizeis changed to 5 and the position cannot be liquidated because 4 * 5 = 0. In reality the amount would be small, but there is a very high chance this will happen if thelotSizeis ever updated.Recommendation
Validate that the existing order fulfillment is not impacted by lot size changes prior to changing the lot size.
Resolution
Ethereal Team: The issue was resolved in PR#104.
-
L-11 Low Incorrect Typehash With Liquidation Orders Compatibility Acknowledged
Description
The
LiquidateTradeOrderstruct includes theTraderOrderstruct, along with liquidator andliquidatorSubaccountfields. The type hash for this struct is created in the code as follows:“
LiquidateTradeOrder(address sender,bytes32subaccount,uint128quantity,uint128price,uint8side,uint8,engineType,uint32 productId,uint64nonce,address liquidator,bytes32liquidatorSubaccount)".However, according to EIP-712, when encoding structs that contain nested structs, each struct should be encoded separately. For the
LiquidateTradeOrdertype above, the correct encoding should be:"
LiquidateTraderOrder(TradeOrderorder, address liquidator,bytes32liquidatorSubaccount)TraderOrder(address sender,bytes32subaccount,uint128quantity,uint128price,uint8 side,uint8 engineType,uint32 productId,uint64nonce)”.Recommendation
Update the struct encoding according to the EIP standard.
Resolution
Ethereal Team: Although this does not strictly follow the EIP standard, the current encoding still produces a unique hash for each order, just implemented differently.
-
L-12 Low Updating Lockout Affects Pending Withdrawals Unexpected Behavior Acknowledged
Description
Withdrawals are a two-step process in the protocol. Users initiate withdrawals and finalize them after the lockout period has passed.
The lockout period check is performed during the second step of the process in the
finalizeWithdrawfunction:validAfter = withdraw.initiatedAt + exchange.withdrawLockout.However, the lockout period can be changed at any time, and this change not only affects future withdrawals but also pending withdrawals. A withdrawal request should have the
validAftertime based on the lockout period at the time of the request's creation.Recommendation
Determine the
validAfterparameter during the first step of the withdrawal process.Resolution
Ethereal Team: Acknowledged.
-
L-13 Low maxLeverage Not Validated Validation Acknowledged
Description
The
maxLeveragevalue is configured and updatable. However, a trader’s leverage is never validated. This allows traders to open positions that vastly exceed the leverage tolerance for a product.Recommendation
Validate the trader is not using more leverage than is allowed for the product.
Resolution
Ethereal Team: maxLeverage and other attributes mentioned here, such as maxOpenInterest although not validated onchain, is validated offchain. The reason we don't validate maxLeverage during trades is it can significantly lower settlement throughput and without formal coordination could lead to temporary settlement halts.
-
L-14 Low Funds Permanently Stuck With Failed ERC20 Transfer DoS Resolved
Description
In the case where there is a withdraw fee, the fee is subtracted from the
action.message.amount. It is checked that the message amount is at least as large as thewithdrawfee→if (withdrawFee >action.message.amount) { revert…}. However, this presents an edge case whereaction.message.amount = withdrawFee. In this case, the amount written for the withdraw request will be 0.However, some tokens revert upon transferring 0-value, causing the call to
finalizeTransfer()to revert. Since a user can only have one pending withdrawal at a time, it is imperative that the user can finalize each withdrawal.Recommendation
The recommended mitigation is two-fold. Firstly, ensure that the withdrawal amount is strictly greater than the withdraw fee
action.message.amount > withdrawFee. Second, add some logic to mitigate general ERC20 transfer failures.While these tokens will be on their own L3, there may be tokens with transfer restrictions like
USDC’s blacklist. You can potentially check if the transfer fails and add back the token balance to the user and delete the pending withdrawal so that the user can queue another token to be withdrawn.Resolution
Ethereal Team: The issue was resolved in PR#100.
-
L-15 Low maxOpenInterest Not Verified Validation Acknowledged
Description
The
maxOpenInterestis not verified when opening a new position. Unless the trade is verified by the Sequencer themaxOpenInterestcan easily be surpassed since there are no checks inside the contract.Since many orders will occur in a single batch it may be possible that open interest will exceed the max if a single batch is large enough.
Recommendation
Inside
_verifyOrderverify themaxOpenInteresthas not been reached similar to how they are checking the quantity,lotSizeetc.Resolution
Ethereal Team: Similar to other configuration variables, this is verified offchain and largely in place to provide a central point of exchange configuration. We’ve provided more docs around config management in the README.
-
L-16 Low Market Orders Have No On-Chain Price Protection Validation Acknowledged
Description
Off-chain market orders will be signed with a
price = 0and will offer no on-chain price protection for a user. The fulfilled price could be far from what they originally expected.Recommendation
Consider implementing either on chain or off chain slippage where the user can ensure they are being matched with what they anticipate the market price to be, and if it is not, don't match the order.
Resolution
Ethereal Team: The matching engine has price slippage protection for market orders such that if the slippage exceeds 5% then the order will not be filled.
-
I-01 Informational Misleading Error Validation Resolved
Description
In the
_verifyProductSizesfunction themaxQuantity lotSize = 0validation provides theP_ERR_AMT_GT_MAXerror. However this error code is not the most accurate for this validation since it is not comparing against a max, but instead a modulus.Recommendation
Consider using the
P_ERR_BAD_VALerror code or introducing a new error code for themaxQuantitylotSize = 0validation.Resolution
Ethereal Team: The issue was resolved in PR#108.
-
I-02 Informational Incorrect Error Used For Excluded Accounts Errors Resolved
Description
The code mistakenly uses the
UnauthorizedAccounterror instead ofExcludedAccounterror when checking if the sender is an excluded account.(accountGlobal.excludedAccounts[msg.sender]) {revert UnauthorizedAccount(msg.sender);}Compare this to a similar check elsewhere in the code:
(accountGlobal.excludedAccounts[action.message.account]) {revert ExcludedAccount(idx, action.message.account);}Recommendation
Use the
ExcludedAccounterror for both checks.Resolution
Ethereal Team: The issue was resolved in PR#107.
-
I-03 Informational Trade Digest Parameters Should Match Code Quality Acknowledged
Description
The function
_getTradeOrderDigest()orders the parameters for the struct digest slightly differently than theTradeOrderstruct.function _getTradeOrderDigest(TradeOrder memory order) private view returns (bytes32) {bytes32 structDigest = keccak256(abi.encode(TRADE_ORDER_ABI_PARAM_SIG, order.sender, order.quantity, order.price, order.side, order.productId, order.engineType, order.subaccount, order.nonce));vs:
struct TradeOrder {address sender; bytes32 subaccount; uint128 quantity; uint128 price; OrderSide side; EngineType engineType; uint32 productId; uint64 nonce;}Recommendation
Consider ordering the digest entries the same as the
TradeOrderstruct entries.Resolution
Ethereal Team: Acknowledged.
-
I-04 Informational Unused Errors Errors Resolved
Description
The
ExchangeGatewaycontract holds several unused errors:InvalidParameterP_ERR_BAD_ADDRSignerNotFound
Recommendation
Consider implementing the use of these errors or removing them.
Resolution
Ethereal Team: The issue was resolved in PR#94.
-
I-05 Informational Typos Typo Resolved
Description
Throughout the contract there are several typos:
- ExchangeGateway.sol:292 Accured → Accrued
- PerpEngine.sol:349 Accured → Accrued
- Architecture Diagram: Sotre -> Store
- ExchangeGateway.sol:244: withou -> without
- ProcessActions.InitiateWithdraw.t.sol:37: Inititate -> Initiate
- ProcessActions.LinkSigner.t.sol:91-93 Lined -> Linked
Recommendation
Consider correcting these typos.
Resolution
Ethereal Team: The issue was resolved in PR#94.
-
I-06 Informational FeeCollector’s Unclaimed Fees Are Counted Toward depositCap Logical Error Acknowledged
Description
The
depositCapis strictly checked against the globaltokenBalance. However, theFeeCollector’s unclaimed fees are contained in the global balance until they claim them.This is somewhat misleading as the
FeeCollector’s fees are already earmarked for them and are not truly a deposit.Recommendation
When checking the global balance against the deposit cap, deduct the
FeeCollector’s balance.Resolution
Ethereal Team: Expected behaviour. The team will ensure deposit capacity is sufficiently large enough to account for unclaimed fees. Additionally, we will have processes to periodically claim fees on a regular basis.
-
I-07 Informational Incorrect Comment For Open Interest Calculation Logical Error Resolved
Description
The comment about the OI calculation states:
Total product OI in native units (e.g. 5 short, 5 long =10 OI). But the implementation only counts long open interest.Recommendation
Correct the comment to correctly reflect the OI calculation.
Resolution
Ethereal Team: The issue was resolved in PR#94.
-
I-08 Informational Lacking Error Data Errors Acknowledged
Description
The
_verifyOrderfunction includes a boolean parameterisTakerwhich indicates whether it is the maker or taker order which is being verified.However the errors raised in the
_verifyOrderfunction do not specify theisTakervalue and therefore are ambiguous as to which order the revert occurred with.Recommendation
Consider including the
isTakerinformation in the reverts in the_verifyOrderfunction to provide more data about the error.Resolution
Ethereal Team: Acknowledged.
-
I-09 Informational Gas Savings Reading Constant Storage Slots Optimization Acknowledged
Description
There can be gas savings made by changing libraries to read from constant storage slots.
Recommendation
Consider implementing constant storage slots in the libraries used.
Resolution
Ethereal Team: Acknowledged.
-
I-10 Informational decimals() Not Required For ERC20 Standard Compatibility Acknowledged
Description
ERC20Helpers.isERC20()validates if a token can be added by checking if it is anERC-20token. One of the checks looks for a return value from thedecimals()function. Since this function is not required to be implemented, someERC-20tokens may be excluded from the use in the protocol.Recommendation
If you wish to include
ERC-20tokens that do not implementdecimals(), other protocols default the decimal value to 18 in a try/catch block.Resolution
Ethereal Team: We will only support ERC20 tokens with a
decimals()function and assuming 18 decimals can lead to downstream problems if the assumption doesn’t hold true. -
I-11 Informational Lacking Event Info Events Resolved
Description
The
Depositevent does not include details on how much fees were charged during the deposit, nor what the original total deposit amount was before fees.This information may be useful to off-chain systems which are reading for
Depositevents and is in contrast to theWithdrawFinalizedevent which includes the fee.Recommendation
Consider emitting the fee amount along with the
Depositfunction.Resolution
Ethereal Team: The issue was resolved in PR#110.
-
I-12 Informational Incorrect Comment Documentation Resolved
Description
The comment in the
_handleLinkSignerfunction on line 403 mentions thatsubaccountsare anexcludedSignersaddress. However it is normal accounts which are excluded, not sub accounts.Recommendation
Correct the comment to indicate that it is accounts which can be in the
excludedSignersmapping and not subaccounts.Resolution
Ethereal Team: Resolved.
-
I-13 Informational Protocol Cannot Handle Bad Debt Logical Error Acknowledged
Description
The
_settlePositionfunction is invoked for both sides of the trade when matching orders. The function calculates the PnL, determines the new USD balance, and updates positions.The
usdTokenBalance + pricePnl - fundingPnlis converted touint256after it is calculated. However, thetoUint256function reverts when the provided value is negative. As a result, settlements will fail when a trader loses their entire balance.Since the liquidation process also follows the same execution flow, liquidations will also fail in that case. Even if a partial liquidation is attempted, it would also fail because the PnL is calculated based on the entire position size.
Recommendation
Consider setting the trader's balance to 0 when it falls below zero due to negative PnL. However, this would also require covering the negative amount, either from protocol-owned liquidity (e.g., fees) or from other traders.
Alternatively, set high liquidation thresholds and large margin requirements to ensure this situation never occurs, even during sudden and large price movements.
Resolution
Ethereal Team: There will be a large enough maintenance margin buffer where this will never happen.
Furthermore, If a loss was incurred due to a e.g. MarkChange, the offchain matching engine would cap the loss to prevent an insolvency (i.e. bankruptcy price) where the balance would never go below 0. In short, the sequencer would never trigger a trade where the account would be negative. If it did, it would be a bug and this should revert and halt, which it currently does.
-
I-14 Informational Users Are Never Charged For Gas Warning Resolved
Description
The protocol never charges users for gas, and all gas required to settle on-chain actions must be paid by the sequencer. Even if this is intentional, users can cause the sequencer to consume more gas by frequently linking and revoking signers.
Recommendation
Be aware of this situation. Either charge users gas for on-chain actions or restrict certain actions (especially those that don’t require any fees) from being called repeatedly.
Resolution
Ethereal Team: This is resolved by deposit/withdrawal fees, increasing minOrderQty, API rate limits, and rate limits on maximum linked signers per day/week.
.
-
I-15 Informational minDeposit Circumvented Validation Acknowledged
Description
In the
_handleInitiateWithdrawfunction there is no validation to ensure that the remaining deposit is larger than the configuredminDepositfor the deposit token.As a result, users may deposit and then withdraw funds in order to leave a dust amount of collateral in their account. This may cause unexpected issues in the off-chain system if a malicious actor were to create many accounts with a small amount of collateral deposited in each.
This would require the sequencer to hold and validate state for a potentially large number of accounts. In the worst case this could cause the sequencer to OOM at a certain scale, though this case is exceptionally unlikely.
Recommendation
Consider validating that the
minDepositis still met, optionally with a buffer to account for price changes of open positions, in the_handleInitiateWithdrawfunction.Resolution
Ethereal Team: We have deposit and withdrawal fees to disincentivize this behavior.
No findings match.
Invariants 9
The review's fuzzing suite asserted 9 invariants. 9 held.
Every invariant tested
| ID | Invariant | Result |
|---|---|---|
MATCH-01 | In CLOSE_ONLY mode, position sizes can only decrease or stay the same | Held |
MATCH-02 | ProductStatusViolation error should not occur when reducing position in CLOSE_ONLY mode | Held |
MATCH-03 | Total position size should be 0 | Held |
MATCH-04 | No-position trader balance must be freely withdrawable | Held |
MATCH-05 | Long OI is always the same as Short OI. | Held |
MATCH-06 | Sum of long position sizes is equal to the product tracked OI. | Held |
FEE-01 | Protocol should be globally solvent | Held |
LIQUI-01 | Liquidations should never unexpectedly revert | Held |
ERR-01 | Unexpected Error | Held |
More from Ethereal
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.
