MiniApp Architecture

MiniApp Architecture Guide

This guide provides a comprehensive overview of how Based.One MiniApps work under the hood, including communication patterns, security models, and architectural decisions.

High-Level Architecture

System Overview

┌─────────────────────────────────────────────────────────────────────┐
│                        Based.One Terminal                          │
├─────────────────────────────────────────────────────────────────────┤
│  ┌───────────────┐  ┌─────────────────────────────────────────────┐ │
│  │   MiniApp     │  │           Core Systems                      │ │
│  │   Container   │  │                                             │ │
│  │               │  │  ┌─────────────┐  ┌─────────────────────────┐ │ │
│  │  ┌─────────┐  │◄─┤  │ Permission  │  │    Trading Engine       │ │ │
│  │  │Your App │  │  │  │ Manager     │  │                         │ │ │
│  │  │         │  │─►│  │             │  │ • Order Management      │ │ │
│  │  │         │  │  │  └─────────────┘  │ • Risk Controls         │ │ │
│  │  └─────────┘  │  │                   │ • Portfolio Tracking    │ │ │
│  │               │  │  ┌─────────────┐  │                         │ │ │
│  │  iframe       │  │  │ Market Data │  └─────────────────────────┘ │ │
│  │  sandbox      │  │◄─┤ Service     │                             │ │
│  │               │  │  │             │  ┌─────────────────────────┐ │ │
│  └───────────────┘  │  │ • WebSocket │  │   Account Service       │ │ │
│                     │  │ • REST API  │  │                         │ │ │
│                     │  │ • Caching   │  │ • Balance Management    │ │ │
│                     │  │             │  │ • Position Tracking     │ │ │
│                     │  └─────────────┘  │ • Transaction History   │ │ │
│                     │                   │                         │ │ │
│                     │                   └─────────────────────────┘ │ │
└─────────────────────────────────────────────────────────────────────┘

Communication Architecture

1. PostMessage Communication

MiniApps run in sandboxed iframes and communicate with the terminal via the PostMessage API:

// MiniApp to Terminal
window.parent.postMessage({
  type: 'MINIAPP_REQUEST',
  requestId: 'uuid-123',
  payload: {
    action: 'place_order',
    data: {
      symbol: 'ETH',
      side: 'buy',
      quantity: 0.1,
      type: 'market'
    }
  }
}, '*');

// Terminal to MiniApp
window.addEventListener('message', (event) => {
  if (event.data.type === 'MINIAPP_RESPONSE') {
    const { requestId, success, data, error } = event.data;
    // Handle response
  }
});

2. Message Flow Diagram

MiniApp                     Terminal                 Trading Engine
   │                           │                          │
   │ 1. place_order           │                          │
   ├─────────────────────────►│                          │
   │                           │ 2. validate_permissions  │
   │                           ├──────────────┐           │
   │                           │◄─────────────┘           │
   │                           │ 3. execute_order        │
   │                           ├─────────────────────────►│
   │                           │ 4. order_confirmation   │
   │ 5. order_response        │◄─────────────────────────┤
   │◄─────────────────────────┤                          │
   │                           │ 6. broadcast_update     │
   │ 7. market_data_update    │                          │
   │◄─────────────────────────┤                          │

3. Event-Driven Architecture

The SDK uses an event-driven pattern for real-time updates:

class SimpleMiniAppClient extends EventEmitter {
  constructor(config: SimpleConfig) {
    super();
    this.setupMessageHandlers();
  }

  private setupMessageHandlers() {
    window.addEventListener('message', (event) => {
      const { type, data } = event.data;
      
      switch (type) {
        case 'MARKET_DATA_UPDATE':
          this.emit('marketData', data);
          break;
        case 'ORDER_CONFIRMATION':
          this.emit('orderConfirmation', data);
          break;
        case 'ACCOUNT_UPDATE':
          this.emit('accountUpdate', data);
          break;
      }
    });
  }
}

Security Architecture

1. Permission Model

MiniApps operate under a strict permission-based security model:

interface PermissionScope {
  // Market data access
  market_data_read: boolean;
  
  // Trading permissions
  trading_read: boolean;      // View orders, positions
  trading_write: boolean;     // Place orders
  trading_cancel: boolean;    // Cancel orders
  
  // Account permissions  
  account_read: boolean;      // View balances, history
  
  // Advanced permissions
  api_access: boolean;        // External API calls
}

2. Permission Request Flow

// Simple API handles permissions automatically
const miniApp = createSimpleMiniApp({ 
  appId: 'my-app',
  requestedPermissions: ['trading_read', 'trading_write', 'market_data_read']
});

// Permission request is automatic
await miniApp.requestTradingPermissions();

// Manual permission checking
if (await miniApp.hasPermission('trading_write')) {
  await miniApp.placeOrder(orderData);
} else {
  console.log('Trading permission required');
}

3. Sandboxing

MiniApps run in isolated iframe sandboxes with restricted capabilities:

<iframe 
  src="miniapp-url"
  sandbox="allow-scripts allow-same-origin allow-forms"
  style="width: 100%; height: 100%; border: none;">
</iframe>

Sandbox Restrictions:

  • No direct DOM access to parent window

  • No access to terminal's localStorage/cookies

  • Limited network access (proxied through terminal)

  • No popup windows or modal dialogs

  • Communication only via PostMessage API

Data Flow Architecture

1. Real-Time Data Pipeline

External Data Sources → Terminal → MiniApp SDK → Your Application

              ┌─────────────┐
              │ WebSocket   │ ← Market feeds, order updates
              │ Manager     │
              └─────────────┘

              ┌─────────────┐
              │ Data        │ ← Normalization, validation
              │ Processor   │
              └─────────────┘

              ┌─────────────┐
              │ Event       │ ← Broadcast to subscribed MiniApps
              │ Dispatcher  │
              └─────────────┘

              ┌─────────────┐
              │ MiniApp     │ ← Your event handlers
              │ SDK         │
              └─────────────┘

2. State Management

The SDK provides different state management patterns:

Simple API - Event-Based:

const miniApp = createSimpleMiniApp({ appId: 'my-app' });

// State is managed through events
let currentPrice = 0;
miniApp.on('marketData', (data) => {
  if (data.symbol === 'ETH') {
    currentPrice = data.price;
  }
});

React API - Hook-Based:

function TradingComponent() {
  // State is managed by hooks
  const { marketData, positions, balance } = useSimpleMiniApp({
    appId: 'trading-ui',
    symbols: ['ETH', 'BTC']
  });

  // Automatic re-renders on state changes
  return <div>ETH: ${marketData.ETH?.price}</div>;
}

SDK Architecture Layers

1. Layered Architecture

┌─────────────────────────────────────────────────────┐
│                React Components                     │ ← SimpleOrderForm, etc.
├─────────────────────────────────────────────────────┤
│                React Hooks                          │ ← useSimpleTrade, etc.
├─────────────────────────────────────────────────────┤
│                Simple API                           │ ← createSimpleMiniApp
├─────────────────────────────────────────────────────┤
│                Core SDK                             │ ← MiniAppSDK class
├─────────────────────────────────────────────────────┤
│             Communication Layer                     │ ← PostMessage handling
├─────────────────────────────────────────────────────┤
│              Browser APIs                           │ ← iframe, postMessage
└─────────────────────────────────────────────────────┘

2. Simple API Architecture

// High-level Simple API
class SimpleMiniAppClient {
  private coreSDK: MiniAppSDK;
  private eventEmitter: EventEmitter;
  private permissionManager: PermissionManager;
  
  constructor(config: SimpleConfig) {
    this.coreSDK = new MiniAppSDK(config);
    this.setupAutomaticPermissions();
    this.setupEventBridge();
  }

  // Convenience methods wrap core SDK
  async quickBuy(symbol: string, quantity: number) {
    await this.ensureTradingPermissions();
    return this.coreSDK.commands.trading.placeOrder({
      symbol,
      side: 'buy',
      type: 'market',
      quantity
    });
  }
}

Performance Architecture

1. Connection Management

class ConnectionManager {
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 5;
  private reconnectDelay = 1000;

  async connect() {
    try {
      await this.establishConnection();
      this.reconnectAttempts = 0;
    } catch (error) {
      await this.handleConnectionFailure();
    }
  }

  private async handleConnectionFailure() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts);
      
      setTimeout(() => this.connect(), delay);
    }
  }
}

2. Message Queuing

class MessageQueue {
  private queue: Message[] = [];
  private processing = false;

  async sendMessage(message: Message) {
    this.queue.push(message);
    
    if (!this.processing) {
      await this.processQueue();
    }
  }

  private async processQueue() {
    this.processing = true;
    
    while (this.queue.length > 0) {
      const message = this.queue.shift()!;
      try {
        await this.sendMessageToTerminal(message);
      } catch (error) {
        // Handle retry logic
        if (message.retryCount < 3) {
          message.retryCount++;
          this.queue.unshift(message); // Retry first
        }
      }
    }
    
    this.processing = false;
  }
}

3. Data Caching

class DataCache {
  private cache = new Map<string, CacheEntry>();
  private readonly TTL = 5000; // 5 seconds

  get(key: string): any {
    const entry = this.cache.get(key);
    
    if (entry && Date.now() - entry.timestamp < this.TTL) {
      return entry.data;
    }
    
    return null;
  }

  set(key: string, data: any) {
    this.cache.set(key, {
      data,
      timestamp: Date.now()
    });
  }
}

Error Handling Architecture

1. Error Classification

enum ErrorType {
  CONNECTION_ERROR = 'connection',
  PERMISSION_ERROR = 'permission', 
  VALIDATION_ERROR = 'validation',
  TRADING_ERROR = 'trading',
  NETWORK_ERROR = 'network'
}

class MiniAppError extends Error {
  constructor(
    public type: ErrorType,
    message: string,
    public code?: string,
    public recoverable = true
  ) {
    super(message);
    this.name = 'MiniAppError';
  }
}

2. Error Recovery Strategies

class ErrorHandler {
  async handleError(error: MiniAppError, context: any) {
    switch (error.type) {
      case ErrorType.CONNECTION_ERROR:
        return this.handleConnectionError(error);
        
      case ErrorType.PERMISSION_ERROR:
        return this.handlePermissionError(error);
        
      case ErrorType.TRADING_ERROR:
        return this.handleTradingError(error);
        
      default:
        throw error; // Re-throw unhandleable errors
    }
  }

  private async handleConnectionError(error: MiniAppError) {
    // Implement reconnection logic
    await this.reconnect();
  }

  private async handlePermissionError(error: MiniAppError) {
    // Request missing permissions
    await this.requestPermissions();
  }
}

Key Architectural Decisions

1. Why iframe Sandboxing?

  • Security: Complete isolation from terminal code

  • Stability: MiniApp crashes don't affect terminal

  • Flexibility: Support for any web technology

  • Updates: Independent deployment and versioning

2. Why PostMessage Communication?

  • Security: Controlled communication channel

  • Standards: Built on web standards

  • Reliability: Browser-native implementation

  • Debugging: Easy to inspect and debug

3. Why Event-Driven Design?

  • Real-time: Immediate updates from markets

  • Scalability: Efficient one-to-many broadcasting

  • Flexibility: Easy to add new event types

  • Performance: Non-blocking operations

4. Why Multiple API Layers?

  • Progressive Enhancement: Start simple, add complexity as needed

  • Developer Experience: Choose the right abstraction level

  • Maintenance: Clear separation of concerns

  • Testing: Each layer can be tested independently

Next Steps

Now that you understand the architecture:

  1. Simple API Reference - Detailed API documentation

  2. React Integration - Building UIs with React


Next: Simple API Reference → Complete API documentation

Last updated