Skip to main content
Glama
guard-engine.tsβ€’10.2 kB
import { GuardEngineConfig, GuardRuleParams, GuardType, TxSimulateResponse, TxExecuteRequest } from '../types/index.js' export interface GuardRule { type: GuardType params: GuardRuleParams enabled: boolean } export interface GuardResult { passed: boolean triggeredGuards: string[] warnings: string[] } export class GuardEngine { private rules: Map<string, GuardRule> = new Map() private config: GuardEngineConfig private emergencyStop = false constructor(config: GuardEngineConfig) { this.config = config this.loadDefaultRules() } /** * Add or update a guard rule */ setRule(name: string, type: GuardType, params: GuardRuleParams): void { this.rules.set(name, { type, params, enabled: true }) } /** * Remove a guard rule */ removeRule(name: string): void { this.rules.delete(name) } /** * Enable/disable a guard rule */ toggleRule(name: string, enabled: boolean): void { const rule = this.rules.get(name) if (rule) { rule.enabled = enabled } } /** * Check if a transaction simulation passes all guards */ validateSimulation(simulation: TxSimulateResponse, txRequest: any): GuardResult { const triggeredGuards: string[] = [] const warnings: string[] = [] // Check if emergency stop is active if (this.emergencyStop || this.config.emergencyStop) { triggeredGuards.push('emergency_stop') return { passed: false, triggeredGuards, warnings: ['Emergency stop is active'] } } // Check all enabled rules for (const [ruleName, rule] of this.rules) { if (!rule.enabled) continue const result = this.checkRule(ruleName, rule, simulation, txRequest) if (!result.passed) { triggeredGuards.push(...result.triggeredGuards) warnings.push(...result.warnings) } } return { passed: triggeredGuards.length === 0, triggeredGuards, warnings } } /** * Check if a transaction execution request passes all guards */ validateExecution(executeRequest: TxExecuteRequest): GuardResult { const triggeredGuards: string[] = [] const warnings: string[] = [] // Check if emergency stop is active if (this.emergencyStop || this.config.emergencyStop) { triggeredGuards.push('emergency_stop') return { passed: false, triggeredGuards, warnings: ['Emergency stop is active'] } } // Check daily limits if configured if (this.config.maxDailyVolumeUsd || this.config.maxDailyTransactions) { const dailyCheck = this.checkDailyLimits(executeRequest) if (!dailyCheck.passed) { triggeredGuards.push(...dailyCheck.triggeredGuards) warnings.push(...dailyCheck.warnings) } } return { passed: triggeredGuards.length === 0, triggeredGuards, warnings } } /** * Check a specific rule */ private checkRule( ruleName: string, rule: GuardRule, simulation: TxSimulateResponse, txRequest: any ): GuardResult { const triggeredGuards: string[] = [] const warnings: string[] = [] switch (rule.type) { case 'risk': const riskResult = this.checkRiskGuards(rule.params, simulation, txRequest) if (!riskResult.passed) { triggeredGuards.push(`${ruleName}_risk`) warnings.push(...riskResult.warnings) } break case 'gas': const gasResult = this.checkGasGuards(rule.params, simulation, txRequest) if (!gasResult.passed) { triggeredGuards.push(`${ruleName}_gas`) warnings.push(...gasResult.warnings) } break case 'route': const routeResult = this.checkRouteGuards(rule.params, simulation, txRequest) if (!routeResult.passed) { triggeredGuards.push(`${ruleName}_route`) warnings.push(...routeResult.warnings) } break case 'deny': const denyResult = this.checkDenyGuards(rule.params, simulation, txRequest) if (!denyResult.passed) { triggeredGuards.push(`${ruleName}_deny`) warnings.push(...denyResult.warnings) } break } return { passed: triggeredGuards.length === 0, triggeredGuards, warnings } } /** * Check risk-related guards */ private checkRiskGuards(params: GuardRuleParams, simulation: TxSimulateResponse, txRequest: any): GuardResult { const triggeredGuards: string[] = [] const warnings: string[] = [] // Check slippage if (params.maxSlippagePct && simulation.est.slippagePct > params.maxSlippagePct) { triggeredGuards.push('max_slippage_exceeded') warnings.push(`Slippage ${simulation.est.slippagePct}% exceeds maximum ${params.maxSlippagePct}%`) } // Check drawdown (would need historical data) if (params.maxDrawdownPct) { // This would require portfolio history analysis // For now, we'll skip this check } // Check minimum liquidity if (params.minLiquidityUsd && simulation.est.avgPrice) { // This would require checking DEX liquidity // For now, we'll skip this check } return { passed: triggeredGuards.length === 0, triggeredGuards, warnings } } /** * Check gas-related guards */ private checkGasGuards(params: GuardRuleParams, simulation: TxSimulateResponse, txRequest: any): GuardResult { const triggeredGuards: string[] = [] const warnings: string[] = [] // Check max gas price if (params.maxGasGwei && txRequest.gasPrice) { const gasPriceGwei = parseFloat(txRequest.gasPrice) / 1e9 if (gasPriceGwei > params.maxGasGwei) { triggeredGuards.push('max_gas_price_exceeded') warnings.push(`Gas price ${gasPriceGwei} gwei exceeds maximum ${params.maxGasGwei} gwei`) } } return { passed: triggeredGuards.length === 0, triggeredGuards, warnings } } /** * Check route-related guards */ private checkRouteGuards(params: GuardRuleParams, simulation: TxSimulateResponse, txRequest: any): GuardResult { const triggeredGuards: string[] = [] const warnings: string[] = [] // Check allowed DEXes if (params.allowedDexes && (simulation as any).route) { const routeDexes = this.extractDexesFromRoute((simulation as any).route) const hasAllowedDex = routeDexes.some(dex => params.allowedDexes!.includes(dex)) if (!hasAllowedDex) { triggeredGuards.push('unauthorized_dex') warnings.push(`Route uses unauthorized DEXes: ${routeDexes.join(', ')}`) } } // Check blocked tokens if (params.blockedTokens && txRequest.tokenAddresses) { const blockedTokens = txRequest.tokenAddresses.filter((addr: string) => params.blockedTokens!.includes(addr.toLowerCase()) ) if (blockedTokens.length > 0) { triggeredGuards.push('blocked_token') warnings.push(`Transaction involves blocked tokens: ${blockedTokens.join(', ')}`) } } return { passed: triggeredGuards.length === 0, triggeredGuards, warnings } } /** * Check deny list guards */ private checkDenyGuards(params: GuardRuleParams, simulation: TxSimulateResponse, txRequest: any): GuardResult { const triggeredGuards: string[] = [] const warnings: string[] = [] // Check blocked addresses if (params.blockedAddresses && txRequest.to) { if (params.blockedAddresses.includes(txRequest.to.toLowerCase())) { triggeredGuards.push('blocked_address') warnings.push(`Transaction target is blocked: ${txRequest.to}`) } } // Check blocked protocols if (params.blockedProtocols && (simulation as any).route) { const routeProtocols = this.extractProtocolsFromRoute((simulation as any).route) const blockedProtocols = routeProtocols.filter(protocol => params.blockedProtocols!.includes(protocol) ) if (blockedProtocols.length > 0) { triggeredGuards.push('blocked_protocol') warnings.push(`Route uses blocked protocols: ${blockedProtocols.join(', ')}`) } } return { passed: triggeredGuards.length === 0, triggeredGuards, warnings } } /** * Check daily limits */ private checkDailyLimits(executeRequest: TxExecuteRequest): GuardResult { const triggeredGuards: string[] = [] const warnings: string[] = [] // This would require implementing daily tracking // For now, we'll return a passed result // In a real implementation, you'd check against a database or cache return { passed: triggeredGuards.length === 0, triggeredGuards, warnings } } /** * Load default rules from config */ private loadDefaultRules(): void { for (const [ruleName, params] of Object.entries(this.config.defaultRules)) { this.setRule(ruleName, 'risk', params) } } /** * Extract DEX names from route string */ private extractDexesFromRoute(route: string): string[] { // Simple implementation - in reality, you'd parse the route more carefully const dexes = [] if (route.toLowerCase().includes('uniswap')) dexes.push('uniswap') if (route.toLowerCase().includes('1inch')) dexes.push('1inch') if (route.toLowerCase().includes('sushiswap')) dexes.push('sushiswap') return dexes } /** * Extract protocol names from route string */ private extractProtocolsFromRoute(route: string): string[] { // Simple implementation - in reality, you'd parse the route more carefully const protocols = [] if (route.toLowerCase().includes('aave')) protocols.push('aave') if (route.toLowerCase().includes('compound')) protocols.push('compound') if (route.toLowerCase().includes('curve')) protocols.push('curve') return protocols } /** * Set emergency stop */ setEmergencyStop(enabled: boolean): void { this.emergencyStop = enabled } /** * Get all rules */ getAllRules(): Map<string, GuardRule> { return new Map(this.rules) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/antidump/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server