Architecture
Challenge4Trading is built as a hybrid trading stack:
- onchain contracts hold core trading state, collateral accounting, fees, and pool logic
- oracle and pricing contracts validate market data and quote execution prices
- backend workers continuously monitor orders, positions, price freshness, and auto-close conditions
The goal of this architecture is straightforward: keep user execution coherent, keep liquidation logic deterministic, and protect the pool from avoidable price or accounting errors.
High-Level Components
1. Perp core contract
The core perp system stores and enforces:
- assets and market configuration
- open positions
- pending orders
- collateral balances
- fee settings
- pool balance and exposure tracking
- keeper and one-click permissions
Core production references:
- Perp core:
0x54A62D550e1754f3bB34ad80501A63815297Fccc - See also: Contracts
2. Oracle router
The oracle router is responsible for validating price updates before they are accepted as usable protocol prices.
3. Pricing engine
The pricing engine turns a validated base price into an execution price by applying:
- spread
- skew
- volatility adjustment
- impact based on requested size versus available liquidity
4. Lens and backend services
Lens and backend workers support:
- risk inspection
- auto-close checks
- order execution
- market snapshots
- price freshness monitoring
Onchain Modules
The current contract system is split into focused modules:
PerpAssetModulePerpRiskModulePerpPriceModulePerpPoolModulePerpTradeModulePerpKeeperModulePerpLensOracleRouterOracleConfigPricingEngine
This separation matters because it makes responsibilities easier to reason about:
- asset and leverage settings are not mixed with keeper execution
- pool accounting is not mixed with oracle validation
- pricing logic is isolated from trade state storage
Open Trades and Orders
Challenge4Trading supports both immediate position opening and pending order workflows.
Direct position opening
When a trader opens a position, the core trade module checks:
- the asset is enabled
- collateral is greater than zero
- requested leverage is within the asset cap
- relay fee is within the configured maximum
- TP and SL are logically consistent with trade direction
- resulting collateral remains above maintenance margin
The protocol then:
- transfers collateral
- calculates open fees and fixed opening fees
- computes the resulting net collateral and final notional size
- derives entry price from oracle price plus spread logic
- stores the position only if maintenance margin is still respected
Pending orders
Orders are stored separately from open positions and contain:
- trader
- asset
- side
- leverage
- collateral
- target price
- order type
- TP / SL
- slippage limit
- optional expiry
The order executor service only executes an order when:
- the order is still active
- it has not expired
- its trigger condition is met against the current market price
That prevents the system from silently opening trades on stale or invalid conditions.
Price Verification with Pyth
The price security model is one of the most important parts of the system.
Validation path
For a market to be priced, the oracle router requires:
- a configured Pyth price ID
- an active asset configuration
- the market not to be paused
When updates are submitted:
- the router calculates the required Pyth fee
- applies the update payload
- validates the returned price
- stores the last accepted validated price
Staleness checks
The router rejects prices that are:
- missing
- non-positive
- older than the configured
pythMaxAge
That prevents execution on stale market data.
Confidence checks
Even if the price is fresh, the router also checks Pyth confidence bounds. If confidence is too wide relative to price, the update is rejected.
Chainlink sanity checks
If a Chainlink feed is configured for the market, the router also verifies:
- Chainlink data is fresh enough
- Chainlink answer is valid
- Pyth and Chainlink do not deviate beyond the configured maximum
This creates a second validation layer before a Pyth price is accepted.
Fallback behaviour
There are two important fallback ideas in the system:
-
core oracle fallback The core perp pricing module still supports a primary oracle plus a fallback oracle path for price reads at the contract level.
-
router realignment path The oracle router has an owner-only
forceRealignPriceX30path that can ignore deviation checks while still preserving freshness and confidence checks. This is useful for controlled operational recovery if the last accepted reference becomes desynchronized.
The system does not blindly accept any fallback price. Freshness, positivity, and configuration checks still apply.
Execution Price and Slippage Protection
Validated price does not automatically mean executable price. Execution pricing is handled separately.
Pricing engine
The pricing engine starts from a validated base price and then applies:
- base spread
- skew premium
- volatility factor
- size impact
This produces the quoted execution price that better reflects actual trading conditions than a raw oracle mid-price alone.
User slippage controls
The core trade module also enforces:
- a global slippage ceiling
- a user-provided max slippage
If the difference is too high, the trade reverts.
This protects traders from accepting execution outside the tolerance they selected.
Fees
The fee system is explicit and split by purpose.
Opening fees
Opening fees can include:
openFeeBpsoracleFeeUsdconeClickOpenFeeUsdc- optional relay fee for one-click flows
The open fee is calculated on the final position size, not simply on gross collateral input. That means the system first removes fixed fees, then computes the open fee and resulting notional size coherently.
Closing fees
Closing a trade applies:
closeFeeBps
Liquidation fees
When a position is liquidated, the liquidation fee path is separate and visible in protocol accounting.
Rollover fees
Rollover is accumulated over time using:
- long-side rate
- short-side rate
- rollover interval
This means holding a position over time can change its effective net equity and therefore affect liquidation distance.
Auto-Close, Liquidation, and Monitoring Services
Challenge4Trading does not rely on a single passive process. Several workers are used to keep the system responsive.
Pyth updater
The Pyth updater worker:
- refreshes oracle-router prices from Hermes/Pyth
- updates market price records used by backend monitoring
- works in batch mode with single-asset fallback if batch refresh fails
- skips fully stale situations instead of forcing bad updates
It also evaluates near-trigger conditions so operational attention can focus on markets close to TP, SL, liquidation, or max-PnL thresholds.
Order executor
The order executor worker:
- scans active orders
- groups them by asset
- refreshes the relevant price payload
- checks expiry
- checks whether the trigger price condition is actually met
- executes only the orders that are ready
If the trigger is not met, the order is explicitly skipped rather than forced.
Keeper
The keeper worker scans open positions and checks auto-close eligibility through the lens.
It can close a position when one of the protocol-defined reasons is reached:
- TP hit
- SL hit
- max-loss threshold reached
- max-PnL cap reached
- liquidation condition reached
The lens returns a reason code so the worker is not guessing. The keeper then executes close or liquidation using current pricing data and a controlled max slippage setting.
Worker health and operational visibility
The backend also tracks:
- worker heartbeats
- gas cost recording
- per-trade execution checks
- market-price snapshots
This helps operators detect stale services or abnormal execution behaviour early.
Pool Protection
Pool protection is built into both the pricing model and the accounting model.
Exposure and utilization tracking
The protocol tracks:
- pool balance
- total exposure per asset
- pool utilization
These values feed directly into spread and risk logic.
Dynamic spread
Spread is not static. It can widen based on:
- utilization
- configured asset volatility
- directional skew
This means the protocol can become more conservative when one side of the book or the pool becomes riskier.
Payout caps
The protocol uses a maxPnlMultiple cap in several paths. This helps bound payout behaviour relative to collateral and reduces the chance of the pool absorbing extreme asymmetric outcomes in a single position.
Pool sufficiency checks
Before payouts are made, the system checks whether the pool can support them. Partial closes also re-check that the remaining position would still be healthy after the change.
Keeper emergency pause
The keeper has a dedicated keeperPauseIfPoolUnder path. If the pool falls below a required threshold and keeper pause is allowed, the system can be paused rather than continuing in a degraded state.
Trader Protection
Several protections are designed specifically for the trader side of the system.
Self-custody
Users keep control of their wallet and signatures.
Bounded leverage
Each asset has its own max leverage cap.
TP / SL validity rules
TP and SL values are validated against trade direction and entry logic.
Maintenance margin enforcement
Positions are not opened if the resulting collateral would already sit below maintenance margin.
Safe collateral removal
Removing collateral is checked against live equity so a user cannot withdraw collateral in a way that would immediately make the position unsafe.
Why This Matters
No leveraged trading system is risk-free. What matters is whether the protocol has clear, layered controls rather than a single optimistic path.
Challenge4Trading uses multiple layers:
- validated price sources
- deviation and staleness controls
- execution price adjustment
- explicit fee accounting
- maintenance margin checks
- automated order and close services
- pool-aware spread and payout controls
- pause and operational recovery paths
That combination is what makes the architecture understandable and defendable from both a trader-safety and pool-safety perspective.