Position and account caps are enforced by
RiskManager.validateOpenPosition() on every call to openPosition and increasePosition. They are checked in real time against current pool equity, so the effective caps change as the pool grows or shrinks.Cap Calculations
Both caps are expressed as a fraction ofmaxNetExposure, which itself is derived from pool equity (see Pool Exposure Caps):
Default Parameters
| Parameter | Default Value | Percentage | Role |
|---|---|---|---|
perPositionCapFactorBps | 500 | 5% of maxNetExposure | RISK_ADMIN_ROLE |
perAccountCapFactorBps | 500 | 5% of maxNetExposure | RISK_ADMIN_ROLE |
Both factors default to 500 bps (5%), meaning a single position or account can hold at most 5% of the pool’s maximum net exposure. This ensures that at least 20 positions (or 20 accounts) would be needed to reach the pool’s net exposure limit, providing meaningful diversification.
Worked Example
Trader Opens Position
A trader opens a 20M USDC position. This is within the 25M per-position cap and within the 25M per-account cap. The position is accepted.
Validation Flow
On everyopenPosition and increasePosition call, RiskManager.validateOpenPosition() performs five checks in strict order. If any check fails, the transaction reverts with the corresponding error:
| # | Check | Error Code | Description |
|---|---|---|---|
| 1 | notional <= maxPositionNotional | ExceedsPositionCap | Single position size limit |
| 2 | accountGrossNotional + notional <= maxAccountNotional | ExceedsAccountCap | Total account exposure limit |
| 3 | |proposedNetExposure| <= maxNetExposure | ExceedsPoolExposureCap | Pool net directional limit |
| 4 | windowGrossAdded + notional <= maxGrossNotionalDeltaPerWindow | RateOfChangeExceeded | Gross addition rate limit |
| 5 | |windowNetChange + delta| <= maxNetExposureDeltaPerWindow | RateOfChangeExceeded | Net change rate limit |
Net Exposure Direction
The direction of net exposure change depends on the position side:- LONG Position
- SHORT Position
When a trader opens a LONG position, the pool takes the opposite (short) side:LONG positions decrease net exposure (push the pool short).
Minimum Position Notional
In addition to upper caps, the protocol enforces a minimum position size to prevent dust positions that would be uneconomical to settle or liquidate:| Parameter | Default Value | USDC Equivalent |
|---|---|---|
minPositionNotional | 100,000,000 (raw) | 100 USDC |
Why enforce a minimum?
Why enforce a minimum?
Dust positions create several problems:
- Gas inefficiency: Settlement and liquidation gas costs may exceed the position’s notional value
- Keeper overhead: The keeper service must scan and process every open position; tiny positions add overhead without meaningful economic value
- Storage bloat: Each position consumes onchain storage; dust positions waste storage with negligible protocol utility
Does the minimum apply to partial reductions?
Does the minimum apply to partial reductions?
Yes. When a trader calls
reducePosition(positionId, reductionNotional), the remaining notional after reduction must be at least minPositionNotional. If the reduction would leave less than the minimum, the trader must close the position entirely instead. This prevents positions from being reduced to dust over multiple partial reductions.Dynamic Cap Behavior
Because all caps are derived from pool equity, they exhibit important dynamic properties:Growing Pool
As LPs deposit USDC, pool equity rises. All caps increase proportionally. More traders can open larger positions, and the protocol can support greater overall trading volume.
Shrinking Pool
When the pool pays out trader profits or absorbs bad debt, equity falls. Caps tighten automatically. Traders attempting to open positions near the old cap limits will find their transactions rejected until the pool recovers.
LP Withdrawals
LP withdrawals reduce
totalAssets, which reduces poolEquity. This tightens all caps. The maxUtilizationBps check prevents withdrawals that would make caps too restrictive relative to existing open positions.Bad Debt Events
Bad debt reduces pool equity directly. After a bad debt event, caps tighten immediately. In extreme cases where pool equity approaches zero,
maxNetExposure approaches zero, effectively blocking all new positions.Interaction Between Caps
The three cap levels form a hierarchy of protection:A position can pass the position-level cap and the account-level cap but still be rejected by the pool-level net exposure cap. For example, if the pool is already near its net exposure limit, even a small position that pushes exposure over the cap will be rejected. All three checks must pass for a position to be opened.
Parameter Tuning
All cap parameters are controlled by theRISK_ADMIN_ROLE and take effect immediately:
| Parameter | Range | Effect of Increase | Effect of Decrease |
|---|---|---|---|
perPositionCapFactorBps | 1 - 10,000 | Larger individual positions allowed | Smaller positions, more diversification |
perAccountCapFactorBps | 1 - 10,000 | Accounts can hold more total notional | Accounts limited to smaller totals |
netExposureCapFactorBps | 1 - 10,000 | Pool accepts more net exposure | Pool becomes more conservative |
stressMoveBps | 1 - 10,000 | Caps tighten (more stress buffer) | Caps loosen (less stress buffer) |