DiffusalOptionsSeriesRegistry
Registry for option series lifecycle management
The DiffusalOptionsSeriesRegistry contract manages the lifecycle of option series from creation through settlement. It handles lazy series creation on first trade, validates series parameters, and coordinates TWAP-based settlement when options expire.
Overview
An option series is defined by four parameters:
| Parameter | Description |
|---|---|
pairId | Trading pair (e.g., keccak256("ETH-USD")) |
strike | Strike price (WAD) |
expiry | Option expiry timestamp |
isCall | Call (true) or put (false) |
Series Lifecycle
1. CREATION (lazy)
└─ Created on first trade via getOrCreateSeries()
2. ACTIVE
└─ Trading allowed until expiry
3. EXPIRED
└─ Trading stops, waiting for settlement
4. SETTLED
└─ Settlement price set, positions can settleKey Concepts
Lazy Series Creation
Series are not created in advance. Instead, they're created on-demand when the first trade occurs:
// Called by OrderBook or RFQ on every trade
SERIES_REGISTRY.getOrCreateSeries(seriesId, seriesParams);This approach:
- Eliminates need for admin intervention to list new options
- Reduces gas costs (only create series that are actually traded)
- Allows infinite series combinations
Series ID Generation
The series ID is a deterministic hash of the series parameters:
seriesId = keccak256(abi.encodePacked(pairId, strike, expiry, isCall));TWAP Settlement
When a series expires, it's settled using a 1-hour Time-Weighted Average Price (TWAP) from the PriceHistory contract:
(settlementPrice, snapshotCount) = priceHistory.getTwap(pairId, expiry);This prevents settlement price manipulation via single-block price attacks.
Storage & State
/// @custom:storage-location erc7201:diffusal.storage.SeriesRegistry
struct SeriesRegistryStorage {
address owner;
mapping(address => bool) operators; // Authorized operators
mapping(bytes32 => SeriesInfo) series; // Series ID → info
uint256 minTimeToExpiry; // Min time for new series
address priceHistory; // TWAP provider
}SeriesInfo Struct
struct SeriesInfo {
bytes32 pairId; // Trading pair identifier
uint256 strike; // Strike price (WAD)
uint256 expiry; // Option expiry timestamp
bool isCall; // true = call, false = put
bool isSettled; // Whether settled
uint256 settlementPrice; // Settlement price (WAD, 0 until settled)
}SeriesParams Struct
struct SeriesParams {
bytes32 pairId;
uint256 strike;
uint256 optionExpiry;
bool isCall;
}External Functions
Series Management
getOrCreateSeries
Gets existing series or creates a new one.
function getOrCreateSeries(bytes32 seriesId, SeriesParams calldata params)
external returns (SeriesInfo memory info)| Parameter | Type | Description |
|---|---|---|
seriesId | bytes32 | Expected series identifier |
params | SeriesParams | Series parameters for validation/creation |
If series exists:
- Validates series is still tradeable (not expired, not settled)
- Returns existing SeriesInfo
If series doesn't exist:
- Validates
seriesIdmatches computed hash of params - Validates strike > 0
- Validates expiry > now + minTimeToExpiry
- Creates and returns new series
Emits: SeriesCreated (on new series only)
settle
Settles an expired series using TWAP.
function settle(bytes32 seriesId) externalRequirements:
- Series must exist
- Series must be expired (
block.timestamp >= expiry) - Series must not already be settled
Process:
- Query TWAP from PriceHistory contract
- Set settlement price
- Mark series as settled
Emits: SeriesSettled, optionally SettlementFallbackUsed
Note: This function is permissionless—anyone can trigger settlement.
View Functions
seriesExists
Checks if a series has been created.
function seriesExists(bytes32 seriesId) external view returns (bool)getSeriesInfo
Returns full series information.
function getSeriesInfo(bytes32 seriesId) external view returns (SeriesInfo memory info)Reverts: SeriesNotFound if series doesn't exist.
isExpired
Checks if a series has expired.
function isExpired(bytes32 seriesId) external view returns (bool)isSettled
Checks if a series has been settled.
function isSettled(bytes32 seriesId) external view returns (bool)canTrade
Checks if a series can be traded.
function canTrade(bytes32 seriesId) external view returns (bool)Returns true if:
- Series doesn't exist yet (will be created on first trade), OR
- Series exists AND not expired AND not settled
computeSeriesId
Computes the series ID from parameters.
function computeSeriesId(bytes32 pairId, uint256 strike, uint256 expiry, bool isCall)
external pure returns (bytes32)validateSeriesId
Validates that a series ID matches its parameters.
function validateSeriesId(bytes32 seriesId, SeriesParams calldata params)
external pure returns (bool)Owner Functions
setOperator
Authorizes or deauthorizes an operator.
function setOperator(address operator, bool authorized) external onlyOwnerEmits: OperatorUpdated
setMinTimeToExpiry
Sets the minimum time to expiry for new series.
function setMinTimeToExpiry(uint256 _minTimeToExpiry) external onlyOwnerDefault: MIN_TIME_TO_EXPIRY from Constants (1 hour)
setPriceHistory
Sets the price history contract for TWAP settlement.
function setPriceHistory(address priceHistory_) external onlyOwnerEmits: PriceHistoryUpdated
transferOwnership
Transfers contract ownership.
function transferOwnership(address newOwner) external onlyOwnerEmits: OwnershipTransferred
Events
| Event | Parameters | Description |
|---|---|---|
SeriesCreated | seriesId, pairId, strike, expiry, isCall | New series created |
SeriesSettled | seriesId, settlementPrice, snapshotCount | Series settlement completed |
SettlementFallbackUsed | seriesId | No TWAP snapshots available |
OperatorUpdated | operator, authorized | Operator status changed |
PriceHistoryUpdated | oldPriceHistory, newPriceHistory | Price history contract changed |
MinTimeToExpiryUpdated | oldMinTime, newMinTime | Minimum time to expiry changed |
OwnershipTransferred | previousOwner, newOwner | Ownership changed |
Integration Points
Depends On
| Contract | Purpose |
|---|---|
| DiffusalPriceHistory | TWAP for settlement |
Used By
| Contract | Purpose |
|---|---|
| DiffusalOptionsOrderBook | Series validation on order fill |
| DiffusalOptionsRFQ | Series validation on RFQ fill |
| DiffusalSettlementEngine | Settlement price lookup |
| DiffusalCollateralVault | Series info for margin calculations |
Security Considerations
Series ID Validation
Every trade validates that the provided seriesId matches the computed hash:
if (_computeSeriesIdFromParams(p) != seriesId) revert Errors.InvalidSeriesId();This prevents:
- Trading non-existent series with arbitrary IDs
- Parameter mismatches between order and series
Minimum Time to Expiry
New series must have sufficient time until expiry:
if (p.optionExpiry < block.timestamp + $.minTimeToExpiry) {
revert Errors.OptionExpiryTooSoon();
}This ensures:
- Adequate time for position management
- Prevention of near-expiry manipulation
Settlement Security
TWAP-based settlement provides:
- Resistance to single-block price manipulation
- Fair settlement price based on historical data
- Permissionless triggering (no admin bottleneck)
Code Reference
Source: packages/contracts/src/DiffusalOptionsSeriesRegistry.sol
Interface: packages/contracts/src/interfaces/IDiffusalOptionsSeriesRegistry.sol
Testnet: View on MonadVision
Key Constants
// From Constants.sol
uint256 constant MIN_TIME_TO_EXPIRY = 1 hours;Related
- Options Creation (Protocol) — Series creation mechanics
- Options Settlement (Protocol) — Settlement process
- DiffusalPriceHistory — TWAP data source
- DiffusalSettlementEngine — Position settlement