网关连接器架构¶
概述¶
网关连接器遵循标准化的架构,以确保与 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]- 接收请求:网关接收 HTTP 请求
- 路由:请求被路由到相应的处理器
- 验证:根据模式对请求进行验证
- 处理:连接器方法处理请求
- 执行:SDK 执行区块链操作
- 响应:格式化后的响应返回给客户端
状态管理¶
网关连接器维护最少的状态:
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. 依赖注入¶
3. 不可变性¶
4. Async/Await 一致性¶
// 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 }
    }
  );
}
