ADR 001: Scalable Architecture & Batch Market Updates¶
Status: Accepted
Date: 2025-12-23
Deciders: Development Team
Technical Story: Issue: Scalable Architecture & Batch Market Updates for High-Traffic Scenarios
Executive Summary¶
This document outlines the scalable architecture design for the ClearPath & FairWins prediction market platform, with specific focus on batch processing capabilities, enhanced event structures, and efficient market discovery mechanisms to support high-traffic scenarios and explosive growth.
Context¶
The application is preparing for potential explosive growth and needs proactive scalability measures. Current system limitations include: - Individual transaction processing leading to high gas costs - No batch processing capabilities for markets or positions - Limited event indexing making market discovery inefficient - Sequential operations creating bottlenecks at scale
This ADR documents the architectural decisions to address these limitations and enable 100-1000x growth in concurrent markets.
Table of Contents¶
- Current System Analysis
- Scalability Challenges
- Batch Processing Architecture
- Enhanced Event Structure
- Market Discovery & Lookup API
- Gas Optimization Strategies
- Implementation Roadmap
- Performance Benchmarks
Current System Analysis¶
Architecture Overview¶
The current system consists of several key components:
- FutarchyGovernor: Main coordination layer
- ProposalRegistry: Proposal submission and management
- ConditionalMarketFactory: Market deployment and resolution
- PrivacyCoordinator: Encrypted position management
- OracleResolver: Multi-stage oracle resolution
- WelfareMetricRegistry: Welfare metrics tracking
- RagequitModule: Minority protection
Current Limitations¶
1. Throughput Constraints¶
| Operation | Current Design | Limitation | Impact at Scale |
|---|---|---|---|
| Market Creation | One-by-one deployment | ~200k gas per market | 5 markets = 1M gas |
| Position Updates | Individual submissions | ~100k gas per position | 10 positions = 1M gas |
| Market Resolution | Sequential processing | ~150k gas per market | High latency |
| Event Querying | No pagination | Full scan required | O(n) complexity |
2. State Storage Inefficiencies¶
- Current: Each market stored in separate mapping slot
- Issue: High storage costs (20,000 gas for new slot)
- Impact: Linear cost increase with market count
3. Event Discovery Challenges¶
- Current: Basic events without comprehensive indexing
- Issue: Off-chain indexers must process all blocks
- Impact: Slow market discovery, poor UX at scale
4. Memory-Bound Operations¶
- Current: Loading full market state for each operation
- Issue: Block gas limit constraints (30M gas on ETC)
- Impact: Max ~150 markets processable in single transaction
Scalability Challenges¶
1. High-Traffic Scenarios¶
Expected Growth Pattern: - Launch: 10-50 markets/day - 6 months: 100-500 markets/day - 1 year: 1,000+ markets/day - Peak: 10,000+ concurrent markets
Challenges: - Block space competition - Gas price volatility - State bloat - Query performance degradation
2. Cost Efficiency Requirements¶
Target Metrics: - Market creation: <100k gas - Batch operations: <50k gas per item - Position updates: <30k gas per position - Query operations: <10k gas
3. User Experience Requirements¶
- Market discovery: <2 seconds
- Position updates: <5 seconds
- Historical data: <3 seconds
- Real-time updates: <1 second latency
Batch Processing Architecture¶
Design Principles¶
- Atomic Batch Execution: All-or-nothing batch processing
- Gas Optimization: Minimize storage operations
- Failure Isolation: Individual item failures don't block batch
- Transparent Logging: Comprehensive event emission
1. Batch Market Creation¶
Interface Design¶
struct MarketCreationParams {
uint256 proposalId;
address collateralToken;
uint256 liquidityAmount;
uint256 liquidityParameter;
uint256 tradingPeriod;
}
function batchDeployMarkets(
MarketCreationParams[] calldata params
) external onlyOwner returns (uint256[] memory marketIds);
Implementation Strategy¶
Optimizations: 1. Shared Storage Slots: Pack related data together 2. Calldata over Memory: Use calldata for input arrays 3. Pre-allocation: Reserve storage slots in batch 4. Event Batching: Single event for multiple markets
Gas Savings: - Single call: ~200k gas per market - Batch (10 markets): ~120k gas per market (40% savings) - Batch (50 markets): ~100k gas per market (50% savings)
Example Event Structure¶
event BatchMarketsCreated(
uint256[] indexed marketIds,
uint256[] proposalIds,
uint256 batchTimestamp,
uint256 totalMarketsCreated
);
event MarketCreatedInBatch(
uint256 indexed marketId,
uint256 indexed proposalId,
uint256 indexed batchId,
address passToken,
address failToken,
uint256 tradingEndTime
);
2. Batch Position Updates¶
Current Flow (Inefficient)¶
User 1 → Submit Position 1 → Process → Event
User 2 → Submit Position 2 → Process → Event
User 3 → Submit Position 3 → Process → Event
Total: 3 transactions, 3 × 100k = 300k gas
Optimized Flow (Batch Processing)¶
User 1, 2, 3 → Submit to Buffer
Coordinator → Process Batch [1,2,3] → Single Event
Total: 1 coordinator transaction, ~150k gas (50% savings)
Implementation Strategy¶
Privacy Coordinator Enhancement:
struct BatchPositionUpdate {
uint256[] positionIds;
bytes32[] commitments;
bytes[] zkProofs;
uint256 batchTimestamp;
}
function processBatchPositions(
BatchPositionUpdate calldata batch
) external onlyCoordinator returns (bool);
Optimizations: 1. Commitment Batching: Process multiple commitments in single call 2. Proof Aggregation: Use batch ZK proof verification 3. Epoch Consolidation: Process full epochs atomically 4. Storage Packing: Pack position metadata efficiently
Gas Savings: - Single position: ~100k gas - Batch (10 positions): ~40k gas per position (60% savings) - Batch (50 positions): ~25k gas per position (75% savings)
3. Batch Market Resolution¶
Interface Design¶
struct MarketResolutionParams {
uint256 marketId;
uint256 passValue;
uint256 failValue;
}
function batchResolveMarkets(
MarketResolutionParams[] calldata params
) external onlyOwner returns (bool[] memory results);
Implementation Strategy¶
Features: 1. Parallel Processing: Resolve independent markets together 2. Failure Handling: Continue on individual failures 3. Result Tracking: Return success/failure for each market 4. Event Emission: Emit both batch and individual events
Gas Savings: - Single resolution: ~150k gas - Batch (10 resolutions): ~100k gas each (33% savings) - Batch (25 resolutions): ~80k gas each (47% savings)
Enhanced Event Structure¶
Design Principles¶
- Comprehensive Indexing: Index all query-relevant fields
- Hierarchical Events: Both summary and detail events
- Timestamp Precision: Block number + timestamp for all events
- Status Tracking: Emit events for all state transitions
1. Market Lifecycle Events¶
Enhanced Event Schema¶
// Market creation with full context
event MarketCreated(
uint256 indexed marketId,
uint256 indexed proposalId,
address indexed collateralToken,
address passToken,
address failToken,
uint256 tradingEndTime,
uint256 liquidityParameter,
uint256 createdAt,
address creator
);
// Market status transitions
event MarketStatusChanged(
uint256 indexed marketId,
MarketStatus indexed previousStatus,
MarketStatus indexed newStatus,
uint256 changedAt,
address changedBy
);
// Trading activity
event MarketTrade(
uint256 indexed marketId,
address indexed trader,
bool indexed isPassToken,
uint256 amount,
uint256 price,
uint256 timestamp,
uint256 newPassPrice,
uint256 newFailPrice
);
// Market resolution with outcomes
event MarketResolved(
uint256 indexed marketId,
uint256 indexed proposalId,
uint256 passValue,
uint256 failValue,
bool indexed approved,
uint256 resolvedAt,
address resolver
);
// Market cancellation
event MarketCancelled(
uint256 indexed marketId,
uint256 indexed proposalId,
string reason,
uint256 cancelledAt,
address cancelledBy
);
2. Position Management Events¶
// Position submission
event PositionSubmitted(
uint256 indexed positionId,
address indexed user,
uint256 indexed marketId,
bytes32 commitment,
uint256 epoch,
uint256 timestamp
);
// Batch position processing
event BatchPositionsProcessed(
uint256 indexed batchId,
uint256 indexed epochId,
uint256[] positionIds,
uint256 processedCount,
uint256 timestamp
);
// Position settlement
event PositionSettled(
uint256 indexed positionId,
address indexed user,
uint256 indexed marketId,
uint256 payout,
uint256 timestamp
);
3. Proposal Lifecycle Events¶
// Enhanced proposal submission
event ProposalSubmitted(
uint256 indexed proposalId,
address indexed proposer,
string title,
uint256 fundingAmount,
address indexed fundingToken,
uint256 welfareMetricId,
uint256 bondAmount,
uint256 submittedAt,
uint256 reviewEndsAt,
uint256 executionDeadline
);
// Phase transitions
event ProposalPhaseChanged(
uint256 indexed proposalId,
ProposalPhase indexed previousPhase,
ProposalPhase indexed newPhase,
uint256 changedAt
);
// Execution tracking
event ProposalExecuted(
uint256 indexed proposalId,
address indexed recipient,
uint256 amount,
address indexed fundingToken,
uint256 executedAt,
bytes32 txHash
);
4. Aggregate Statistics Events¶
// Daily statistics
event DailyStatistics(
uint256 indexed date,
uint256 marketsCreated,
uint256 marketsResolved,
uint256 totalVolume,
uint256 uniqueTraders,
uint256 totalPositions
);
// Market metrics snapshot
event MarketMetricsSnapshot(
uint256 indexed marketId,
uint256 indexed timestamp,
uint256 totalVolume,
uint256 totalLiquidity,
uint256 passPrice,
uint256 failPrice,
uint256 uniqueTraders
);
Market Discovery & Lookup API¶
Design Goals¶
- Fast Queries: O(1) or O(log n) complexity
- Flexible Filtering: Multiple filter criteria
- Pagination Support: Handle large result sets
- Efficient Indexing: Minimize gas costs
1. On-Chain Query Functions¶
Market Discovery¶
/**
* @notice Get active markets with pagination
* @param offset Starting index
* @param limit Maximum results to return
* @return marketIds Array of market IDs
* @return hasMore Whether more results exist
*/
function getActiveMarkets(
uint256 offset,
uint256 limit
) external view returns (
uint256[] memory marketIds,
bool hasMore
);
/**
* @notice Get markets by status with filtering
* @param status Market status to filter by
* @param minLiquidity Minimum liquidity threshold
* @param offset Starting index
* @param limit Maximum results
* @return markets Array of market data
*/
function getMarketsByStatus(
MarketStatus status,
uint256 minLiquidity,
uint256 offset,
uint256 limit
) external view returns (Market[] memory markets);
/**
* @notice Get markets for a specific proposal
* @param proposalId Proposal ID
* @return marketId Associated market ID
* @return market Market details
*/
function getMarketForProposal(
uint256 proposalId
) external view returns (
uint256 marketId,
Market memory market
);
/**
* @notice Get markets by date range
* @param startTime Start timestamp
* @param endTime End timestamp
* @param offset Starting index
* @param limit Maximum results
* @return marketIds Array of market IDs in range
*/
function getMarketsByDateRange(
uint256 startTime,
uint256 endTime,
uint256 offset,
uint256 limit
) external view returns (uint256[] memory marketIds);
Market Statistics¶
/**
* @notice Get market statistics
* @param marketId Market ID
* @return volume Total trading volume
* @return liquidity Current liquidity
* @return traderCount Number of unique traders
* @return positionCount Total positions
*/
function getMarketStatistics(
uint256 marketId
) external view returns (
uint256 volume,
uint256 liquidity,
uint256 traderCount,
uint256 positionCount
);
/**
* @notice Get global platform statistics
* @return totalMarkets Total markets created
* @return activeMarkets Currently active markets
* @return totalVolume Lifetime trading volume
* @return totalTraders Unique trader count
*/
function getPlatformStatistics() external view returns (
uint256 totalMarkets,
uint256 activeMarkets,
uint256 totalVolume,
uint256 totalTraders
);
User Position Queries¶
/**
* @notice Get user positions across all markets
* @param user User address
* @param offset Starting index
* @param limit Maximum results
* @return positionIds Array of position IDs
* @return markets Associated market IDs
*/
function getUserPositions(
address user,
uint256 offset,
uint256 limit
) external view returns (
uint256[] memory positionIds,
uint256[] memory markets
);
/**
* @notice Get user position in specific market
* @param user User address
* @param marketId Market ID
* @return hasPosition Whether user has position
* @return positionId Position ID if exists
* @return value Current position value
*/
function getUserMarketPosition(
address user,
uint256 marketId
) external view returns (
bool hasPosition,
uint256 positionId,
uint256 value
);
2. Indexing Strategy¶
Storage Optimization¶
// Market status tracking for fast filtering
mapping(MarketStatus => uint256[]) private marketsByStatus;
// Time-based indexing for date range queries
mapping(uint256 => uint256[]) private marketsByDay; // day => market IDs
// User position tracking
mapping(address => uint256[]) private userPositionIds;
mapping(address => mapping(uint256 => uint256)) private userMarketPosition;
// Pagination metadata
struct PaginationInfo {
uint256 totalCount;
uint256 pageSize;
uint256 lastUpdated;
}
mapping(MarketStatus => PaginationInfo) public statusPagination;
Efficient Updates¶
/**
* @notice Update market index on status change
* @dev Called internally on status transitions
*/
function _updateMarketIndex(
uint256 marketId,
MarketStatus oldStatus,
MarketStatus newStatus
) internal {
// Remove from old status index
_removeFromStatusIndex(marketId, oldStatus);
// Add to new status index
_addToStatusIndex(marketId, newStatus);
// Update time-based index
uint256 day = block.timestamp / 1 days;
marketsByDay[day].push(marketId);
}
3. Off-Chain Indexing Support¶
Event Indexing Schema¶
Recommended Database Schema:
-- Markets table
CREATE TABLE markets (
market_id BIGINT PRIMARY KEY,
proposal_id BIGINT,
collateral_token VARCHAR(42),
pass_token VARCHAR(42),
fail_token VARCHAR(42),
trading_end_time TIMESTAMP,
liquidity_parameter NUMERIC,
status VARCHAR(20),
created_at TIMESTAMP,
resolved_at TIMESTAMP,
pass_value NUMERIC,
fail_value NUMERIC
);
CREATE INDEX idx_markets_status ON markets(status);
CREATE INDEX idx_markets_created_at ON markets(created_at);
CREATE INDEX idx_markets_proposal ON markets(proposal_id);
-- Positions table
CREATE TABLE positions (
position_id BIGINT PRIMARY KEY,
user_address VARCHAR(42),
market_id BIGINT,
commitment BYTEA,
epoch BIGINT,
submitted_at TIMESTAMP,
processed BOOLEAN,
settled BOOLEAN
);
CREATE INDEX idx_positions_user ON positions(user_address);
CREATE INDEX idx_positions_market ON positions(market_id);
CREATE INDEX idx_positions_epoch ON positions(epoch);
-- Trades table
CREATE TABLE trades (
trade_id SERIAL PRIMARY KEY,
market_id BIGINT,
trader_address VARCHAR(42),
is_pass_token BOOLEAN,
amount NUMERIC,
price NUMERIC,
timestamp TIMESTAMP,
block_number BIGINT,
tx_hash VARCHAR(66)
);
CREATE INDEX idx_trades_market ON trades(market_id);
CREATE INDEX idx_trades_trader ON trades(trader_address);
CREATE INDEX idx_trades_timestamp ON trades(timestamp);
-- Market statistics (materialized view)
CREATE MATERIALIZED VIEW market_stats AS
SELECT
market_id,
COUNT(DISTINCT trader_address) as unique_traders,
SUM(amount) as total_volume,
MAX(timestamp) as last_trade_time
FROM trades
GROUP BY market_id;
GraphQL API Schema¶
type Market {
id: ID!
proposalId: Int!
collateralToken: String!
passToken: String!
failToken: String!
tradingEndTime: DateTime!
liquidityParameter: BigInt!
status: MarketStatus!
createdAt: DateTime!
resolvedAt: DateTime
passValue: BigInt
failValue: BigInt
statistics: MarketStatistics!
trades(first: Int, skip: Int): [Trade!]!
}
type MarketStatistics {
totalVolume: BigInt!
uniqueTraders: Int!
currentPassPrice: BigInt!
currentFailPrice: BigInt!
totalLiquidity: BigInt!
}
enum MarketStatus {
ACTIVE
TRADING_ENDED
RESOLVED
CANCELLED
}
type Query {
market(id: ID!): Market
markets(
status: MarketStatus
minLiquidity: BigInt
first: Int = 20
skip: Int = 0
orderBy: MarketOrderBy = CREATED_AT
orderDirection: OrderDirection = DESC
): [Market!]!
userPositions(
user: String!
first: Int = 20
skip: Int = 0
): [Position!]!
platformStatistics: PlatformStatistics!
}
type PlatformStatistics {
totalMarkets: Int!
activeMarkets: Int!
totalVolume: BigInt!
uniqueTraders: Int!
last24hVolume: BigInt!
}
REST API Specification¶
openapi: 3.0.0
info:
title: Prediction Market Lookup API
version: 1.0.0
description: RESTful API for market discovery and querying
paths:
/markets:
get:
summary: List markets with filtering and pagination
parameters:
- name: status
in: query
schema:
type: string
enum: [active, trading_ended, resolved, cancelled]
- name: min_liquidity
in: query
schema:
type: integer
- name: offset
in: query
schema:
type: integer
default: 0
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: List of markets
content:
application/json:
schema:
type: object
properties:
markets:
type: array
items:
$ref: '#/components/schemas/Market'
pagination:
$ref: '#/components/schemas/Pagination'
/markets/{marketId}:
get:
summary: Get market details
parameters:
- name: marketId
in: path
required: true
schema:
type: integer
responses:
'200':
description: Market details
content:
application/json:
schema:
$ref: '#/components/schemas/Market'
/markets/{marketId}/statistics:
get:
summary: Get market statistics
parameters:
- name: marketId
in: path
required: true
schema:
type: integer
responses:
'200':
description: Market statistics
content:
application/json:
schema:
$ref: '#/components/schemas/MarketStatistics'
/users/{address}/positions:
get:
summary: Get user positions
parameters:
- name: address
in: path
required: true
schema:
type: string
- name: offset
in: query
schema:
type: integer
default: 0
- name: limit
in: query
schema:
type: integer
default: 20
responses:
'200':
description: User positions
content:
application/json:
schema:
type: object
properties:
positions:
type: array
items:
$ref: '#/components/schemas/Position'
pagination:
$ref: '#/components/schemas/Pagination'
components:
schemas:
Market:
type: object
properties:
id:
type: integer
proposalId:
type: integer
collateralToken:
type: string
passToken:
type: string
failToken:
type: string
tradingEndTime:
type: string
format: date-time
status:
type: string
liquidityParameter:
type: string
statistics:
$ref: '#/components/schemas/MarketStatistics'
MarketStatistics:
type: object
properties:
totalVolume:
type: string
uniqueTraders:
type: integer
currentPassPrice:
type: string
currentFailPrice:
type: string
totalLiquidity:
type: string
Position:
type: object
properties:
id:
type: integer
marketId:
type: integer
userAddress:
type: string
commitment:
type: string
submittedAt:
type: string
format: date-time
Pagination:
type: object
properties:
offset:
type: integer
limit:
type: integer
total:
type: integer
hasMore:
type: boolean
Gas Optimization Strategies¶
1. Storage Optimization¶
Packed Structs¶
// Before: 5 storage slots
struct Market {
uint256 proposalId; // slot 0
uint256 tradingEndTime; // slot 1
uint256 liquidityParameter; // slot 2
address passToken; // slot 3
address failToken; // slot 4
}
// Cost: 5 × 20,000 = 100,000 gas
// After: 3 storage slots
struct Market {
uint256 proposalId; // slot 0
uint256 tradingEndTime; // slot 1
uint256 liquidityParameter; // slot 2 (first 128 bits)
address passToken; // slot 2 (96 bits)
address failToken; // slot 3 (160 bits)
bool resolved; // slot 3 (8 bits)
}
// Cost: 3 × 20,000 = 60,000 gas
// Savings: 40,000 gas (40%)
Use Events for Historical Data¶
// Don't store historical trades on-chain
// Instead, emit events and index off-chain
event MarketTrade(
uint256 indexed marketId,
address indexed trader,
uint256 amount,
uint256 price,
uint256 timestamp
);
// Only store current state
mapping(uint256 => uint256) public currentPassPrice;
mapping(uint256 => uint256) public currentFailPrice;
2. Computation Optimization¶
Avoid Repeated Calculations¶
// Before: Recalculate on every access
function getMarketPrice(uint256 marketId) public view returns (uint256) {
uint256 passQty = passTokens[marketId];
uint256 failQty = failTokens[marketId];
uint256 beta = liquidityParams[marketId];
// Complex LMSR calculation...
return calculatePrice(passQty, failQty, beta);
}
// After: Cache calculated values
mapping(uint256 => uint256) private cachedPassPrices;
mapping(uint256 => uint256) private cachedFailPrices;
function updateMarketPrice(uint256 marketId) internal {
(uint256 passPrice, uint256 failPrice) = calculatePrices(marketId);
cachedPassPrices[marketId] = passPrice;
cachedFailPrices[marketId] = failPrice;
}
Use Unchecked Math Where Safe¶
// Safe to use unchecked when overflow impossible
function _addToArray(uint256[] storage arr, uint256 value) internal {
uint256 len = arr.length;
arr.push(value);
unchecked {
// Length can never overflow in practice
assert(arr.length == len + 1);
}
}
3. Calldata vs Memory¶
// Use calldata for read-only arrays (saves ~3 gas per word)
function batchProcess(
uint256[] calldata ids, // Use calldata
uint256[] calldata values // Use calldata
) external {
// Process without copying to memory
for (uint256 i = 0; i < ids.length; ) {
_process(ids[i], values[i]);
unchecked { ++i; }
}
}
4. Short-Circuit Evaluation¶
// Order checks from cheapest to most expensive
function validateMarket(uint256 marketId) public view returns (bool) {
// Check storage first (cheapest)
if (marketId >= marketCount) return false;
// Then check mapping
Market storage market = markets[marketId];
if (market.status != MarketStatus.Active) return false;
// Finally check timestamp (external call potential)
if (block.timestamp < market.tradingEndTime) return false;
return true;
}
5. Batch Storage Updates¶
// Instead of multiple SSTORE operations
function updateMarketsSequential(uint256[] calldata ids) external {
for (uint256 i = 0; i < ids.length; i++) {
markets[ids[i]].status = MarketStatus.Resolved; // Multiple SSTOREs
}
}
// Use single SSTORE by updating memory first
function updateMarketsBatch(uint256[] calldata ids) external {
for (uint256 i = 0; i < ids.length; i++) {
Market storage market = markets[ids[i]];
market.status = MarketStatus.Resolved;
market.resolvedAt = block.timestamp;
market.passValue = passValues[i];
market.failValue = failValues[i];
// All updates in single storage slot access pattern
}
}
Implementation Roadmap¶
Phase 1: Foundation (Weeks 1-2)¶
Week 1: Contract Enhancements¶
- Add batch market creation to ConditionalMarketFactory
- Implement storage packing for Market struct
- Add comprehensive event structure
- Create pagination helper functions
- Write unit tests for batch operations
Week 2: Indexing Infrastructure¶
- Implement status-based indexing
- Add time-based market tracking
- Create user position tracking
- Add pagination metadata
- Write integration tests
Deliverables: - Updated ConditionalMarketFactory contract - Enhanced event definitions - Test coverage >90% - Gas optimization report
Phase 2: Batch Processing (Weeks 3-4)¶
Week 3: Position Batching¶
- Enhance PrivacyCoordinator for batch processing
- Implement batch position submission
- Add batch ZK proof verification
- Create epoch consolidation logic
- Write fuzz tests
Week 4: Resolution Batching¶
- Add batch resolution to ConditionalMarketFactory
- Implement failure handling
- Add batch events
- Create monitoring tools
- Performance testing
Deliverables: - Batch-enabled PrivacyCoordinator - Batch resolution functionality - Performance benchmarks - Gas comparison analysis
Phase 3: Query API (Weeks 5-6)¶
Week 5: On-Chain Queries¶
- Implement getActiveMarkets with pagination
- Add getMarketsByStatus filtering
- Create market statistics functions
- Add user position queries
- Write view function tests
Week 6: Off-Chain Support¶
- Design database schema
- Create GraphQL API specification
- Document REST API endpoints
- Build example indexer
- Write integration guide
Deliverables: - Complete query function library - Database schema documentation - API specifications - Example indexer implementation
Phase 4: Optimization & Testing (Weeks 7-8)¶
Week 7: Gas Optimization¶
- Profile gas usage across operations
- Implement identified optimizations
- Benchmark before/after
- Document savings
- Update cost projections
Week 8: Security & Testing¶
- Security audit preparation
- Comprehensive test suite
- Fuzzing campaign
- Load testing
- Documentation review
Deliverables: - Optimized contract suite - Security audit report - Load test results - Complete documentation
Phase 5: Deployment & Monitoring (Weeks 9-10)¶
Week 9: Testnet Deployment¶
- Deploy to Mordor testnet
- Run integration tests
- Monitor performance
- Gather community feedback
- Fix identified issues
Week 10: Production Preparation¶
- Mainnet deployment plan
- Monitoring dashboard
- Alerting setup
- Documentation finalization
- Training materials
Deliverables: - Testnet deployment - Monitoring infrastructure - Deployment documentation - Operator training
Performance Benchmarks¶
Expected Performance Improvements¶
Gas Costs¶
| Operation | Current | Optimized | Savings |
|---|---|---|---|
| Create 1 Market | 200k | 200k | 0% |
| Create 10 Markets | 2.0M | 1.2M | 40% |
| Create 50 Markets | 10M | 5.0M | 50% |
| Update 1 Position | 100k | 100k | 0% |
| Update 10 Positions | 1.0M | 400k | 60% |
| Update 50 Positions | 5.0M | 1.25M | 75% |
| Resolve 1 Market | 150k | 150k | 0% |
| Resolve 10 Markets | 1.5M | 1.0M | 33% |
| Resolve 25 Markets | 3.75M | 2.0M | 47% |
Query Performance¶
| Query Type | Current | Optimized | Improvement |
|---|---|---|---|
| Find Active Markets | O(n) scan | O(1) lookup | 100x faster |
| Market by ID | O(1) | O(1) | Same |
| Markets by Status | O(n) scan | O(m) where m=results | 10-100x faster |
| User Positions | O(n) scan | O(k) where k=user positions | 50-500x faster |
| Date Range Query | Not supported | O(d) where d=days | New feature |
Scalability Metrics¶
| Metric | Current Limit | Optimized Limit | Improvement |
|---|---|---|---|
| Markets per Day | 50 | 500+ | 10x |
| Concurrent Markets | 100 | 10,000+ | 100x |
| Positions per Epoch | 50 | 1,000+ | 20x |
| Query Response Time | 5-10s | <1s | 5-10x |
| Indexer Sync Time | 1 hour | 5 minutes | 12x |
Load Testing Scenarios¶
Scenario 1: High Market Creation Rate¶
Test: Create 100 markets in rapid succession
Expected:
- Gas: ~10M total (100k per market)
- Time: ~20 seconds (5 markets/second)
- Success Rate: >99%
Scenario 2: Heavy Trading Load¶
Test: 1000 position updates across 100 markets
Expected:
- Gas: ~25M total (25k per position)
- Time: ~3 minutes (batches of 50)
- Success Rate: >99.9%
Scenario 3: Mass Market Resolution¶
Test: Resolve 50 markets simultaneously
Expected:
- Gas: ~2M total (40k per market)
- Time: ~10 seconds
- Success Rate: 100%
Scenario 4: Query Performance¶
Test: 10,000 concurrent market lookups
Expected:
- Response Time: <100ms per query
- Throughput: >100 queries/second
- Cache Hit Rate: >90%
Risk Mitigation¶
Technical Risks¶
| Risk | Impact | Likelihood | Mitigation |
|---|---|---|---|
| Batch operation failure | High | Medium | Implement failure isolation |
| Gas limit exceeded | High | Low | Enforce batch size limits |
| Event indexing lag | Medium | Medium | Implement backfill mechanism |
| Query performance degradation | High | Medium | Add caching layer |
| Storage bloat | Medium | High | Use events for historical data |
Operational Risks¶
| Risk | Impact | Likelihood | Mitigation |
|---|---|---|---|
| Network congestion | Medium | High | Adaptive gas pricing |
| Coordinator downtime | High | Low | Automated failover |
| Database corruption | High | Low | Regular backups, replication |
| API rate limiting | Medium | Medium | CDN + caching |
Monitoring & Observability¶
Key Metrics to Track¶
Smart Contract Metrics¶
- Gas usage per operation type
- Batch sizes and success rates
- Failed transaction reasons
- Storage utilization
- Event emission rates
API Metrics¶
- Query response times (p50, p95, p99)
- Query throughput
- Error rates
- Cache hit rates
- Database query performance
Business Metrics¶
- Markets created per day
- Active markets count
- Trading volume
- Unique users
- Position update rate
Alerting Thresholds¶
alerts:
- name: high_gas_usage
condition: avg_gas > 200k
severity: warning
- name: batch_failure_rate
condition: failure_rate > 5%
severity: critical
- name: slow_queries
condition: p95_response_time > 2s
severity: warning
- name: indexer_lag
condition: blocks_behind > 100
severity: critical
- name: storage_growth
condition: daily_growth > 1GB
severity: warning
Conclusion¶
This scalability architecture provides a comprehensive roadmap for supporting high-traffic scenarios while maintaining cost efficiency and user experience. The batch processing mechanisms, enhanced event structures, and efficient query APIs will enable the platform to scale from hundreds to thousands of concurrent markets without degradation.
Key Benefits¶
- 40-75% gas savings through batch operations
- 10-100x faster queries with proper indexing
- 100x capacity increase in concurrent markets
- Comprehensive monitoring for proactive management
- Future-proof architecture for continued growth
Next Steps¶
- Review and approve architecture design
- Prioritize implementation phases
- Allocate development resources
- Begin Phase 1 implementation
- Set up continuous monitoring
For questions or clarifications, please refer to the specific sections above or contact the development team.