网关连接器架构¶
概述¶
网关连接器遵循标准化架构,确保与 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. 异步/等待一致性¶
// 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 }
}
);
}