跳转至内容

网关连接器架构

概述

网关连接器遵循标准化架构,确保与 Hummingbot 客户端的一致性、可维护性和兼容性。本页面描述了网关连接器中使用的架构模式和设计原则。

核心组件

1. 连接器类

主连接器类作为所有 DEX 操作的入口点和协调器:

export class ConnectorBase {
  protected chain: string;
  protected network: string;
  protected config: ConnectorConfig;
  protected sdk: ProtocolSDK;

  constructor(chain: string, network: string) {
    this.chain = chain;
    this.network = network;
    this.config = this.loadConfig();
    this.sdk = this.initializeSDK();
  }
}

职责: - SDK 初始化和管理 - 配置加载 - 方法协调 - 错误处理和恢复

2. 路由处理器

路由处理器将 HTTP 请求转换为连接器方法调用:

interface RouteHandler {
  validateRequest(req: Request): void;
  processRequest(req: Request): Promise<any>;
  formatResponse(data: any): Response;
  handleError(error: Error): ErrorResponse;
}

关键特性: - 根据模式验证请求 - 异步操作处理 - 标准化响应格式 - 全面的错误处理

3. 交易类型

每种交易类型定义特定的接口和操作:

路由器接口

interface RouterConnector {
  quote(params: QuoteParams): Promise<Quote>;
  trade(params: TradeParams): Promise<Transaction>;
  estimateGas(params: TradeParams): Promise<BigNumber>;
  getRoute(params: RouteParams): Promise<Route[]>;
}

AMM 接口

interface AMMConnector {
  poolInfo(pair: TradingPair): Promise<PoolInfo>;
  poolPrice(pair: TradingPair): Promise<Price>;
  addLiquidity(params: LiquidityParams): Promise<Transaction>;
  removeLiquidity(params: RemoveLiquidityParams): Promise<Transaction>;
  positionInfo(params: PositionParams): Promise<Position>;
}

CLMM 接口

interface CLMMConnector {
  openPosition(params: OpenPositionParams): Promise<Position>;
  closePosition(positionId: string): Promise<Transaction>;
  addLiquidity(params: AddLiquidityParams): Promise<Transaction>;
  removeLiquidity(params: RemoveLiquidityParams): Promise<Transaction>;
  collectFees(positionId: string): Promise<Transaction>;
  getPositions(owner: string): Promise<Position[]>;
}

设计模式

单例模式

连接器使用单例模式以确保高效的资源使用:

class MyDex {
  private static instances: Map<string, MyDex> = new Map();

  public static getInstance(chain: string, network: string): MyDex {
    const key = `${chain}:${network}`;
    if (!this.instances.has(key)) {
      this.instances.set(key, new MyDex(chain, network));
    }
    return this.instances.get(key)!;
  }
}

优势: - 重用 SDK 连接 - 维持状态一致性 - 减少内存占用 - 提升性能

工厂模式

代币和池创建使用工厂模式:

class TokenFactory {
  static createToken(
    address: string,
    chain: string,
    network: string
  ): Token {
    const chainInstance = ChainFactory.getChain(chain, network);
    return new Token(address, chainInstance);
  }
}

策略模式

基于协议类型的不同交换策略:

interface SwapStrategy {
  execute(params: SwapParams): Promise<Transaction>;
}

class UniswapV2Strategy implements SwapStrategy {
  async execute(params: SwapParams): Promise<Transaction> {
    // V2 specific logic
  }
}

class UniswapV3Strategy implements SwapStrategy {
  async execute(params: SwapParams): Promise<Transaction> {
    // V3 specific logic
  }
}

数据流

请求生命周期

graph TD
    A[HTTP Request] --> B[Route Handler]
    B --> C[Schema Validation]
    C --> D[Connector Method]
    D --> E[SDK Call]
    E --> F[Blockchain RPC]
    F --> G[Response Processing]
    G --> H[HTTP Response]
  1. 请求接收:网关接收 HTTP 请求
  2. 路由:请求路由到适当的处理器
  3. 验证:根据模式验证请求
  4. 处理:连接器方法处理请求
  5. 执行:SDK 执行区块链操作
  6. 响应:格式化响应返回给客户端

状态管理

网关连接器维持最小状态:

class ConnectorState {
  // Cached data with TTL
  private poolCache: Map<string, CachedPool>;
  private tokenCache: Map<string, CachedToken>;

  // Active operations
  private pendingTransactions: Map<string, Transaction>;

  // Performance metrics
  private metrics: PerformanceMetrics;
}

缓存项目: - 代币元数据 - 池信息 - Gas 估算 - 路由计算

TTL 策略: - 代币信息:1 小时 - 池数据:30 秒 - Gas 价格:10 秒 - 路由:报价 TTL

错误处理

错误层次

class GatewayError extends Error {
  code: number;
  details: any;
}

class ValidationError extends GatewayError {
  code = 400;
}

class InsufficientLiquidityError extends GatewayError {
  code = 422;
}

class BlockchainError extends GatewayError {
  code = 503;
}

错误恢复

连接器为临时故障实现重试逻辑:

async function withRetry<T>(
  operation: () => Promise<T>,
  maxRetries: number = 3
): Promise<T> {
  let lastError: Error;

  for (let i = 0; i < maxRetries; i++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;
      if (!isRetryable(error)) throw error;
      await sleep(exponentialBackoff(i));
    }
  }

  throw lastError;
}

性能优化

批处理

尽可能批量处理多个操作:

class BatchProcessor {
  private queue: Operation[] = [];
  private timer: NodeJS.Timeout;

  add(operation: Operation): void {
    this.queue.push(operation);
    this.scheduleFlush();
  }

  private async flush(): Promise<void> {
    const batch = this.queue.splice(0);
    await this.processBatch(batch);
  }
}

缓存

实施智能缓存策略:

class Cache<T> {
  private data: Map<string, CacheEntry<T>> = new Map();

  get(key: string): T | undefined {
    const entry = this.data.get(key);
    if (!entry || this.isExpired(entry)) {
      return undefined;
    }
    return entry.value;
  }

  set(key: string, value: T, ttl: number): void {
    this.data.set(key, {
      value,
      expiry: Date.now() + ttl
    });
  }
}

连接池

维护区块链 RPC 的连接池:

class RPCPool {
  private connections: RPCConnection[] = [];
  private currentIndex = 0;

  getConnection(): RPCConnection {
    const connection = this.connections[this.currentIndex];
    this.currentIndex = (this.currentIndex + 1) % this.connections.length;
    return connection;
  }
}

安全考虑

输入验证

所有输入都必须经过验证:

function validateAddress(address: string, chain: string): void {
  if (!isValidAddress(address, chain)) {
    throw new ValidationError('Invalid address format');
  }
}

function validateAmount(amount: string): BigNumber {
  const bn = BigNumber.from(amount);
  if (bn.lte(0)) {
    throw new ValidationError('Amount must be positive');
  }
  return bn;
}

私钥处理

切勿记录或暴露私钥:

class WalletManager {
  private wallets: Map<string, Wallet> = new Map();

  addWallet(address: string, encryptedKey: string): void {
    const wallet = this.decryptWallet(encryptedKey);
    this.wallets.set(address, wallet);
    // Never log wallet or private key
  }
}

限流

对对外部调用实现限流:

class RateLimiter {
  private calls: number[] = [];
  private limit: number;
  private window: number;

  async throttle(): Promise<void> {
    const now = Date.now();
    this.calls = this.calls.filter(t => t > now - this.window);

    if (this.calls.length >= this.limit) {
      const waitTime = this.calls[0] + this.window - now;
      await sleep(waitTime);
    }

    this.calls.push(now);
  }
}

测试架构

模拟框架

创建全面的模拟测试:

class MockSDK {
  async swap(params: SwapParams): Promise<MockTransaction> {
    return {
      hash: '0xmock...',
      gasUsed: BigNumber.from('100000'),
      status: 'success'
    };
  }
}

测试装置

为常见场景维护测试装置:

export const fixtures = {
  tokens: {
    USDC: { address: '0x...', decimals: 6, symbol: 'USDC' },
    WETH: { address: '0x...', decimals: 18, symbol: 'WETH' }
  },
  pools: {
    USDC_WETH: { address: '0x...', fee: 3000 }
  }
};

最佳实践

1. 关注点分离

  • 将业务逻辑保留在连接器类中
  • 路由处理器仅处理 HTTP 相关事宜
  • 工具函数用于纯函数

2. 依赖注入

class MyDex {
  constructor(
    private sdk: ISDK,
    private cache: ICache,
    private logger: ILogger
  ) {}
}

3. 不可变性

// Good
const newState = { ...oldState, updated: true };

// Avoid
oldState.updated = true;

4. 异步/等待一致性

// Good
async function process(): Promise<Result> {
  const data = await fetchData();
  return transform(data);
}

// Avoid mixing patterns
function process(): Promise<Result> {
  return fetchData().then(transform);
}

5. 错误上下文

try {
  await operation();
} catch (error) {
  throw new ConnectorError(
    'Operation failed',
    { 
      originalError: error,
      context: { operation: 'swap', params }
    }
  );
}

资源